Beispiel #1
0
        void Init()
        {
            var visible = world.ActorsHavingTrait <StrategicVictoryConditions>().Any() &&
                          world.ActorsHavingTrait <StrategicPoint>().Any();

            IsVisible   = () => visible;
            initialised = true;
        }
        internal Actor FindClosestEnemyBuilding(WPos pos)
        {
            var enemy = World.ActorsHavingTrait <Building>().Where(IsEnemyUnit).ClosestTo(pos);

            if (enemy != null)
            {
                return(enemy);
            }
            return(World.Actors.Where(IsEnemyUnit).ClosestTo(pos));
        }
Beispiel #3
0
        // TODO: Possibly give this a more generic name when terrain type is unhardcoded
        public bool EnoughWaterToBuildNaval()
        {
            var baseProviders = World.ActorsHavingTrait <BaseProvider>()
                                .Where(a => a.Owner == Player && !a.Info.HasTraitInfo <MobileInfo>());

            foreach (var b in baseProviders)
            {
                // TODO: Unhardcode terrain type
                // TODO2: Properly check building foundation rather than 3x3 area
                var playerWorld     = Player.World;
                var countWaterCells = Map.FindTilesInCircle(b.Location, Info.MaxBaseRadius)
                                      .Where(c => playerWorld.Map.Contains(c) &&
                                             playerWorld.Map.GetTerrainInfo(c).IsWater &&
                                             Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c))
                                             .All(a => playerWorld.Map.GetTerrainInfo(a).IsWater))
                                      .Count();

                if (countWaterCells > 0)
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #4
0
        public int CountPotentialFreeBeds()
        {
            var housactors = world.ActorsHavingTrait <Building>()
                             .Where(a => a.Owner == Player && hackyAIInfo.BuildingCommonNames.Houses.Contains(a.Info.Name));

            var potentialpop = 0;

            if (housactors.Any() && housactors != null)
            {
                foreach (var hous in housactors)
                {
                    var preserv = Player.World.Map.Rules.Actors[hous.Info.Name.Replace(".scaff", string.Empty).ToLower()];

                    if (preserv != null && preserv.HasTraitInfo <ProvidesLivingspaceInfo>())
                    {
                        potentialpop += preserv.TraitInfo <ProvidesLivingspaceInfo>().Ammount;
                    }

                    if (hous != null && hous.Info.HasTraitInfo <ProvidesLivingspaceInfo>())
                    {
                        potentialpop += hous.Info.TraitInfo <ProvidesLivingspaceInfo>().Ammount;
                    }
                }
            }

            return(potentialpop);
        }
Beispiel #5
0
        public IngameRadarDisplayLogic(Widget widget, World world)
        {
            var radarEnabled       = false;
            var cachedRadarEnabled = false;
            var blockColor         = Color.Transparent;
            var radar = widget.Get <RadarWidget>("RADAR_MINIMAP");

            radar.IsEnabled = () => radarEnabled;

            var ticker = widget.Get <LogicTickerWidget>("RADAR_TICKER");

            ticker.OnTick = () =>
            {
                radarEnabled = world.ActorsHavingTrait <ProvidesRadar>(r => !r.IsTraitDisabled).Any(a => a.Owner == world.LocalPlayer);

                if (radarEnabled != cachedRadarEnabled)
                {
                    //WarGame.Sound.playno
                }
                cachedRadarEnabled = radarEnabled;
            };

            var block = widget.GetOrNull <ColorBlockWidget>("RADAR_FADETOBLACK");

            if (block != null)
            {
                radar.Animating = x => blockColor = Color.FromArgb((int)(255 * x), Color.Black);
                block.IsVisible = () => blockColor.A != 0;
                block.GetColor  = () => blockColor;
            }
        }
        protected override bool OnHotkeyActivated(KeyInput e)
        {
            var player = world.RenderPlayer ?? world.LocalPlayer;

            var harvesters = world.ActorsHavingTrait <Harvester>()
                             .Where(a => a.IsInWorld && a.Owner == player)
                             .ToList();

            if (!harvesters.Any())
            {
                return(true);
            }

            var next = harvesters
                       .SkipWhile(b => !selection.Contains(b))
                       .Skip(1)
                       .FirstOrDefault();

            if (next == null)
            {
                next = harvesters.First();
            }

            selection.Combine(world, new Actor[] { next }, false, true);
            viewport.Center(selection.Actors);

            return(true);
        }
        public IngameRadarDisplayLogic(Widget widget, World world)
        {
            var radarEnabled = false;
            var cachedRadarEnabled = false;
            var blockColor = Color.Transparent;
            var radar = widget.Get<RadarWidget>("RADAR_MINIMAP");
            radar.IsEnabled = () => radarEnabled;
            var devMode = world.LocalPlayer.PlayerActor.Trait<DeveloperMode>();

            var ticker = widget.Get<LogicTickerWidget>("RADAR_TICKER");
            ticker.OnTick = () =>
            {
                radarEnabled = devMode.DisableShroud || world.ActorsHavingTrait<ProvidesRadar>(r => r.IsActive)
                    .Any(a => a.Owner == world.LocalPlayer);

                if (radarEnabled != cachedRadarEnabled)
                    Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", radarEnabled ? "RadarUp" : "RadarDown", null);
                cachedRadarEnabled = radarEnabled;
            };

            var block = widget.GetOrNull<ColorBlockWidget>("RADAR_FADETOBLACK");
            if (block != null)
            {
                radar.Animating = x => blockColor = Color.FromArgb((int)(255 * x), Color.Black);
                block.IsVisible = () => blockColor.A != 0;
                block.GetColor = () => blockColor;
            }
        }
