Exemple #1
0
        public Squad(HackyMWAI bot, SquadType type, Actor target)
        {
            Bot               = bot;
            World             = bot.World;
            Random            = bot.Random;
            Type              = type;
            Target            = Target.FromActor(target);
            FuzzyStateMachine = new StateMachine();

            switch (type)
            {
            case SquadType.Assault:
            case SquadType.Rush:
                FuzzyStateMachine.ChangeState(this, new GroundUnitsIdleState(), true);
                break;

            case SquadType.Air:
                FuzzyStateMachine.ChangeState(this, new AirIdleState(), true);
                break;

            case SquadType.Protection:
                FuzzyStateMachine.ChangeState(this, new UnitsForProtectionIdleState(), true);
                break;

            case SquadType.Naval:
                FuzzyStateMachine.ChangeState(this, new NavyUnitsIdleState(), true);
                break;
            }
        }
Exemple #2
0
 public UndeadAIHAndler(World w, HackyMWAIInfo hackinfo, HackyMWAI hai, Player player)
 {
     world       = w;
     hackyAIInfo = hackinfo;
     hackyAI     = hai;
     this.Player = player;
 }
Exemple #3
0
 public MWAIHarvesterManager(HackyMWAI ai, Player p)
 {
     this.ai     = ai;
     world       = p.World;
     pathfinder  = world.WorldActor.Trait <IPathFinder>();
     domainIndex = world.WorldActor.Trait <DomainIndex>();
     resLayer    = world.WorldActor.TraitOrDefault <ResourceLayer>();
     claimLayer  = world.WorldActor.TraitOrDefault <ResourceClaimLayer>();
 }
 public BaseBuilder(HackyMWAI ai, string category, Player p, PlayerResources pr)
 {
     this.ai         = ai;
     world           = p.World;
     player          = p;
     playerResources = pr;
     this.category   = category;
     failRetryTicks  = ai.Info.StructureProductionResumeDelay;
 }
Exemple #5
0
 public MWAISupportPowerManager(HackyMWAI ai, Player p)
 {
     this.ai             = ai;
     world               = p.World;
     player              = p;
     frozenLayer         = p.PlayerActor.Trait <FrozenActorLayer>();
     supportPowerManager = p.PlayerActor.TraitOrDefault <SupportPowerManager>();
     foreach (var decision in ai.Info.SupportPowerDecisions)
     {
         powerDecisions.Add(decision.OrderName, decision);
     }
 }
Exemple #6
0
        /// <summary>Scans the map in chunks, evaluating all actors in each.</summary>
        CPos?FindCoarseAttackLocationToSupportPower(SupportPowerInstance readyPower)
        {
            CPos?bestLocation       = null;
            var  bestAttractiveness = 0;
            var  powerDecision      = powerDecisions[readyPower.Info.OrderName];

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

            var map         = world.Map;
            var checkRadius = powerDecision.CoarseScanRadius;

            for (var i = 0; i < map.MapSize.X; i += checkRadius)
            {
                for (var j = 0; j < map.MapSize.Y; j += checkRadius)
                {
                    var tl     = new MPos(i, j);
                    var br     = new MPos(i + checkRadius, j + checkRadius);
                    var region = new CellRegion(map.Grid.Type, tl, br);

                    // HACK: The AI code should not be messing with raw coordinate transformations
                    var wtl     = world.Map.CenterOfCell(tl.ToCPos(map));
                    var wbr     = world.Map.CenterOfCell(br.ToCPos(map));
                    var targets = world.ActorMap.ActorsInBox(wtl, wbr);

                    var frozenTargets            = frozenLayer.FrozenActorsInRegion(region);
                    var consideredAttractiveness = powerDecision.GetAttractiveness(targets, player) + powerDecision.GetAttractiveness(frozenTargets, player);
                    if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness)
                    {
                        continue;
                    }

                    bestAttractiveness = consideredAttractiveness;
                    bestLocation       = new MPos(i, j).ToCPos(map);
                }
            }

            return(bestLocation);
        }
