public Squad(HackyAI bot, SquadType type, Actor target) { this.bot = bot; this.world = bot.world; this.random = bot.random; this.type = type; this.target = Traits.Target.FromActor(target); fsm = new StateMachine(); switch (type) { case SquadType.Assault: case SquadType.Rush: fsm.ChangeState(this, new GroundUnitsIdleState(), true); break; case SquadType.Air: fsm.ChangeState(this, new AirIdleState(), true); break; case SquadType.Protection: fsm.ChangeState(this, new UnitsForProtectionIdleState(), true); break; } }
public BaseBuilder(HackyAI ai, string category, Player p, PowerManager pm, PlayerResources pr) { this.ai = ai; world = p.World; player = p; playerPower = pm; playerResources = pr; this.category = category; }
bool TickQueue(ProductionQueue queue) { var currentBuilding = queue.CurrentItem(); // Waiting to build something if (currentBuilding == null) { var item = ChooseBuildingToBuild(queue); if (item == null) { return(false); } HackyAI.BotDebug("AI: {0} is starting production of {1}".F(player, item.Name)); world.IssueOrder(Order.StartProduction(queue.Actor, item.Name, 1)); } // Production is complete else if (currentBuilding.Done) { // Choose the placement logic // HACK: HACK HACK HACK var type = BuildingType.Building; if (world.Map.Rules.Actors[currentBuilding.Item].Traits.Contains <AttackBaseInfo>()) { type = BuildingType.Defense; } else if (world.Map.Rules.Actors[currentBuilding.Item].Traits.Contains <OreRefineryInfo>()) { type = BuildingType.Refinery; } var location = ai.ChooseBuildLocation(currentBuilding.Item, true, type); if (location == null) { HackyAI.BotDebug("AI: {0} has nowhere to place {1}".F(player, currentBuilding.Item)); world.IssueOrder(Order.CancelProduction(queue.Actor, currentBuilding.Item, 1)); } else { world.IssueOrder(new Order("PlaceBuilding", player.PlayerActor, false) { TargetLocation = location.Value, TargetString = currentBuilding.Item, TargetActor = queue.Actor, SuppressVisualFeedback = true }); return(true); } } return(true); }
public BaseBuilder(HackyAI ai, string category, Func<ProductionQueue, ActorInfo> chooseItem) { this.ai = ai; this.category = category; this.chooseItem = chooseItem; }
public Squad(HackyAI bot, SquadType type) : this(bot, type, null) { }
public void Tick() { // Pick a free queue var queue = ai.FindQueues(category).FirstOrDefault(); if (queue == null) { return; } var currentBuilding = queue.CurrentItem(); switch (state) { case BuildState.ChooseItem: { var item = chooseItem(queue); if (item == null) { state = BuildState.WaitForFeedback; lastThinkTick = ai.ticks; } else { HackyAI.BotDebug("AI: Starting production of {0}".F(item.Name)); state = BuildState.WaitForProduction; ai.world.IssueOrder(Order.StartProduction(queue.self, item.Name, 1)); } } break; case BuildState.WaitForProduction: if (currentBuilding == null) { return; /* let it happen.. */ } else if (currentBuilding.Paused) { ai.world.IssueOrder(Order.PauseProduction(queue.self, currentBuilding.Item, false)); } else if (currentBuilding.Done) { state = BuildState.WaitForFeedback; lastThinkTick = ai.ticks; /* place the building */ var location = ai.ChooseBuildLocation(currentBuilding.Item); if (location == null) { HackyAI.BotDebug("AI: Nowhere to place {0}".F(currentBuilding.Item)); ai.world.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1)); } else { ai.world.IssueOrder(new Order("PlaceBuilding", ai.p.PlayerActor, false) { TargetLocation = location.Value, TargetString = currentBuilding.Item }); } } break; case BuildState.WaitForFeedback: if (ai.ticks - lastThinkTick > HackyAI.feedbackTime) { state = BuildState.ChooseItem; } break; } }
public BaseBuilder(HackyAI ai, string category, Func <ProductionQueue, ActorInfo> chooseItem) { this.ai = ai; this.category = category; this.chooseItem = chooseItem; }
ActorInfo ChooseBuildingToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); // First priority is to get out of a low power situation if (playerPower.ExcessPower < 0) { var power = GetProducibleBuilding("Power", buildableThings, a => a.Traits.Get <PowerInfo>().Amount); if (power != null && power.Traits.Get <PowerInfo>().Amount > 0) { // TODO: Handle the case when of when we actually do need a power plant because we don't have enough but are also suffering from a power outage if (playerPower.PowerOutageRemainingTicks <= 0) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (low power)", queue.Actor.Owner, power.Name); return(power); } } } // Next is to build up a strong economy if (!ai.HasAdequateProc() || !ai.HasMinimumProc()) { var refinery = GetProducibleBuilding("Refinery", buildableThings); if (refinery != null) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (refinery)", queue.Actor.Owner, refinery.Name); return(refinery); } } // Make sure that we can can spend as fast as we are earning if (ai.Info.NewProductionCashThreshold > 0 && playerResources.Resources > ai.Info.NewProductionCashThreshold) { var production = GetProducibleBuilding("Production", buildableThings); if (production != null) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (production)", queue.Actor.Owner, production.Name); return(production); } } // Create some head room for resource storage if we really need it if (playerResources.AlertSilo) { var silo = GetProducibleBuilding("Silo", buildableThings); if (silo != null) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (silo)", queue.Actor.Owner, silo.Name); return(silo); } } // 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; } // Do we want to build this structure? var count = playerBuildings.Count(a => a.Info.Name == name); if (count > frac.Value * playerBuildings.Length) { continue; } if (ai.Info.BuildingLimits.ContainsKey(name) && ai.Info.BuildingLimits[name] <= count) { continue; } // Will this put us into low power? var actor = world.Map.Rules.Actors[frac.Key]; var pi = actor.Traits.GetOrDefault <PowerInfo>(); if (playerPower.ExcessPower < 0 || (pi != null && playerPower.ExcessPower < pi.Amount)) { // Try building a power plant instead var power = GetProducibleBuilding("Power", buildableThings, a => a.Traits.Get <PowerInfo>().Amount); if (power != null && power.Traits.Get <PowerInfo>().Amount > 0) { // TODO: Handle the case when of when we actually do need a power plant because we don't have enough but are also suffering from a power outage if (playerPower.PowerOutageRemainingTicks > 0) { HackyAI.BotDebug("AI: {0} is suffering from a power outage; not going to build {1}", queue.Actor.Owner, power.Name); } else { HackyAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, power.Name); return(power); } } } // Lets build this HackyAI.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. // HackyAI.BotDebug("{0} couldn't decide what to build for queue {1}.", queue.Actor.Owner, queue.Info.Group); return(null); }
public void Tick() { // Pick a free queue var queue = ai.FindQueues(category).FirstOrDefault(); if (queue == null) { return; } var currentBuilding = queue.CurrentItem(); switch (state) { case BuildState.ChooseItem: var item = chooseItem(queue); if (item == null) { state = BuildState.WaitForFeedback; lastThinkTick = ai.ticks; } else { HackyAI.BotDebug("AI: Starting production of {0}".F(item.Name)); state = BuildState.WaitForProduction; ai.world.IssueOrder(Order.StartProduction(queue.self, item.Name, 1)); } break; case BuildState.WaitForProduction: if (currentBuilding == null) { return; } if (currentBuilding.Paused) { ai.world.IssueOrder(Order.PauseProduction(queue.self, currentBuilding.Item, false)); } else if (currentBuilding.Done) { state = BuildState.WaitForFeedback; lastThinkTick = ai.ticks; // Place the building var type = BuildingType.Building; if (ai.Map.Rules.Actors[currentBuilding.Item].Traits.Contains <AttackBaseInfo>()) { type = BuildingType.Defense; } else if (ai.Map.Rules.Actors[currentBuilding.Item].Traits.Contains <OreRefineryInfo>()) { type = BuildingType.Refinery; } var location = ai.ChooseBuildLocation(currentBuilding.Item, type); if (location == null) { HackyAI.BotDebug("AI: Nowhere to place {0}".F(currentBuilding.Item)); ai.world.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1)); } else { ai.world.IssueOrder(new Order("PlaceBuilding", ai.p.PlayerActor, false) { TargetLocation = location.Value, TargetString = currentBuilding.Item }); } } break; case BuildState.WaitForFeedback: if (ai.ticks - lastThinkTick > HackyAI.feedbackTime) { state = BuildState.ChooseItem; } break; } }