Beispiel #8
0
        protected override bool OnHotkeyActivated(KeyInput e)
        {
            var player = world.RenderPlayer ?? world.LocalPlayer;

            var facilities = world.ActorsHavingTrait <Production>()
                             .Where(a => a.Owner == player && a.OccupiesSpace != null && !a.Info.HasTraitInfo <BaseBuildingInfo>() &&
                                    a.TraitsImplementing <Production>().Any(t => !t.IsTraitDisabled))
                             .OrderBy(f => f.TraitsImplementing <Production>().First(t => !t.IsTraitDisabled).Info.Produces.First())
                             .ToList();

            if (!facilities.Any())
            {
                return(true);
            }

            var next = facilities
                       .SkipWhile(b => !selection.Contains(b))
                       .Skip(1)
                       .FirstOrDefault();

            if (next == null)
            {
                next = facilities.First();
            }

            Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", clickSound, null);

            selection.Combine(world, new Actor[] { next }, false, true);
            viewport.Center(selection.Actors);

            return(true);
        }
Beispiel #9
0
        /// <summary>Detail scans an area, evaluating positions.</summary>
        CPos?FindAttackLocationToSupportPower(SupportPowerInstance readyPower)
        {
            CPos?bestLocation       = null;
            var  bestAttractiveness = 0;
            var  powerDecision      = powerDecisions[readyPower.Info.OrderName];

            if (powerDecision == null)
            {
                AIUtils.BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", readyPower.Info.OrderName);
                return(null);
            }

            var availableTargets = world.ActorsHavingTrait <IOccupySpace>().Where(x => x.IsInWorld && !x.IsDead &&
                                                                                  (powerDecision.IgnoreVisibility || x.CanBeViewedByPlayer(player)) &&
                                                                                  powerDecision.Against.HasRelationship(player.RelationshipWith(x.Owner)) &&
                                                                                  powerDecision.Types.Overlaps(x.GetEnabledTargetTypes()));

            foreach (var a in availableTargets)
            {
                var pos = a.CenterPosition;
                var consideredAttractiveness = 0;
                consideredAttractiveness += powerDecision.GetAttractiveness(pos, player);

                if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness)
                {
                    continue;
                }

                bestAttractiveness = consideredAttractiveness;
                bestLocation       = world.Map.CellContaining(pos);
            }

            return(bestLocation);
        }
Beispiel #10
0
        void IBotTick.BotTick(IBot bot)
        {
            if (world.WorldTick % tickEvery != 0)
            {
                return;
            }

            var miners = world.ActorsHavingTrait <Transforms>()
                         .Where(a => a.Owner == player && a.IsIdle && Info.MinerTypes.Contains(a.Info.Name));

            foreach (var miner in miners)
            {
                var closestMine = ClosestHarvestablePos(miner);
                if (!closestMine.HasValue)
                {
                    continue;
                }

                var claimedOk = claimLayer.TryClaimCell(miner, closestMine.Value);
                if (!claimedOk)
                {
                    continue;
                }

                bot.QueueOrder(new Order("Move", miner, Target.FromCell(world, closestMine.Value), true));
                bot.QueueOrder(new Order("DeployTransform", miner, true));
            }
        }
Beispiel #11
0
        public IngameRadarDisplayLogic(Widget widget, World world)
        {
            var radarEnabled       = false;
            var cachedRadarEnabled = false;
            var blockColor         = Color.Transparent;
            var radar = widget.Get <RadarWidget>("RADAR_MINIMAP");

            radar.IsEnabled = () => radarEnabled;
            var devMode = world.LocalPlayer.PlayerActor.Trait <DeveloperMode>();

            var ticker = widget.Get <LogicTickerWidget>("RADAR_TICKER");

            ticker.OnTick = () =>
            {
                radarEnabled = devMode.DisableShroud || world.ActorsHavingTrait <ProvidesRadar>(r => !r.IsTraitDisabled)
                               .Any(a => a.Owner == world.LocalPlayer);

                if (radarEnabled != cachedRadarEnabled)
                {
                    Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", radarEnabled ? "RadarUp" : "RadarDown", null);
                }
                cachedRadarEnabled = radarEnabled;
            };

            var block = widget.GetOrNull <ColorBlockWidget>("RADAR_FADETOBLACK");

            if (block != null)
            {
                radar.Animating = x => blockColor = Color.FromArgb((int)(255 * x), Color.Black);
                block.IsVisible = () => blockColor.A != 0;
                block.GetColor  = () => blockColor;
            }
        }