Exemple #7
0
        public void Tick(List <Actor> activeUnits)
        {
            if (resLayer == null || resLayer.IsResourceLayerEmpty)
            {
                return;
            }

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

                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);
                HackyMWAI.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(harvester, newSafeResourcePatch));
                ai.QueueOrder(new Order("Harvest", harvester, Target.FromCell(world, newSafeResourcePatch), false));
            }
        }
Exemple #8
0
        void ITick.Tick(Actor self)
        {
            if (!self.Owner.IsBot)
            {
                return;
            }

            if (--assignRolesTicks <= 0)
            {
                hackyaiinfo     = self.Owner.PlayerActor.Info.TraitInfos <HackyMWAIInfo>().Where(a => a.Type == self.Owner.BotType).First();
                hackyai         = self.Owner.PlayerActor.TraitsImplementing <HackyMWAI>().Where(a => a.Info.Type == self.Owner.BotType).First();
                undeadaihandler = new UndeadAIHAndler(self.World, hackyaiinfo, hackyai, self.Owner);

                if (undeadaihandler == null || hackyai == null || hackyaiinfo == null)
                {
                    return;
                }

                assignRolesTicks = hackyaiinfo.AssignRolesInterval;
                DoStuff(self);
            }
        }
Exemple #9
0
        /// <summary>Detail scans an area, evaluating positions.</summary>
        CPos?FindFineAttackLocationToSupportPower(SupportPowerInstance readyPower, CPos checkPos, int extendedRange = 1)
        {
            CPos?bestLocation       = null;
            var  bestAttractiveness = 0;
            var  powerDecision      = powerDecisions[readyPower.Info.OrderName];

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

            var checkRadius = powerDecision.CoarseScanRadius;
            var fineCheck   = powerDecision.FineScanRadius;

            for (var i = 0 - extendedRange; i <= (checkRadius + extendedRange); i += fineCheck)
            {
                var x = checkPos.X + i;

                for (var j = 0 - extendedRange; j <= (checkRadius + extendedRange); j += fineCheck)
                {
                    var y   = checkPos.Y + j;
                    var pos = world.Map.CenterOfCell(new CPos(x, y));
                    var consideredAttractiveness = 0;
                    consideredAttractiveness += powerDecision.GetAttractiveness(pos, player, frozenLayer);

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

                    bestAttractiveness = consideredAttractiveness;
                    bestLocation       = new CPos(x, y);
                }
            }

            return(bestLocation);
        }
