ActorInfo ChooseUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) { return(null); } var myUnits = Player.World .ActorsHavingTrait <IPositionable>() .Where(a => a.Owner == Player) .Select(a => a.Info.Name).ToList(); foreach (var unit in Info.UnitsToBuild.Shuffle(Random)) { if (buildableThings.Any(b => b.Name == unit.Key)) { if (myUnits.Count(a => a == unit.Key) < unit.Value * myUnits.Count) { if (HasAdequateAirUnitReloadBuildings(Map.Rules.Actors[unit.Key])) { return(Map.Rules.Actors[unit.Key]); } } } } return(null); }
private void CheckIfProductionConfirmed(ProductionQueue productionQueue) { if (productionQueue.ProductionStatus != ProductionStatus.Confirmed) { throw new ProductionQueueNotConfirmedException(); } }
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name) { producer = queue.Actor; placeBuildingInfo = producer.Owner.PlayerActor.Info.Traits.Get <PlaceBuildingInfo>(); building = name; // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) { producer.World.Selection.Clear(); } var map = producer.World.Map; var tileset = producer.World.TileSet.Id.ToLowerInvariant(); var info = map.Rules.Actors[building]; buildingInfo = info.Traits.Get <BuildingInfo>(); var buildableInfo = info.Traits.Get <BuildableInfo>(); race = buildableInfo.ForceRace ?? queue.MostLikelyProducer().Trait.Race; buildOk = map.SequenceProvider.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0); buildBlocked = map.SequenceProvider.GetSequence("overlay", "build-invalid").GetSprite(0); buildingInfluence = producer.World.WorldActor.Trait <BuildingInfluence>(); }
public override void Tick() { VisibleQueues.Clear(); var queues = world.ActorsWithTrait <ProductionQueue>() .Where(p => p.Actor.Owner == world.LocalPlayer) .Select(p => p.Trait); if (CurrentQueue != null && CurrentQueue.Actor.Destroyed) { CurrentQueue = null; } foreach (var queue in queues) { if (queue.AllItems().Any()) { VisibleQueues.Add(queue); } else if (CurrentQueue == queue) { CurrentQueue = null; } } if (CurrentQueue == null) { CurrentQueue = VisibleQueues.FirstOrDefault(); } TickPaletteAnimation(world); }
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name, WorldRenderer worldRenderer) { Queue = queue; world = queue.Actor.World; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo <PlaceBuildingInfo>(); resourceLayer = world.WorldActor.TraitOrDefault <IResourceLayer>(); viewport = worldRenderer.Viewport; // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) { world.Selection.Clear(); } var variants = new List <VariantWrapper>() { new VariantWrapper(worldRenderer, queue, world.Map.Rules.Actors[name]) }; foreach (var v in variants[0].ActorInfo.TraitInfos <PlaceBuildingVariantsInfo>()) { foreach (var a in v.Actors) { variants.Add(new VariantWrapper(worldRenderer, queue, world.Map.Rules.Actors[a])); } } this.variants = variants.ToArray(); }
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name) { var world = queue.Actor.World; this.queue = queue; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo<PlaceBuildingInfo>(); building = name; // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) world.Selection.Clear(); var map = world.Map; var tileset = world.Map.Tileset.ToLowerInvariant(); var info = map.Rules.Actors[building]; buildingInfo = info.TraitInfo<BuildingInfo>(); var buildableInfo = info.TraitInfo<BuildableInfo>(); var mostLikelyProducer = queue.MostLikelyProducer(); faction = buildableInfo.ForceFaction ?? (mostLikelyProducer.Trait != null ? mostLikelyProducer.Trait.Faction : queue.Actor.Owner.Faction.InternalName); buildOk = map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0); buildBlocked = map.Rules.Sequences.GetSequence("overlay", "build-invalid").GetSprite(0); buildingInfluence = world.WorldActor.Trait<BuildingInfluence>(); }
private async Task ChangeProductionStatusToFinished(ProductionQueue productionQueue, string token) { productionQueue.ProductionStatus = ProductionStatus.Finished; await productionQueueRepo.SaveAllAsync(); await bus.Publish(new ProductionFinishedEvent(productionQueue.OrderId, productionQueue.Quantity, token)); }
public void SetItem(ProductionQueue scr, GameObject prefab) { _scr = scr; _prefab = prefab; UpdateDescription(prefab); button.onClick.AddListener(HandleClick); }
private static void CheckIfProductionBeingCreated(ProductionQueue productionQueue) { if (productionQueue.ProductionStatus != ProductionStatus.BeingCreated) { throw new ProductsNotBeingCreatedException(); } }
public void Tick(Actor self) { if (queue == null) { var type = info.ProductionType ?? self.Trait<Production>().Info.Produces.First(); // Per-actor queue // Note: this includes disabled queues, as each bar must bind to exactly one queue. queue = self.TraitsImplementing<ProductionQueue>() .FirstOrDefault(q => type == null || type == q.Info.Type); if (queue == null) { // No queues available - check for classic production queues queue = self.Owner.PlayerActor.TraitsImplementing<ProductionQueue>() .FirstOrDefault(q => type == null || type == q.Info.Type); } if (queue == null) throw new InvalidOperationException("No queues available for production type '{0}'".F(type)); } var current = queue.CurrentItem(); value = current != null ? 1 - (float)current.RemainingCost / current.TotalCost : 0; }
ActorInfo ChooseUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) { return(null); } var myUnits = player.World .ActorsHavingTrait <IPositionable>() .Where(a => a.Owner == player) .Select(a => a.Info.Name).ToList(); foreach (var unit in Info.UnitsToBuild.Shuffle(world.LocalRandom)) { if (buildableThings.Any(b => b.Name == unit.Key)) { if (myUnits.Count(a => a == unit.Key) * 100 < unit.Value * myUnits.Count) { if (CanBuildMoreOfAircraft(world.Map.Rules.Actors[unit.Key])) { return(world.Map.Rules.Actors[unit.Key]); } } } } return(null); }
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name, WorldRenderer worldRenderer) { var world = queue.Actor.World; this.queue = queue; viewport = worldRenderer.ViewPort; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo <PlaceBuildingInfo>(); building = name; if (WarGame.Settings.Game.UseClassicMouseStyle) { world.Selection.Clear(); } var map = world.Map; var tileset = world.Map.Tileset.ToLowerInvariant(); var info = map.Rules.Actors[building]; buildingInfo = info.TraitInfo <BuildingInfo>(); centerOffset = buildingInfo.CenterOffset(world); topLeftScreenOffset = -worldRenderer.ScreenPxOffset(centerOffset); var buildableInfo = info.TraitInfo <BuildableInfo>(); var mostLikelyProducer = queue.MostLikelyProducer(); faction = buildableInfo.ForceFaction ?? (mostLikelyProducer.Trait != null ? mostLikelyProducer.Trait.Faction : queue.Actor.Owner.Faction.InternalName); buildOk = map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0); buildBlocked = map.Rules.Sequences.GetSequence("overlay", "build-invalid").GetSprite(0); buildingInfluence = world.WorldActor.Trait <BuildingInfluence>(); }
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name) { var world = queue.Actor.World; this.queue = queue; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo <PlaceBuildingInfo>(); building = name; // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) { world.Selection.Clear(); } var map = world.Map; var tileset = world.Map.Tileset.ToLowerInvariant(); var info = map.Rules.Actors[building]; buildingInfo = info.TraitInfo <BuildingInfo>(); var buildableInfo = info.TraitInfo <BuildableInfo>(); var mostLikelyProducer = queue.MostLikelyProducer(); faction = buildableInfo.ForceFaction ?? (mostLikelyProducer.Trait != null ? mostLikelyProducer.Trait.Faction : queue.Actor.Owner.Faction.InternalName); buildOk = map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0); buildBlocked = map.Rules.Sequences.GetSequence("overlay", "build-invalid").GetSprite(0); buildingInfluence = world.WorldActor.Trait <BuildingInfluence>(); }
ActorInfo ChooseUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) { return(null); } var myUnits = p.World .ActorsWithTrait <IPositionable>() .Where(a => a.Actor.Owner == p) .Select(a => a.Actor.Info.Name).ToArray(); foreach (var unit in Info.UnitsToBuild) { if (buildableThings.Any(b => b.Name == unit.Key)) { if (myUnits.Count(a => a == unit.Key) < unit.Value * myUnits.Length) { if (HasAdequateAirUnits(Rules.Info[unit.Key])) { return(Rules.Info[unit.Key]); } } } } return(null); }
ActorInfo ChooseBuildingToBuild(ProductionQueue queue, bool buildPower) { var buildableThings = queue.BuildableItems(); if (!HasAdequatePower()) /* try to maintain 20% excess power */ { if (!buildPower) { return(null); } /* find the best thing we can build which produces power */ return(buildableThings.Where(a => GetPowerProvidedBy(a) > 0) .OrderByDescending(a => GetPowerProvidedBy(a)).FirstOrDefault()); } var myBuildings = p.World .ActorsWithTrait <Building>() .Where(a => a.Actor.Owner == p) .Select(a => a.Actor.Info.Name).ToArray(); foreach (var frac in Info.BuildingFractions) { if (buildableThings.Any(b => b.Name == frac.Key)) { if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length && playerPower.ExcessPower >= Rules.Info[frac.Key].Traits.Get <BuildingInfo>().Power) { return(Rules.Info[frac.Key]); } } } return(null); }
// In cases where we want to build a specific unit but don't know the queue name (because there's more than one possibility) void BuildUnit(IBot bot, string name) { var actorInfo = world.Map.Rules.Actors[name]; if (actorInfo == null) { return; } var buildableInfo = actorInfo.TraitInfoOrDefault <BuildableInfo>(); if (buildableInfo == null) { return; } ProductionQueue queue = null; foreach (var pq in buildableInfo.Queue) { queue = AIUtils.FindQueues(player, pq).FirstOrDefault(q => !q.AllQueued().Any()); if (queue != null) { break; } } if (queue != null) { bot.QueueOrder(Order.StartProduction(queue.Actor, name, 1)); AIUtils.BotDebug("AI: {0} decided to build {1} (external request)", queue.Actor.Owner, name); } }
public ProductionItem(ProductionQueue queue, string item, int cost, PowerManager pm, Action onComplete) { Item = item; RemainingTime = TotalTime = 1; RemainingCost = TotalCost = cost; OnComplete = onComplete; Queue = queue; this.pm = pm; }
public override bool HandleMouseInput(MouseInput mi) { if (mi.Event == MouseInputEvent.Scroll) { Scroll(mi.ScrollDelta); return(true); } if (mi.Button != MouseButton.Left) { return(true); } if (mi.Event == MouseInputEvent.Down && !TakeMouseFocus(mi)) { return(true); } if (!HasMouseFocus) { return(true); } if (HasMouseFocus && mi.Event == MouseInputEvent.Up) { return(YieldMouseFocus(mi)); } leftPressed = leftButtonRect.Contains(mi.Location); rightPressed = rightButtonRect.Contains(mi.Location); var leftDisabled = listOffset >= 0; var rightDisabled = listOffset <= Bounds.Width - rightButtonRect.Width - leftButtonRect.Width - contentWidth; if (leftPressed || rightPressed) { if ((leftPressed && !leftDisabled) || (rightPressed && !rightDisabled)) { Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", "ClickSound", null); } else { Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", "ClickDisabledSound", null); } } // Check production tabs var offsetloc = mi.Location - new int2(leftButtonRect.Right - 1 + (int)listOffset, leftButtonRect.Y); if (offsetloc.X > 0 && offsetloc.X < contentWidth) { CurrentQueue = Groups[queueGroup].Tabs[offsetloc.X / (TabWidth - 1)].Queue; Game.Sound.PlayNotification(world.Map.Rules, null, "Sounds", "ClickSound", null); } return(true); }
ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) { return(null); } return(buildableThings.ElementAtOrDefault(random.Next(buildableThings.Count()))); }
public ProductionItem(ProductionQueue queue, string item, int cost, PowerManager pm, Action onComplete) { Item = item; RemainingTime = TotalTime = 1; RemainingCost = TotalCost = cost; OnComplete = onComplete; Queue = queue; this.pm = pm; //Log.Write("debug", "new ProductionItem: {0} time={1} cost={2}", item, time, cost); }
public void SetCurrentTab(ProductionQueue queue) { if (!paletteOpen) { paletteAnimating = true; } paletteOpen = true; CurrentQueue = queue; }
public async Task StartCreatingProductsCommandHandler_ThrowsProductionQueueNotConfirmedException() { //Arrange var productionQueue = new ProductionQueue(); productionQueueRepo.Setup(x => x.GetById(It.IsAny <int>())).Returns(Task.FromResult(productionQueue)); //Assert await Assert.ThrowsAsync <ProductionQueueNotConfirmedException>(() => commandHandler.Handle(command, It.IsAny <CancellationToken>())); }
public ProductionItem(ProductionQueue queue, string item, int cost, PowerManager pm, Action onComplete) { Item = item; RemainingTime = TotalTime = 1; RemainingCost = TotalCost = cost; OnComplete = onComplete; Queue = queue; this.pm = pm; ai = Queue.Actor.World.Map.Rules.Actors[Item]; bi = ai.TraitInfo<BuildableInfo>(); }
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 ProductionItem(ProductionQueue queue, string item, int time, int cost, Action onComplete) { if (time <= 0) time = 1; Item = item; RemainingTime = TotalTime = time; RemainingCost = TotalCost = cost; OnComplete = onComplete; Queue = queue; //Log.Write("debug", "new ProductionItem: {0} time={1} cost={2}", item, time, cost); }
public BuildPaletteWidget(World world, WorldRenderer worldRenderer) { this.world = world; this.worldRenderer = worldRenderer; cantBuild = new Animation("clock"); cantBuild.PlayFetchIndex("idle", () => 0); clock = new Animation("clock"); VisibleQueues = new List <ProductionQueue>(); CurrentQueue = null; }
public BuildPaletteWidget(OrderManager orderManager, World world, WorldRenderer worldRenderer) { this.orderManager = orderManager; this.world = world; this.worldRenderer = worldRenderer; cantBuild = new Animation(world, "clock"); cantBuild.PlayFetchIndex("idle", () => 0); clock = new Animation(world, "clock"); VisibleQueues = new List<ProductionQueue>(); CurrentQueue = null; }
ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) { return(null); } var unit = buildableThings.Random(world.LocalRandom); return(CanBuildMoreOfAircraft(unit) ? unit : null); }
ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) { return(null); } var unit = buildableThings.ElementAtOrDefault(random.Next(buildableThings.Count())); return(HasAdequateAirUnits(unit) ? unit : null); }
/** * Allocate resources to the top item on this production queue * and return the leftover resources */ private Cost allocateToQueue(ProductionQueue queue, Cost costPer, Cost allocated) { double ironiumPerc = (costPer.getIronium() > 0 ? (double)(allocated.getIronium()) / costPer.getIronium() : 100.0); double boraniumPerc = (costPer.getBoranium() > 0 ? (double)(allocated.getBoranium()) / costPer.getBoranium() : 100.0); double germaniumPerc = (costPer.getGermanium() > 0 ? (double)(allocated.getGermanium()) / costPer.getGermanium() : 100.0); double resourcesPerc = (costPer.getResources() > 0 ? (double)(allocated.getResources()) / costPer.getResources() : 100.0); double minPerc = Mathf.Min((float)ironiumPerc, Mathf.Min((float)boraniumPerc, Mathf.Min((float)germaniumPerc, (float)resourcesPerc))); queue.setAllocated(new Cost((int)(costPer.getIronium() * minPerc), (int)(costPer.getBoranium() * minPerc), (int)(costPer.getGermanium() * minPerc), (int)(costPer.getResources() * minPerc))); return(allocated.subtract(queue.getAllocated())); }
ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) { return(null); } var unit = buildableThings.Random(Random); return(HasAdequateAirUnitReloadBuildings(unit) ? unit : null); }
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name) { Producer = queue.Actor; Building = name; var map = Producer.World.Map; var tileset = Producer.World.TileSet.Id.ToLowerInvariant(); BuildingInfo = map.Rules.Actors[Building].Traits.Get <BuildingInfo>(); buildOk = map.SequenceProvider.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0); buildBlocked = map.SequenceProvider.GetSequence("overlay", "build-invalid").GetSprite(0); }
void FindQueue() { // Per-actor queue // Note: this includes disabled queues, as each bar must bind to exactly one queue. queue = self.TraitsImplementing <ProductionQueue>() .FirstOrDefault(q => Info.ProductionType == q.Info.Type); if (queue == null) { // No queues available - check for classic production queues queue = self.Owner.PlayerActor.TraitsImplementing <ProductionQueue>() .FirstOrDefault(q => Info.ProductionType == q.Info.Type); } }
public async Task StartCreatingProductsCommandHandler_Success() { //Arrange var productionQueue = new ProductionQueue { ProductionStatus = ProductionStatus.Confirmed }; productionQueueRepo.Setup(x => x.GetById(It.IsAny <int>())).Returns(Task.FromResult(productionQueue)); //Act var action = await commandHandler.Handle(command, It.IsAny <CancellationToken>()); //Assert productionQueueRepo.Verify(x => x.SaveAllAsync(), Times.Once); Assert.Equal(Unit.Value, action); }
void SelectQueue(Actor self) { var perBuildingQueues = self.TraitsImplementing <ProductionQueue>(); queue = perBuildingQueues.FirstOrDefault(q => q.Enabled && production.Produces.Contains(q.Info.Type)); if (queue == null) { var perPlayerQueues = self.Owner.PlayerActor.TraitsImplementing <ProductionQueue>(); queue = perPlayerQueues.FirstOrDefault(q => q.Enabled && production.Produces.Contains(q.Info.Type)); } if (queue == null) { throw new InvalidOperationException("Can't find production queues."); } }
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name, WorldRenderer worldRenderer) { var world = queue.Actor.World; this.queue = queue; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo <PlaceBuildingInfo>(); buildingInfluence = world.WorldActor.Trait <BuildingInfluence>(); viewport = worldRenderer.Viewport; // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) { world.Selection.Clear(); } actorInfo = world.Map.Rules.Actors[name]; buildingInfo = actorInfo.TraitInfo <BuildingInfo>(); var previewGeneratorInfo = actorInfo.TraitInfoOrDefault <IPlaceBuildingPreviewGeneratorInfo>(); if (previewGeneratorInfo != null) { var faction = actorInfo.TraitInfo <BuildableInfo>().ForceFaction; if (faction == null) { var mostLikelyProducer = queue.MostLikelyProducer(); faction = mostLikelyProducer.Trait != null ? mostLikelyProducer.Trait.Faction : queue.Actor.Owner.Faction.InternalName; } var td = new TypeDictionary() { new FactionInit(faction), new OwnerInit(queue.Actor.Owner), }; foreach (var api in actorInfo.TraitInfos <IActorPreviewInitInfo>()) { foreach (var o in api.ActorPreviewInits(actorInfo, ActorPreviewType.PlaceBuilding)) { td.Add(o); } } preview = previewGeneratorInfo.CreatePreview(worldRenderer, queue.Actor, actorInfo, td); } }
Action <MouseInput> HandleTabClick(ProductionQueue queue, World world) { return(mi => { if (mi.Button != MouseButton.Left) { return; } Sound.PlayNotification(null, "Sounds", "TabClick", null); var wasOpen = paletteOpen; paletteOpen = (CurrentQueue == queue && wasOpen) ? false : true; CurrentQueue = queue; if (wasOpen != paletteOpen) { paletteAnimating = true; } }); }
ActorInfo ChooseBuildingToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); // First priority is to get out of a low power situation if (playerPower.ExcessPower < ai.Info.MinimumExcessPower) { var power = GetProducibleBuilding("Power", buildableThings, a => a.Traits.WithInterface<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1).Sum(p => p.Amount)); if (power != null && power.Traits.WithInterface<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1).Sum(p => p.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 pis = actor.Traits.WithInterface<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1); if (playerPower.ExcessPower < ai.Info.MinimumExcessPower || playerPower.ExcessPower < pis.Sum(pi => pi.Amount)) { // Try building a power plant instead var power = GetProducibleBuilding("Power", buildableThings, a => a.Traits.WithInterface<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1).Sum(pi => pi.Amount)); if (power != null && power.Traits.WithInterface<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1).Sum(pi => pi.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 override void Tick() { VisibleQueues.Clear(); var queues = world.ActorsWithTrait<ProductionQueue>() .Where(p => p.Actor.Owner == world.LocalPlayer) .Select(p => p.Trait); if (CurrentQueue != null && CurrentQueue.Actor.Destroyed) CurrentQueue = null; foreach (var queue in queues) { if (queue.AllItems().Any()) VisibleQueues.Add(queue); else if (CurrentQueue == queue) CurrentQueue = null; } if (CurrentQueue == null) CurrentQueue = VisibleQueues.FirstOrDefault(); TickPaletteAnimation(world); }
ActorInfo ChooseUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) return null; var myUnits = Player.World .ActorsWithTrait<IPositionable>() .Where(a => a.Actor.Owner == Player) .Select(a => a.Actor.Info.Name).ToList(); foreach (var unit in Info.UnitsToBuild.Shuffle(Random)) if (buildableThings.Any(b => b.Name == unit.Key)) if (myUnits.Count(a => a == unit.Key) < unit.Value * myUnits.Count) if (HasAdequateAirUnitReloadBuildings(Map.Rules.Actors[unit.Key])) return Map.Rules.Actors[unit.Key]; return null; }
int DrawPalette(ProductionQueue queue) { buttons.Clear(); var paletteCollection = "palette-" + world.LocalPlayer.Country.Race; var origin = new float2(paletteOrigin.X + 9, paletteOrigin.Y + 9); var iconOffset = 0.5f * new float2(IconWidth, IconHeight); var x = 0; var y = 0; if (queue != null) { var buildableItems = queue.BuildableItems().ToArray(); var allBuildables = queue.AllItems().OrderBy(a => a.Traits.Get<BuildableInfo>().BuildPaletteOrder).ToArray(); var overlayBits = new List<Pair<Sprite, float2>>(); var textBits = new List<Pair<float2, string>>(); numActualRows = Math.Max((allBuildables.Count() + Columns - 1) / Columns, Rows); // Palette Background WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "top"), new float2(origin.X - 9, origin.Y - 9)); for (var w = 0; w < numActualRows; w++) WidgetUtils.DrawRGBA( ChromeProvider.GetImage(paletteCollection, "bg-" + (w % 4)), new float2(origin.X - 9, origin.Y + IconHeight * w)); WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "bottom"), new float2(origin.X - 9, origin.Y - 1 + IconHeight * numActualRows)); // Icons string tooltipItem = null; var tooltipHotkey = Hotkey.Invalid; var i = 0; foreach (var item in allBuildables) { var rect = new RectangleF(origin.X + x * IconWidth, origin.Y + IconHeight * y, IconWidth, IconHeight); var drawPos = new float2(rect.Location); var icon = new Animation(world, RenderSimple.GetImage(item)); icon.Play(item.Traits.Get<TooltipInfo>().Icon); WidgetUtils.DrawSHPCentered(icon.Image, drawPos + iconOffset, worldRenderer); var firstOfThis = queue.AllQueued().FirstOrDefault(a => a.Item == item.Name); if (rect.Contains(Viewport.LastMousePos)) { tooltipItem = item.Name; tooltipHotkey = Game.Settings.Keys.GetProductionHotkey(i); } var overlayPos = drawPos + new float2(32, 16); if (firstOfThis != null) { clock.PlayFetchIndex("idle", () => (firstOfThis.TotalTime - firstOfThis.RemainingTime) * (clock.CurrentSequence.Length - 1) / firstOfThis.TotalTime); clock.Tick(); WidgetUtils.DrawSHPCentered(clock.Image, drawPos + iconOffset, worldRenderer); if (queue.CurrentItem() == firstOfThis) textBits.Add(Pair.New(overlayPos, GetOverlayForItem(firstOfThis))); var repeats = queue.AllQueued().Count(a => a.Item == item.Name); if (repeats > 1 || queue.CurrentItem() != firstOfThis) textBits.Add(Pair.New(overlayPos + new float2(-24, -14), repeats.ToString())); } else if (buildableItems.All(a => a.Name != item.Name)) overlayBits.Add(Pair.New(cantBuild.Image, drawPos)); var closureName = buildableItems.Any(a => a.Name == item.Name) ? item.Name : null; buttons.Add(Pair.New(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height), HandleClick(closureName, world))); if (++x == Columns) { x = 0; y++; } i++; } if (x != 0) y++; foreach (var ob in overlayBits) WidgetUtils.DrawSHPCentered(ob.First, ob.Second + iconOffset, worldRenderer); var font = Game.Renderer.Fonts["TinyBold"]; foreach (var tb in textBits) { var size = font.Measure(tb.Second); if (ReadyTextStyle == ReadyTextStyleOptions.Solid || orderManager.LocalFrameNumber / 9 % 2 == 0 || tb.Second != ReadyText) font.DrawTextWithContrast(tb.Second, tb.First - new float2(size.X / 2, 0), Color.White, Color.Black, 1); else if (ReadyTextStyle == ReadyTextStyleOptions.AlternatingColor) font.DrawTextWithContrast(tb.Second, tb.First - new float2(size.X / 2, 0), ReadyTextAltColor, Color.Black, 1); } // Tooltip if (tooltipItem != null && !paletteAnimating && paletteOpen) DrawProductionTooltip(world, tooltipItem, tooltipHotkey, new float2(Game.Renderer.Resolution.Width, origin.Y + numActualRows * IconHeight + 9).ToInt2()); } // Palette Dock WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-top"), new float2(Game.Renderer.Resolution.Width - 14, origin.Y - 23)); for (var i = 0; i < numActualRows; i++) WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-" + (i % 4)), new float2(Game.Renderer.Resolution.Width - 14, origin.Y + IconHeight * i)); WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-bottom"), new float2(Game.Renderer.Resolution.Width - 14, origin.Y - 1 + IconHeight * numActualRows)); return IconHeight * y + 9; }
ActorInfo ChooseBuildingToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!HasAdequatePower()) /* try to maintain 20% excess power */ { /* find the best thing we can build which produces power */ return buildableThings.Where(a => GetPowerProvidedBy(a) > 0) .OrderByDescending(a => GetPowerProvidedBy(a)).FirstOrDefault(); } var myBuildings = p.World.Queries.OwnedBy[p].WithTrait<Building>() .Select(a => a.Actor.Info.Name).ToArray(); foreach (var frac in Info.BuildingFractions) if (buildableThings.Any(b => b.Name == frac.Key)) if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length) return Rules.Info[frac.Key]; return null; }
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)); } else if (currentBuilding.Done) { // Production is complete // 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<RefineryInfo>()) 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; }
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 (world.Map.Rules.Actors[currentBuilding.Item].HasTraitInfo<RefineryInfo>()) 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)); 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.ActorsWithTrait<Building>() .Where(a => a.Actor.Owner == player) .Count(); cachedBases = world.ActorsWithTrait<BaseProvider>() .Where(a => a.Actor.Owner == player) .Count(); } } else { failCount = 0; ai.QueueOrder(new Order("PlaceBuilding", player.PlayerActor, false) { TargetLocation = location.Value, TargetString = currentBuilding.Item, TargetActor = queue.Actor, SuppressVisualFeedback = true }); return true; } } return true; }
public void SetCurrentTab(ProductionQueue queue) { if (!paletteOpen) paletteAnimating = true; paletteOpen = true; CurrentQueue = queue; }
ActorInfo ChooseBuildingToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); // This gets used quite a bit, so let's cache it here var power = GetProducibleBuilding("Power", buildableThings, a => a.TraitInfos<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1).Sum(p => p.Amount)); // First priority is to get out of a low power situation if (playerPower.ExcessPower < ai.Info.MinimumExcessPower) { if (power != null && power.TraitInfos<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1).Sum(p => p.Amount) > 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 && HasSufficientPowerForActor(refinery)) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (refinery)", queue.Actor.Owner, refinery.Name); return refinery; } if (power != null && refinery != null && !HasSufficientPowerForActor(refinery)) { HackyAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, power.Name); return power; } } // 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("Production", buildableThings); if (production != null && HasSufficientPowerForActor(production)) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (production)", queue.Actor.Owner, production.Name); return production; } if (power != null && production != null && !HasSufficientPowerForActor(production)) { HackyAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, power.Name); return power; } } // 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.CloseEnoughToWater()) { var navalproduction = GetProducibleBuilding("NavalProduction", buildableThings); if (navalproduction != null && HasSufficientPowerForActor(navalproduction)) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (navalproduction)", queue.Actor.Owner, navalproduction.Name); return navalproduction; } if (power != null && navalproduction != null && !HasSufficientPowerForActor(navalproduction)) { HackyAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, power.Name); return power; } } // Create some head room for resource storage if we really need it if (playerResources.AlertSilo) { var silo = GetProducibleBuilding("Silo", buildableThings); if (silo != null && HasSufficientPowerForActor(silo)) { HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (silo)", queue.Actor.Owner, silo.Name); return silo; } if (power != null && silo != null && !HasSufficientPowerForActor(silo)) { HackyAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, power.Name); return power; } } // 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; // 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. if (ai.Info.BuildingCommonNames.ContainsKey("NavalProduction") && ai.Info.BuildingCommonNames["NavalProduction"].Contains(name) && (waterState == Water.NotEnoughWater || !ai.CloseEnoughToWater())) continue; // Will this put us into low power? var actor = world.Map.Rules.Actors[name]; if (playerPower.ExcessPower < ai.Info.MinimumExcessPower || !HasSufficientPowerForActor(actor)) { // Try building a power plant instead if (power != null && power.TraitInfos<PowerInfo>().Where(i => i.UpgradeMinEnabledLevel < 1).Sum(pi => pi.Amount) > 0) { if (playerPower.PowerOutageRemainingTicks > 0) HackyAI.BotDebug("{0} decided to build {1}: Priority override (is low power)", 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; }
ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (buildableThings.Count() == 0) return null; return buildableThings.ElementAtOrDefault(random.Next(buildableThings.Count())); }
ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) { var buildableThings = queue.BuildableItems(); if (!buildableThings.Any()) return null; var unit = buildableThings.Random(Random); return HasAdequateAirUnitReloadBuildings(unit) ? unit : null; }
Action<MouseInput> HandleTabClick(ProductionQueue queue, World world) { return mi => { if (mi.Button != MouseButton.Left) return; Sound.PlayNotification(world.Map.Rules, null, "Sounds", "TabClick", null); var wasOpen = paletteOpen; paletteOpen = CurrentQueue != queue || !wasOpen; CurrentQueue = queue; if (wasOpen != paletteOpen) paletteAnimating = true; }; }
ActorInfo ChooseDefenseToBuild(ProductionQueue queue) { if (!HasAdequatePower()) return null; var buildableThings = queue.BuildableItems(); var myBuildings = p.World.Queries.OwnedBy[p].WithTrait<Building>() .Select(a => a.Actor.Info.Name).ToArray(); foreach (var frac in Info.BuildingFractions) if (buildableThings.Any(b => b.Name == frac.Key)) if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length) return Rules.Info[frac.Key]; return null; }