Beispiel #12
0
        void ITick.Tick(Actor self)
        {
            if (IsTraitDisabled)
            {
                return;
            }

            if (resLayer == null || resLayer.IsResourceLayerEmpty)
            {
                return;
            }

            if (--scanForIdleHarvestersTicks > 0)
            {
                return;
            }

            harvesters.RemoveAll(unitCannotBeOrdered);
            scanForIdleHarvestersTicks = Info.ScanForIdleHarvestersInterval;

            // Find new harvesters
            // TODO: Look for a more performance-friendly way to update this list
            var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.Contains(a));

            foreach (var a in newHarvesters)
            {
                harvesters.Add(a);
            }

            // Find idle harvesters and give them orders:
            foreach (var harvester in harvesters)
            {
                var harv = harvester.Trait <Harvester>();
                if (!harv.IsEmpty)
                {
                    continue;
                }

                if (!harvester.IsIdle)
                {
                    var act = harvester.CurrentActivity;
                    if (!harv.LastSearchFailed || act.NextActivity == null || act.NextActivity.GetType() != typeof(FindResources))
                    {
                        continue;
                    }
                }

                var para = harvester.TraitOrDefault <Parachutable>();
                if (para != null && para.IsInAir)
                {
                    continue;
                }

                // Tell the idle harvester to quit slacking:
                var newSafeResourcePatch = FindNextResource(harvester, harv);
                AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(harvester, newSafeResourcePatch));
                botOrderManager.QueueOrder(new Order("Harvest", harvester, Target.FromCell(world, newSafeResourcePatch), false));
            }
        }
Beispiel #13
0
        public CPos GetRandomBaseCenter()
        {
            var randomBaseBuilding = World.ActorsHavingTrait <BaseBuilding>()
                                     .Where(a => a.Owner == Player && !a.Info.HasTraitInfo <MobileInfo>())
                                     .RandomOrDefault(Random);

            return(randomBaseBuilding != null ? randomBaseBuilding.Location : initialBaseCenter);
        }
Beispiel #14
0
        public override void Tick(World world)
        {
            this.researchActors = world.ActorsHavingTrait <Researches>().Where(e => e.Owner == world.LocalPlayer);

            if (!this.researchActors.Any())
            {
                world.CancelInputMode();
            }
        }
Beispiel #15
0
        public override void Tick(World world)
        {
            technicians = world.ActorsHavingTrait <Technician>().Where(e => e.Owner == world.LocalPlayer && e.IsIdle);

            if (!technicians.Any())
            {
                world.CancelInputMode();
            }
        }
Beispiel #16
0
        void DeployMcvs(IBot bot, bool chooseLocation)
        {
            var newMCVs = world.ActorsHavingTrait <Transforms>()
                          .Where(a => a.Owner == player && a.IsIdle && Info.McvTypes.Contains(a.Info.Name));

            foreach (var mcv in newMCVs)
            {
                DeployMcv(bot, mcv, chooseLocation);
            }
        }
Beispiel #17
0
        public static bool IsAreaAvailable <T>(World world, Player player, Map map, int radius, HashSet <string> terrainTypes)
        {
            var cells = world.ActorsHavingTrait <T>().Where(a => a.Owner == player);

            // TODO: Properly check building foundation rather than 3x3 area.
            return(cells.Select(a => map.FindTilesInCircle(a.Location, radius)
                                .Count(c => map.Contains(c) && terrainTypes.Contains(map.GetTerrainInfo(c).Type) &&
                                       Util.AdjacentCells(world, Target.FromCell(world, c))
                                       .All(ac => terrainTypes.Contains(map.GetTerrainInfo(ac).Type))))
                   .Any(availableCells => availableCells > 0));
        }
        protected override bool OnHotkeyActivated(KeyInput e)
        {
            var player = world.RenderPlayer ?? world.LocalPlayer;

            var bases = world.ActorsHavingTrait <BaseBuilding>()
                        .Where(a => a.Owner == player)
                        .ToList();

            // If no BaseBuilding exist pick the first selectable Building.
            if (!bases.Any())
            {
                var building = world.ActorsHavingTrait <Building>()
                               .FirstOrDefault(a => a.Owner == player && a.Info.HasTraitInfo <SelectableInfo>());

                // No buildings left
                if (building == null)
                {
                    return(true);
                }

                selection.Combine(world, new Actor[] { building }, false, true);
                viewport.Center(selection.Actors);
                return(true);
            }

            var next = bases
                       .SkipWhile(b => !selection.Contains(b))
                       .Skip(1)
                       .FirstOrDefault();

            if (next == null)
            {
                next = bases.First();
            }

            selection.Combine(world, new Actor[] { next }, false, true);
            viewport.Center(selection.Actors);

            return(true);
        }
Beispiel #19
0
        public static IEnumerable <CPos> GetLineBuildCells(World world, CPos location, string name, BuildingInfo bi)
        {
            var lbi     = world.Map.Rules.Actors[name].TraitInfo <LineBuildInfo>();
            var topLeft = location;             // 1x1 assumption!

            if (world.IsCellBuildable(topLeft, bi))
            {
                yield return(topLeft);
            }

            // Start at place location, search outwards
            // TODO: First make it work, then make it nice
            var vecs = new[] { new CVec(1, 0), new CVec(0, 1), new CVec(-1, 0), new CVec(0, -1) };

            int[] dirs = { 0, 0, 0, 0 };
            for (var d = 0; d < 4; d++)
            {
                for (var i = 1; i < lbi.Range; i++)
                {
                    if (dirs[d] != 0)
                    {
                        continue;
                    }

                    var cell = topLeft + i * vecs[d];
                    if (world.IsCellBuildable(cell, bi))
                    {
                        continue;                         // Cell is empty; continue search
                    }
                    // Cell contains an actor. Is it the type we want?
                    if (world.ActorsHavingTrait <LineBuildNode>()
                        .Any(a => a.Location == cell &&
                             a.Info.TraitInfo <LineBuildNodeInfo>().Types.Overlaps(lbi.NodeTypes)))
                    {
                        dirs[d] = i;                         // Cell contains actor of correct type
                    }
                    else
                    {
                        dirs[d] = -1;                         // Cell is blocked by another actor type
                    }
                }

                // Place intermediate-line sections
                if (dirs[d] > 0)
                {
                    for (var i = 1; i < dirs[d]; i++)
                    {
                        yield return(topLeft + i * vecs[d]);
                    }
                }
            }
        }