Exemple #10
0
        public void TryToUseSupportPower(Actor self)
        {
            if (supportPowerManager == null)
            {
                return;
            }

            foreach (var sp in supportPowerManager.Powers.Values)
            {
                if (sp.Disabled)
                {
                    continue;
                }

                // Add power to dictionary if not in delay dictionary yet
                if (!waitingPowers.ContainsKey(sp))
                {
                    waitingPowers.Add(sp, 0);
                }

                if (waitingPowers[sp] > 0)
                {
                    waitingPowers[sp]--;
                }

                // If we have recently tried and failed to find a use location for a power, then do not try again until later
                var isDelayed = waitingPowers[sp] > 0;
                if (sp.Ready && !isDelayed && powerDecisions.ContainsKey(sp.Info.OrderName))
                {
                    var powerDecision = powerDecisions[sp.Info.OrderName];
                    if (powerDecision == null)
                    {
                        HackyMWAI.BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", sp.Info.OrderName);
                        continue;
                    }

                    var attackLocation = FindCoarseAttackLocationToSupportPower(sp);
                    if (attackLocation == null)
                    {
                        HackyMWAI.BotDebug("AI: {1} can't find suitable coarse attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName);
                        waitingPowers[sp] += powerDecision.GetNextScanTime(ai);

                        continue;
                    }

                    // Found a target location, check for precise target
                    attackLocation = FindFineAttackLocationToSupportPower(sp, (CPos)attackLocation);
                    if (attackLocation == null)
                    {
                        HackyMWAI.BotDebug("AI: {1} can't find suitable final attack location for support power {0}. Delaying rescan.", sp.Info.OrderName, player.PlayerName);
                        waitingPowers[sp] += powerDecision.GetNextScanTime(ai);

                        continue;
                    }

                    // Valid target found, delay by a few ticks to avoid rescanning before power fires via order
                    HackyMWAI.BotDebug("AI: {2} found new target location {0} for support power {1}.", attackLocation, sp.Info.OrderName, player.PlayerName);
                    waitingPowers[sp] += 10;
                    ai.QueueOrder(new Order(sp.Key, supportPowerManager.Self, Target.FromCell(world, attackLocation.Value), false)
                    {
                        SuppressVisualFeedback = true
                    });
                }
            }
        }
 public int GetNextScanTime(HackyMWAI ai)
 {
     return(ai.Random.Next(MinimumScanTimeInterval, MaximumScanTimeInterval));
 }
Exemple #12
0
 public Squad(HackyMWAI bot, SquadType type) : this(bot, type, null)
 {
 }
        ActorInfo ChooseBuildingToBuild(ProductionQueue queue)
        {
            if (ai.Player.Faction.InternalName != "ded")
            {
                var buildableThings = queue.BuildableItems();

                var houses = GetProducibleBuilding(ai.Info.BuildingCommonNames.Houses, buildableThings,
                                                   a => a.TraitInfos <ValuedInfo>().Sum(p => p.Cost));

                // This gets used quite a bit, so let's cache it here
                var population = ai.CountPossiblePopulation() + ai.CountPotentialFreeBeds();

                // First priority is to get out of a low power situation
                if (population < ai.Info.Population)
                {
                    if (houses != null)
                    {
                        HackyMWAI.BotDebug("AI: {0} decided to build {1}: Priority override (low population) Population: " + population, queue.Actor.Owner, houses.Name);
                        return(houses);
                    }

                    if (houses == null && population < ai.Info.MinimumPeasants)
                    {
                        return(null);
                    }
                }

                // Next is to build up a strong economy
                if (!ai.HasAdequateFarm() || !ai.HasMinimumFarm())
                {
                    var farm = GetProducibleBuilding(ai.Info.BuildingCommonNames.Farms, buildableThings);
                    if (farm != null && population > ai.Info.MinimumPeasants)
                    {
                        HackyMWAI.BotDebug("AI: {0} decided to build {1}: Priority override (refinery)", queue.Actor.Owner, farm.Name);
                        return(farm);
                    }

                    if ((houses != null && farm != null) && population < ai.Info.Population)
                    {
                        HackyMWAI.BotDebug("AI: {0} decided to build {1}: Priority override (low population) Population: " + population, queue.Actor.Owner, houses.Name);
                        return(houses);
                    }
                }

                // Make sure that we can spend as fast as we are earning
                if (ai.Info.NewProductionCashThreshold > 0 && playerResources.Resources > ai.Info.NewProductionCashThreshold)
                {
                    var production = GetProducibleBuilding(ai.Info.BuildingCommonNames.Production, buildableThings);
                    if (production != null && population >= ai.Info.Population)
                    {
                        HackyMWAI.BotDebug("AI: {0} decided to build {1}: Priority override (production)", queue.Actor.Owner, production.Name);
                        return(production);
                    }

                    if (houses != null && production != null && population < ai.Info.Population)
                    {
                        HackyMWAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, houses.Name);
                        return(houses);
                    }
                }

                // Only consider building this if there is enough water inside the base perimeter and there are close enough adjacent buildings
                if (waterState == Water.EnoughWater && ai.Info.NewProductionCashThreshold > 0 &&
                    playerResources.Resources > ai.Info.NewProductionCashThreshold &&
                    ai.IsAreaAvailable <GivesBuildableArea>(ai.Info.CheckForWaterRadius, ai.Info.WaterTerrainTypes))
                {
                    var navalproduction = GetProducibleBuilding(ai.Info.BuildingCommonNames.NavalProduction, buildableThings);
                    if (navalproduction != null && population >= ai.Info.Population)
                    {
                        HackyMWAI.BotDebug("AI: {0} decided to build {1}: Priority override (navalproduction)", queue.Actor.Owner, navalproduction.Name);
                        return(navalproduction);
                    }

                    if (houses != null && navalproduction != null && population < ai.Info.Population)
                    {
                        HackyMWAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, houses.Name);
                        return(houses);
                    }
                }

                // Build everything else
                foreach (var frac in ai.Info.BuildingFractions.Shuffle(ai.Random))
                {
                    var name   = frac.Key;
                    var names  = ai.Info.BuildingCommonNames;
                    var hunter = names.Hunter;

                    if (!ai.HasAdequateFarm() && (!names.Houses.Contains(name) || !hunter.Contains(name)) && (!hunter.Contains(name) || ai.Player.Faction.InternalName == "nod"))
                    {
                        continue;
                    }

                    if (names.Houses.Contains(name) && population > 40)
                    {
                        continue;
                    }

                    // Can we build this structure?
                    if (!buildableThings.Any(b => b.Name == name))
                    {
                        continue;
                    }

                    // Do we want to build this structure?
                    var count = playerBuildings.Count(a => a.Info.Name == name) + playerBuildings.Count(a => a.Info.Name == name.Replace(".scaff", string.Empty).ToLower());
                    if (count > frac.Value * playerBuildings.Length)
                    {
                        continue;
                    }

                    if (ai.Info.BuildingLimits.ContainsKey(name) && ai.Info.BuildingLimits[name] <= count)
                    {
                        continue;
                    }

                    // If we're considering to build a naval structure, check whether there is enough water inside the base perimeter
                    // and any structure providing buildable area close enough to that water.
                    // TODO: Extend this check to cover any naval structure, not just production.

                    // Will this put us into low power?
                    var actor = world.Map.Rules.Actors[name];

                    // Lets build this
                    HackyMWAI.BotDebug("{0} decided to build {1}: Desired is {2} ({3} / {4}); current is {5} / {4}",
                                       queue.Actor.Owner, name, frac.Value, frac.Value * playerBuildings.Length, playerBuildings.Length, count);
                    return(actor);
                }

                // Too spammy to keep enabled all the time, but very useful when debugging specific issues.
                // HackyMWAI.BotDebug("{0} couldn't decide what to build for queue {1}.", queue.Actor.Owner, queue.Info.Group);
                return(null);
            }
            else
            {
                var buildableThings = queue.BuildableItems();

                var pentagrams = ai.CountPenagrams();

                if (pentagrams > 1)
                {
                    return(null);
                }

                if ((ai.HasAdequateCrypts() * 3) < playerBuildings.Count())
                {
                    var crypt = GetProducibleBuilding(ai.Info.UndeadCommonNames.Crypts, buildableThings);
                    if (crypt != null)
                    {
                        HackyMWAI.BotDebug("AI: {0} decided to build {1}: Priority override (production)", queue.Actor.Owner, crypt.Name);
                        return(crypt);
                    }
                }

                // Build everything else
                foreach (var frac in ai.Info.BuildingFractions.Shuffle(ai.Random))
                {
                    var name = frac.Key;

                    // Can we build this structure?
                    if (!buildableThings.Any(b => b.Name == name))
                    {
                        continue;
                    }

                    if (ai.HasAdequateCrypts() * 3 >= playerBuildings.Count() && ai.Info.UndeadCommonNames.Crypts.Contains(name))
                    {
                        continue;
                    }

                    // Do we want to build this structure?
                    var count = playerBuildings.Count(a => a.Info.Name == name) + playerBuildings.Count(a => a.Info.Name == name.Replace(".penta", string.Empty).ToLower());
                    if (count > frac.Value * playerBuildings.Length)
                    {
                        continue;
                    }

                    if (ai.Info.BuildingLimits.ContainsKey(name) && ai.Info.BuildingLimits[name] <= count)
                    {
                        continue;
                    }

                    var actor = world.Map.Rules.Actors[name];

                    // Lets build this
                    HackyMWAI.BotDebug("{0} decided to build {1}: Desired is {2} ({3} / {4}); current is {5} / {4}",
                                       queue.Actor.Owner, name, frac.Value, frac.Value * playerBuildings.Length, playerBuildings.Length, count);
                    return(actor);
                }

                // Too spammy to keep enabled all the time, but very useful when debugging specific issues.
                // HackyMWAI.BotDebug("{0} couldn't decide what to build for queue {1}.", queue.Actor.Owner, queue.Info.Group);
                return(null);
            }
        }
        bool TickQueue(ProductionQueue queue)
        {
            var currentBuilding = queue.CurrentItem();

            // Waiting to build something
            if (currentBuilding == null && failCount < ai.Info.MaximumFailedPlacementAttempts)
            {
                var item = ChooseBuildingToBuild(queue);
                if (item == null)
                {
                    return(false);
                }

                ai.QueueOrder(Order.StartProduction(queue.Actor, item.Name, 1));
            }
            else if (currentBuilding != null && currentBuilding.Done)
            {
                // Production is complete
                // Choose the placement logic
                // HACK: HACK HACK HACK
                // TODO: Derive this from BuildingCommonNames instead
                var type = BuildingType.Building;
                if (world.Map.Rules.Actors[currentBuilding.Item].HasTraitInfo <AttackBaseInfo>())
                {
                    type = BuildingType.Defense;
                }
                else if (ai.Info.BuildingCommonNames.Refineries.Contains(world.Map.Rules.Actors[currentBuilding.Item].Name.ToLower()))
                {
                    type = BuildingType.Refinery;
                }
                else if (ai.Info.BuildingCommonNames.Farms.Contains(world.Map.Rules.Actors[currentBuilding.Item].Name.ToLower()))
                {
                    type = BuildingType.Farm;
                }
                else if (ai.Info.UndeadCommonNames.Sppool.Contains(world.Map.Rules.Actors[currentBuilding.Item].Name.ToLower()))
                {
                    type = BuildingType.Sppool;
                }
                else if (ai.Info.BuildingCommonNames.ImportantBuildings.Contains(world.Map.Rules.Actors[currentBuilding.Item].Name.ToLower()))
                {
                    type = BuildingType.Important;
                }
                else if (ai.Info.BuildingCommonNames.Houses.Contains(world.Map.Rules.Actors[currentBuilding.Item].Name.ToLower()))
                {
                    type = BuildingType.Regular;
                }
                else if (ai.Info.BuildingCommonNames.Hunter.Contains(world.Map.Rules.Actors[currentBuilding.Item].Name.ToLower()))
                {
                    type = BuildingType.Hunter;
                }
                else if (ai.Player.Faction.InternalName == "ded")
                {
                    type = BuildingType.Undead;
                }

                var location = ai.ChooseBuildLocation(currentBuilding.Item, true, type);
                if (location == null)
                {
                    HackyMWAI.BotDebug("AI: {0} has nowhere to place {1}".F(player, currentBuilding.Item));
                    ai.QueueOrder(Order.CancelProduction(queue.Actor, currentBuilding.Item, 1));
                    failCount += failCount;

                    // If we just reached the maximum fail count, cache the number of current structures
                    if (failCount == ai.Info.MaximumFailedPlacementAttempts)
                    {
                        cachedBuildings = world.ActorsHavingTrait <Building>().Count(a => a.Owner == player);
                        cachedBases     = world.ActorsHavingTrait <BaseProvider>().Count(a => a.Owner == player);
                    }
                }
                else
                {
                    failCount = 0;
                    ai.QueueOrder(new Order("PlaceBuilding", player.PlayerActor, Target.FromCell(world, location.Value), false)
                    {
                        // Building to place
                        TargetString = currentBuilding.Item,

                        // Actor ID to associate the placement with
                        ExtraData = queue.Actor.ActorID,
                        SuppressVisualFeedback = true
                    });

                    return(true);
                }
            }

            return(true);
        }