Beispiel #20
0
        void IBotTick.BotTick(IBot bot)
        {
            if (!initialized)
            {
                var baseBuildings = world.ActorsHavingTrait <BaseBuilding>().Where(a => a.Owner == player);
                foreach (var baseBuilding in baseBuildings)
                {
                    SetCenter(baseBuilding.Location);
                }

                initialized = true;
            }
        }
        bool CycleBases()
        {
            var player = world.RenderPlayer ?? world.LocalPlayer;

            var bases = world.ActorsHavingTrait <BaseBuilding>()
                        .Where(a => a.Owner == player)
                        .ToList();

            // If no BaseBuilding exist pick the first selectable Building.
            if (!bases.Any())
            {
                var building = world.ActorsHavingTrait <Building>()
                               .FirstOrDefault(a => a.Owner == player && a.Info.HasTraitInfo <SelectableInfo>());

                // No buildings left
                if (building == null)
                {
                    return(true);
                }

                world.Selection.Combine(world, new Actor[] { building }, false, true);
                return(ToSelection());
            }

            var next = bases
                       .SkipWhile(b => !world.Selection.Contains(b))
                       .Skip(1)
                       .FirstOrDefault();

            if (next == null)
            {
                next = bases.First();
            }

            world.Selection.Combine(world, new Actor[] { next }, false, true);

            return(ToSelection());
        }
Beispiel #22
0
        void FindNewUnits(IBot bot)
        {
            var newUnits = World.ActorsHavingTrait <IPositionable>()
                           .Where(a => a.Owner == Player &&
                                  !Info.ExcludeFromSquadsTypes.Contains(a.Info.Name) &&
                                  !activeUnits.Contains(a));

            foreach (var a in newUnits)
            {
                if (a.Info.HasTraitInfo <AircraftInfo>() && a.Info.HasTraitInfo <AttackBaseInfo>())
                {
                    var air = GetSquadOfType(SquadType.Air);
                    if (air == null)
                    {
                        air = RegisterNewSquad(bot, SquadType.Air);
                    }

                    air.Units.Add(a);
                }
                else if (Info.NavalUnitsTypes.Contains(a.Info.Name))
                {
                    var ships = GetSquadOfType(SquadType.Naval);
                    if (ships == null)
                    {
                        ships = RegisterNewSquad(bot, SquadType.Naval);
                    }

                    ships.Units.Add(a);
                }
                else
                {
                    unitsHangingAroundTheBase.Add(a);
                }

                activeUnits.Add(a);
            }

            // Notifying here rather than inside the loop, should be fine and saves a bunch of notification calls
            foreach (var n in notifyIdleBaseUnits)
            {
                n.UpdatedIdleBaseUnits(unitsHangingAroundTheBase);
            }
        }
        void DeployMcvs(IBot bot, bool chooseLocation)
        {
            activeMCVs.RemoveAll(unitCannotBeOrdered);

            var newMCVs = world.ActorsHavingTrait <Transforms>()
                          .Where(a => a.Owner == player &&
                                 a.IsIdle &&
                                 Info.McvTypes.Contains(a.Info.Name) &&
                                 !activeMCVs.Contains(a));

            foreach (var a in newMCVs)
            {
                activeMCVs.Add(a);
            }

            foreach (var mcv in activeMCVs)
            {
                DeployMcv(bot, mcv, chooseLocation);
            }
        }
Beispiel #24
0
        protected void OrderHarvesters(IBot bot)
        {
            var toRemove = harvesters.Keys.Where(unitCannotBeOrdered).ToList();

            foreach (var a in toRemove)
            {
                harvesters.Remove(a);
            }

            // Find new harvesters
            // TODO: Look for a more performance-friendly way to update this list
            var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.ContainsKey(a));

            foreach (var a in newHarvesters)
            {
                harvesters[a] = new HarvesterTraitWrapper(a);
            }

            // Find idle harvesters and give them orders:
            foreach (var h in harvesters)
            {
                if (!h.Key.IsIdle)
                {
                    var act = h.Key.CurrentActivity as FindAndDeliverResources;

                    // Ignore this actor if FindAndDeliverResources is working fine or it is performing a different activity
                    if (act == null || !act.LastSearchFailed)
                    {
                        continue;
                    }
                }

                // Tell the idle harvester to quit slacking:
                var newSafeResourcePatch = FindNextResource(h.Key, h.Value);
                AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(h.Key, newSafeResourcePatch));
                bot.QueueOrder(new Order("Harvest", h.Key, newSafeResourcePatch, false));
            }
        }
Beispiel #25
0
        public bool EnoughWaterToBuildNaval()
        {
            var baseProviders = World.ActorsHavingTrait <BaseProvider>()
                                .Where(a => a.Owner == Player);

            foreach (var b in baseProviders)
            {
                var playerWorld     = Player.World;
                var countWaterCells = Map.FindTilesInCircle(b.Location, Info.MaxBaseRadius)
                                      .Where(c => playerWorld.Map.Contains(c) &&
                                             Info.WaterTerrainTypes.Contains(playerWorld.Map.GetTerrainInfo(c).Type) &&
                                             Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c))
                                             .All(a => Info.WaterTerrainTypes.Contains(playerWorld.Map.GetTerrainInfo(a).Type))).Count();

                if (countWaterCells > 0)
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #26
0
 public static IEnumerable <Actor> GetActorsWithTrait <T>(World world)
 {
     return(world.ActorsHavingTrait <T>());
 }
Beispiel #27
0
        public ObserverStatsLogic(World world, ModData modData, WorldRenderer worldRenderer, Widget widget,
                                  Action onExit, ObserverStatsPanel activePanel, Dictionary <string, MiniYaml> logicArgs)
        {
            this.world         = world;
            this.worldRenderer = worldRenderer;

            MiniYaml yaml;

            string[] keyNames     = Enum.GetNames(typeof(ObserverStatsPanel));
            var      statsHotkeys = new HotkeyReference[keyNames.Length];

            for (var i = 0; i < keyNames.Length; i++)
            {
                statsHotkeys[i] = logicArgs.TryGetValue("Statistics" + keyNames[i] + "Key", out yaml) ? modData.Hotkeys[yaml.Value] : new HotkeyReference();
            }

            players = world.Players.Where(p => !p.NonCombatant);

            basicStatsHeaders            = widget.Get <ContainerWidget>("BASIC_STATS_HEADERS");
            economyStatsHeaders          = widget.Get <ContainerWidget>("ECONOMY_STATS_HEADERS");
            productionStatsHeaders       = widget.Get <ContainerWidget>("PRODUCTION_STATS_HEADERS");
            combatStatsHeaders           = widget.Get <ContainerWidget>("COMBAT_STATS_HEADERS");
            earnedThisMinuteGraphHeaders = widget.Get <ContainerWidget>("EARNED_THIS_MIN_GRAPH_HEADERS");

            playerStatsPanel        = widget.Get <ScrollPanelWidget>("PLAYER_STATS_PANEL");
            playerStatsPanel.Layout = new GridLayout(playerStatsPanel);

            basicPlayerTemplate           = playerStatsPanel.Get <ScrollItemWidget>("BASIC_PLAYER_TEMPLATE");
            economyPlayerTemplate         = playerStatsPanel.Get <ScrollItemWidget>("ECONOMY_PLAYER_TEMPLATE");
            productionPlayerTemplate      = playerStatsPanel.Get <ScrollItemWidget>("PRODUCTION_PLAYER_TEMPLATE");
            combatPlayerTemplate          = playerStatsPanel.Get <ScrollItemWidget>("COMBAT_PLAYER_TEMPLATE");
            earnedThisMinuteGraphTemplate = playerStatsPanel.Get <ContainerWidget>("EARNED_THIS_MIN_GRAPH_TEMPLATE");

            teamTemplate = playerStatsPanel.Get <ScrollItemWidget>("TEAM_TEMPLATE");

            var statsDropDown = widget.Get <DropDownButtonWidget>("STATS_DROPDOWN");
            Func <string, ContainerWidget, Action, StatsDropDownOption> createStatsOption = (title, headers, a) =>
            {
                return(new StatsDropDownOption
                {
                    Title = title,
                    IsSelected = () => headers.Visible,
                    OnClick = () =>
                    {
                        ClearStats();
                        statsDropDown.GetText = () => title;
                        a();
                    }
                });
            };

            var statsDropDownOptions = new StatsDropDownOption[]
            {
                createStatsOption("Basic", basicStatsHeaders, () => DisplayStats(BasicStats)),
                createStatsOption("Economy", economyStatsHeaders, () => DisplayStats(EconomyStats)),
                createStatsOption("Production", productionStatsHeaders, () => DisplayStats(ProductionStats)),
                createStatsOption("Combat", combatStatsHeaders, () => DisplayStats(CombatStats)),
                createStatsOption("Earnings (graph)", earnedThisMinuteGraphHeaders, () => EarnedThisMinuteGraph())
            };

            Func <StatsDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) =>
            {
                var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick);
                item.Get <LabelWidget>("LABEL").GetText = () => option.Title;
                return(item);
            };

            statsDropDown.OnMouseDown = _ => statsDropDown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 150, statsDropDownOptions, setupItem);
            statsDropDownOptions[(int)activePanel].OnClick();

            var close = widget.GetOrNull <ButtonWidget>("CLOSE");

            if (close != null)
            {
                close.OnClick = () =>
                {
                    Ui.CloseWindow();
                    Ui.Root.RemoveChild(widget);
                    onExit();
                }
            }
            ;

            var keyListener = statsDropDown.Get <LogicKeyListenerWidget>("STATS_DROPDOWN_KEYHANDLER");

            keyListener.AddHandler(e =>
            {
                if (e.Event == KeyInputEvent.Down && !e.IsRepeat)
                {
                    for (var i = 0; i < statsHotkeys.Length; i++)
                    {
                        if (statsHotkeys[i].IsActivatedBy(e))
                        {
                            Game.Sound.PlayNotification(modData.DefaultRules, null, "Sounds", "ClickSound", null);
                            statsDropDownOptions[i].OnClick();
                            return(true);
                        }
                    }
                }

                return(false);
            });
        }

        void ClearStats()
        {
            playerStatsPanel.Children.Clear();
            basicStatsHeaders.Visible            = false;
            economyStatsHeaders.Visible          = false;
            productionStatsHeaders.Visible       = false;
            combatStatsHeaders.Visible           = false;
            earnedThisMinuteGraphHeaders.Visible = false;
        }

        void EarnedThisMinuteGraph()
        {
            earnedThisMinuteGraphHeaders.Visible = true;
            var template = earnedThisMinuteGraphTemplate.Clone();

            var graph = template.Get <LineGraphWidget>("EARNED_THIS_MIN_GRAPH");

            graph.GetSeries = () =>
                              players.Select(p => new LineGraphSeries(
                                                 p.PlayerName,
                                                 p.Color.RGB,
                                                 (p.PlayerActor.TraitOrDefault <PlayerStatistics>() ?? new PlayerStatistics(p.PlayerActor)).EarnedSamples.Select(s => (float)s)));

            playerStatsPanel.AddChild(template);
            playerStatsPanel.ScrollToTop();
        }

        void DisplayStats(Func <Player, ScrollItemWidget> createItem)
        {
            var teams = players.GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.ClientIndex) ?? new Session.Client()).Team).OrderBy(g => g.Key);

            foreach (var t in teams)
            {
                var team = t;
                var tt   = ScrollItemWidget.Setup(teamTemplate, () => false, () => { });
                tt.IgnoreMouseOver = true;
                tt.Get <LabelWidget>("TEAM").GetText = () => team.Key == 0 ? "No Team" : "Team " + team.Key;
                playerStatsPanel.AddChild(tt);
                foreach (var p in team)
                {
                    var player = p;
                    playerStatsPanel.AddChild(createItem(player));
                }
            }
        }

        ScrollItemWidget CombatStats(Player player)
        {
            combatStatsHeaders.Visible = true;
            var template = SetupPlayerScrollItemWidget(combatPlayerTemplate, player);

            LobbyUtils.AddPlayerFlagAndName(template, player);

            var stats = player.PlayerActor.TraitOrDefault <PlayerStatistics>();

            if (stats == null)
            {
                return(template);
            }
            template.Get <LabelWidget>("ASSETS_DESTROYED").GetText = () => "$" + stats.KillsCost;
            template.Get <LabelWidget>("ASSETS_LOST").GetText      = () => "$" + stats.DeathsCost;
            template.Get <LabelWidget>("UNITS_KILLED").GetText     = () => stats.UnitsKilled.ToString();
            template.Get <LabelWidget>("UNITS_DEAD").GetText       = () => stats.UnitsDead.ToString();
            template.Get <LabelWidget>("BUILDINGS_KILLED").GetText = () => stats.BuildingsKilled.ToString();
            template.Get <LabelWidget>("BUILDINGS_DEAD").GetText   = () => stats.BuildingsDead.ToString();

            return(template);
        }

        ScrollItemWidget ProductionStats(Player player)
        {
            productionStatsHeaders.Visible = true;
            var template = SetupPlayerScrollItemWidget(productionPlayerTemplate, player);

            LobbyUtils.AddPlayerFlagAndName(template, player);

            template.Get <ObserverProductionIconsWidget>("PRODUCTION_ICONS").GetPlayer      = () => player;
            template.Get <ObserverSupportPowerIconsWidget>("SUPPORT_POWER_ICONS").GetPlayer = () => player;
            template.IgnoreChildMouseOver = false;

            return(template);
        }

        ScrollItemWidget EconomyStats(Player player)
        {
            economyStatsHeaders.Visible = true;
            var template = SetupPlayerScrollItemWidget(economyPlayerTemplate, player);

            LobbyUtils.AddPlayerFlagAndName(template, player);

            var res   = player.PlayerActor.Trait <PlayerResources>();
            var stats = player.PlayerActor.TraitOrDefault <PlayerStatistics>();

            if (stats == null)
            {
                return(template);
            }

            template.Get <LabelWidget>("CASH").GetText            = () => "$" + (res.Cash + res.Resources);
            template.Get <LabelWidget>("EARNED_MIN").GetText      = () => AverageEarnedPerMinute(res.Earned);
            template.Get <LabelWidget>("EARNED_THIS_MIN").GetText = () => "$" + stats.EarnedThisMinute;
            template.Get <LabelWidget>("EARNED").GetText          = () => "$" + res.Earned;
            template.Get <LabelWidget>("SPENT").GetText           = () => "$" + res.Spent;

            var assets = template.Get <LabelWidget>("ASSETS");

            assets.GetText = () => "$" + world.ActorsHavingTrait <Valued>()
                             .Where(a => a.Owner == player && !a.IsDead)
                             .Sum(a => a.Info.TraitInfos <ValuedInfo>().First().Cost);

            var harvesters = template.Get <LabelWidget>("HARVESTERS");

            harvesters.GetText = () => world.ActorsHavingTrait <Harvester>().Count(a => a.Owner == player && !a.IsDead).ToString();

            return(template);
        }

        ScrollItemWidget BasicStats(Player player)
        {
            basicStatsHeaders.Visible = true;
            var template = SetupPlayerScrollItemWidget(basicPlayerTemplate, player);

            LobbyUtils.AddPlayerFlagAndName(template, player);

            var res = player.PlayerActor.Trait <PlayerResources>();

            template.Get <LabelWidget>("CASH").GetText       = () => "$" + (res.Cash + res.Resources);
            template.Get <LabelWidget>("EARNED_MIN").GetText = () => AverageEarnedPerMinute(res.Earned);

            var powerRes = player.PlayerActor.Trait <PowerManager>();
            var power    = template.Get <LabelWidget>("POWER");

            power.GetText  = () => powerRes.PowerDrained + "/" + powerRes.PowerProvided;
            power.GetColor = () => GetPowerColor(powerRes.PowerState);

            var stats = player.PlayerActor.TraitOrDefault <PlayerStatistics>();

            if (stats == null)
            {
                return(template);
            }
            template.Get <LabelWidget>("KILLS").GetText            = () => (stats.UnitsKilled + stats.BuildingsKilled).ToString();
            template.Get <LabelWidget>("DEATHS").GetText           = () => (stats.UnitsDead + stats.BuildingsDead).ToString();
            template.Get <LabelWidget>("ASSETS_DESTROYED").GetText = () => "$" + stats.KillsCost;
            template.Get <LabelWidget>("ASSETS_LOST").GetText      = () => "$" + stats.DeathsCost;
            template.Get <LabelWidget>("EXPERIENCE").GetText       = () => stats.Experience.ToString();
            template.Get <LabelWidget>("ACTIONS_MIN").GetText      = () => AverageOrdersPerMinute(stats.OrderCount);

            return(template);
        }

        ScrollItemWidget SetupPlayerScrollItemWidget(ScrollItemWidget template, Player player)
        {
            return(ScrollItemWidget.Setup(template, () => false, () =>
            {
                var playerBase = world.ActorsHavingTrait <BaseBuilding>().FirstOrDefault(a => !a.IsDead && a.Owner == player);
                if (playerBase != null)
                {
                    worldRenderer.Viewport.Center(playerBase.CenterPosition);
                }
            }));
        }
Beispiel #28
0
        void IBotTick.BotTick(IBot bot)
        {
            if (resourceLayer == null || resourceLayer.IsEmpty)
            {
                return;
            }

            if (--scanForIdleHarvestersTicks > 0)
            {
                return;
            }

            var toRemove = harvesters.Keys.Where(unitCannotBeOrdered).ToList();

            foreach (var a in toRemove)
            {
                harvesters.Remove(a);
            }

            scanForIdleHarvestersTicks = Info.ScanForIdleHarvestersInterval;

            // Find new harvesters
            // TODO: Look for a more performance-friendly way to update this list
            var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.ContainsKey(a));

            foreach (var a in newHarvesters)
            {
                harvesters[a] = new HarvesterTraitWrapper(a);
            }

            // Find idle harvesters and give them orders:
            foreach (var h in harvesters)
            {
                if (!h.Key.IsIdle)
                {
                    // Ignore this actor if FindAndDeliverResources is working fine or it is performing a different activity
                    if (!(h.Key.CurrentActivity is FindAndDeliverResources act) || !act.LastSearchFailed)
                    {
                        continue;
                    }
                }

                if (h.Value.Parachutable != null && h.Value.Parachutable.IsInAir)
                {
                    continue;
                }

                // Tell the idle harvester to quit slacking:
                var newSafeResourcePatch = FindNextResource(h.Key, h.Value);
                AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(h.Key, newSafeResourcePatch));
                bot.QueueOrder(new Order("Harvest", h.Key, newSafeResourcePatch, false));
            }

            // Less harvesters than refineries - build a new harvester
            var unitBuilder = requestUnitProduction.FirstOrDefault(Exts.IsTraitEnabled);

            if (unitBuilder != null && Info.HarvesterTypes.Any())
            {
                var harvInfo        = AIUtils.GetInfoByCommonName(Info.HarvesterTypes, player);
                var harvCountTooLow = AIUtils.CountActorByCommonName(Info.HarvesterTypes, player) < AIUtils.CountBuildingByCommonName(Info.RefineryTypes, player);
                if (harvCountTooLow && unitBuilder.RequestedProductionCount(bot, harvInfo.Name) == 0)
                {
                    unitBuilder.RequestUnitProduction(bot, harvInfo.Name);
                }
            }
        }
Beispiel #29
0
        void QueueCaptureOrders(IBot bot)
        {
            if (!Info.CapturingActorTypes.Any() || player.WinState != WinState.Undefined)
            {
                return;
            }

            activeCapturers.RemoveAll(unitCannotBeOrderedOrIsIdle);

            var newUnits = world.ActorsHavingTrait <IPositionable>()
                           .Where(a => a.Owner == player && !activeCapturers.Contains(a));

            var capturers = newUnits
                            .Where(a => a.IsIdle && Info.CapturingActorTypes.Contains(a.Info.Name) && a.Info.HasTraitInfo <CapturesInfo>())
                            .Select(a => new TraitPair <CaptureManager>(a, a.TraitOrDefault <CaptureManager>()))
                            .Where(tp => tp.Trait != null)
                            .ToArray();

            if (capturers.Length == 0)
            {
                return;
            }

            var randPlayer = world.Players.Where(p => !p.Spectating &&
                                                 Info.CapturableStances.HasStance(player.Stances[p])).Random(world.LocalRandom);

            var targetOptions = Info.CheckCaptureTargetsForVisibility
                                ? GetVisibleActorsBelongingToPlayer(randPlayer)
                                : GetActorsThatCanBeOrderedByPlayer(randPlayer);

            var capturableTargetOptions = targetOptions
                                          .Where(target =>
            {
                var captureManager = target.TraitOrDefault <CaptureManager>();
                if (captureManager == null)
                {
                    return(false);
                }

                return(capturers.Any(tp => captureManager.CanBeTargetedBy(target, tp.Actor, tp.Trait)));
            })
                                          .OrderByDescending(target => target.GetSellValue())
                                          .Take(maximumCaptureTargetOptions);

            if (Info.CapturableActorTypes.Any())
            {
                capturableTargetOptions = capturableTargetOptions.Where(target => Info.CapturableActorTypes.Contains(target.Info.Name.ToLowerInvariant()));
            }

            if (!capturableTargetOptions.Any())
            {
                return;
            }

            var failedAttempts = captureHistory.Where(a => a.Key.IsDead).Select(a => a.Value);

            foreach (var capturer in capturers)
            {
                var targetActor = capturableTargetOptions.MinByOrDefault(t => (t.CenterPosition - capturer.Actor.CenterPosition).LengthSquared);
                if (targetActor == null)
                {
                    continue;
                }

                if (failedAttempts.Any(f => f.Actor == targetActor))
                {
                    AIUtils.BotDebug("AI ({0}): skipping capture of {1} as there was a previously failed attempt.", player.ClientIndex, targetActor);
                    continue;
                }

                var target = Target.FromActor(targetActor);
                bot.QueueOrder(new Order("CaptureActor", capturer.Actor, target, true));
                AIUtils.BotDebug("AI ({0}): Ordered {1} to capture {2}", player.ClientIndex, capturer.Actor, targetActor);
                activeCapturers.Add(capturer.Actor);

                if (!captureHistory.ContainsKey(capturer.Actor))
                {
                    captureHistory.Add(capturer.Actor, target);
                }
            }
        }
Beispiel #30
0
        public void Tick(IBot bot)
        {
            // If failed to place something N consecutive times, wait M ticks until resuming building production
            if (failCount >= baseBuilder.Info.MaximumFailedPlacementAttempts && --failRetryTicks <= 0)
            {
                var currentBuildings = world.ActorsHavingTrait <Building>().Count(a => a.Owner == player);
                var baseProviders    = world.ActorsHavingTrait <BaseProvider>().Count(a => a.Owner == player);

                // Only bother resetting failCount if either a) the number of buildings has decreased since last failure M ticks ago,
                // or b) number of BaseProviders (construction yard or similar) has increased since then.
                // Otherwise reset failRetryTicks instead to wait again.
                if (currentBuildings < cachedBuildings || baseProviders > cachedBases)
                {
                    failCount = 0;
                }
                else
                {
                    failRetryTicks = baseBuilder.Info.StructureProductionResumeDelay;
                }
            }

            if (waterState == WaterCheck.NotChecked)
            {
                if (AIUtils.IsAreaAvailable <BaseProvider>(world, player, world.Map, baseBuilder.Info.MaxBaseRadius, baseBuilder.Info.WaterTerrainTypes))
                {
                    waterState = WaterCheck.EnoughWater;
                }
                else
                {
                    waterState         = WaterCheck.NotEnoughWater;
                    checkForBasesTicks = baseBuilder.Info.CheckForNewBasesDelay;
                }
            }

            if (waterState == WaterCheck.NotEnoughWater && --checkForBasesTicks <= 0)
            {
                var currentBases = world.ActorsHavingTrait <BaseProvider>().Count(a => a.Owner == player);

                if (currentBases > cachedBases)
                {
                    cachedBases = currentBases;
                    waterState  = WaterCheck.NotChecked;
                }
            }

            // Only update once per second or so
            if (--waitTicks > 0)
            {
                return;
            }

            playerBuildings = world.ActorsHavingTrait <Building>().Where(a => a.Owner == player).ToArray();
            var excessPowerBonus = baseBuilder.Info.ExcessPowerIncrement * (playerBuildings.Count() / baseBuilder.Info.ExcessPowerIncreaseThreshold.Clamp(1, int.MaxValue));

            minimumExcessPower = (baseBuilder.Info.MinimumExcessPower + excessPowerBonus).Clamp(baseBuilder.Info.MinimumExcessPower, baseBuilder.Info.MaximumExcessPower);

            var active = false;

            foreach (var queue in AIUtils.FindQueues(player, category))
            {
                if (TickQueue(bot, queue))
                {
                    active = true;
                }
            }

            // Add a random factor so not every AI produces at the same tick early in the game.
            // Minimum should not be negative as delays in HackyAI could be zero.
            var randomFactor = world.LocalRandom.Next(0, baseBuilder.Info.StructureProductionRandomBonusDelay);

            // Needs to be at least 4 * OrderLatency because otherwise the AI frequently duplicates build orders (i.e. makes the same build decision twice)
            waitTicks = active ? 4 * world.OrderLatency + baseBuilder.Info.StructureProductionActiveDelay + randomFactor
                                : baseBuilder.Info.StructureProductionInactiveDelay + randomFactor;
        }
Beispiel #31
0
 IEnumerable <Actor> GetActorsWithTrait <T>()
 {
     return(World.ActorsHavingTrait <T>());
 }