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 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); }
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 BuildPaletteWidget(World world, WorldRenderer worldRenderer) { this.world = world; this.worldRenderer = worldRenderer; cantBuild = new Animation("clock"); cantBuild.PlayFetchIndex("idle", () => 0); clock = new Animation("clock"); paletteOrigin = paletteClosedOrigin; VisibleQueues = new List<ProductionQueue>(); CurrentQueue = null; iconSprites = Rules.Info.Values .Where(u => u.Traits.Contains<BuildableInfo>() && u.Name[0] != '^') .ToDictionary( u => u.Name, u => Game.modData.SpriteLoader.LoadAllSprites( u.Traits.Get<TooltipInfo>().Icon ?? (u.Name + "icon"))[0]); }
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.self.Destroyed) CurrentQueue = null; foreach (var queue in queues) { if (queue.AllItems().Count() > 0) VisibleQueues.Add(queue); else if (CurrentQueue == queue) CurrentQueue = null; } if (CurrentQueue == null) CurrentQueue = VisibleQueues.FirstOrDefault(); TickPaletteAnimation(world); }
public void SetCurrentTab(ProductionQueue queue) { if (!paletteOpen) paletteAnimating = true; paletteOpen = true; CurrentQueue = queue; }
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; }; }
String ChooseShip(ProductionQueue queue) { String item = null; // SS MSUB DD CA PT if (AI.p.Country.Race == "soviet") { int random = AI.random.Next() % 2; if (random == 0) { item = "ss"; } else if (random == 1) { item = "msub"; } } else if (AI.p.Country.Race == "allies") { int random = AI.random.Next() % 3; if (random == 0) { item = "dd"; } else if (random == 1) { item = "ca"; } else if (random == 2) { item = "pt"; } } var buildableThings = queue.BuildableItems(); if (buildableThings.Any(b => b.Name == item)) return item; // Return it only if we can actually build it return null; }
// pbox hbox gun agun ftur tsla sam String ChooseStructure(ProductionQueue queue) { if (!HasAdequateItem("weap", 1)) return null; // Don't start producing until we have a War Factory String item = null; var buildableThings = queue.BuildableItems(); if (AI.p.Country.Race == "soviet") { int random = AI.random.Next() % 3; if (random == 0) { if (!HasAdequateItem("ftur", MaxCheapDefense)) item = "ftur"; } else if (random == 1) { if (!HasAdequateItem("tsla", MaxExpensiveDefense)) item = "tsla"; } else if (random == 2) { if (!HasAdequateItem("sam", MaxAntiAirDefense)) item = "sam"; } } else if (AI.p.Country.Race == "allies") { int random = AI.random.Next() % 4; if (random == 0) { if (!HasAdequateItem("pbox", MaxCheapDefense)) item = "pbox"; } else if (random == 1) { if (!HasAdequateItem("gun", MaxExpensiveDefense)) item = "gun"; } else if (random == 2) { if (!HasAdequateItem("agun", MaxAntiAirDefense)) item = "agun"; } else if (random == 3) { if (!HasAdequateItem("hbox", MaxCheapDefense)) item = "hbox"; } } if (buildableThings.Any(b => b.Name == item)) return item; return null; }
String ChooseStructure(ProductionQueue queue) { String item = null; var buildableThings = queue.BuildableItems(); if (!HasAdequateItem("powr", 1)) { return "powr"; } if (!HasAdequatePower()) if (buildableThings.Any(b => b.Name == "apwr")) return "apwr"; else return "powr"; if (AI.p.Country.Race == "soviet") if (!HasAdequateItem("barr", 1)) { return "barr"; } if (AI.p.Country.Race == "allies") if (!HasAdequateItem("tent", 1)) { return "tent"; } if (!HasAdequateItem("proc", 1)) { return "proc"; } if (!HasAdequateItem("weap", 1)) { return "weap"; } if (!HasAdequateItem("apwr", 1)) { return "apwr"; } if (!HasAdequateItem("weap", 2)) { return "weap"; } if (!HasAdequateItem("dome", 1)) { return "dome"; } if (AI.p.Country.Race == "soviet") if (!HasAdequateItem("afld", 1)) { return "afld"; } if (AI.p.Country.Race == "allies") if (!HasAdequateItem("hpad", 1)) { return "hpad"; } if (AI.p.Country.Race == "soviet") if (!HasAdequateItem("afld", 2)) { return "afld"; } if (AI.p.Country.Race == "allies") if (!HasAdequateItem("hpad", 2)) { return "hpad"; } if (AI.p.Country.Race == "soviet") if (!HasAdequateItem("spen", 1) && (ChooseBuildLocation("spen") != null) ) { return "spen"; } if (AI.p.Country.Race == "allies") if (!HasAdequateItem("syrd", 1) && (ChooseBuildLocation("syrd") != null)) { return "syrd"; } if (!HasAdequateItem("weap", 3)) { return "weap"; } if (!HasAdequateItem("apwr", 2)) { return "apwr"; } if (AI.p.Country.Race == "soviet") if (!HasAdequateItem("stek", 1)) { return "stek"; } if (AI.p.Country.Race == "allies") if (!HasAdequateItem("atek", 1)) { return "atek"; } if (!HasAdequateItem("apwr", 3)) { return "apwr"; } if (!HasAdequateItem("proc", 2)) { return "proc"; } return item; }
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<BuildingInfo>().Power); if (power != null && power.Traits.Get<BuildingInfo>().Power > 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 bi = actor.Traits.Get<BuildingInfo>(); if (playerPower.ExcessPower < 0 || playerPower.ExcessPower < bi.Power) { // Try building a power plant instead var power = GetProducibleBuilding("Power", buildableThings, a => a.Traits.Get<BuildingInfo>().Power); if (power != null && power.Traits.Get<BuildingInfo>().Power > 0) { 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 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; }
String ChooseAircraft(ProductionQueue queue) { String item = null; if (AI.p.Country.Race == "soviet") { int random = AI.random.Next() % 3; if (random == 0) { item = "yak"; } else if (random == 1) { item = "mig"; } else if (random == 2) { item = "hind"; } } else if (AI.p.Country.Race == "allies") { item = "heli"; } if (item == "heli" || item == "hind") { var hpads = world.ActorsWithTrait<Building>() .Where(a => a.Actor.Owner == AI.p && a.Actor.Info.Name == "hpad").Count(); var helis = world.Actors .Where(a => a.Owner == AI.p && a.Info.Name == "heli" || a.Info.Name == "hind").Count(); if ((hpads * 1) <= helis) // Max amount of allowed helis { item = null; } } if (item == "mig" || item == "yak") { var aflds = world.ActorsWithTrait<Building>() .Where(a => a.Actor.Owner == AI.p && a.Actor.Info.Name == "afld").Count(); var planes = world.Actors .Where(a => a.Owner == AI.p && a.Info.Name == "yak" || a.Info.Name == "mig").Count(); if ((aflds * 1) <= planes) // Max amount of allowed planes { item = null; } } var buildableThings = queue.BuildableItems(); if (buildableThings.Any(b => b.Name == item)) return item; // Return it only if we can actually build it 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; 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; 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++; } } 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, 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; }
int DrawPalette(ProductionQueue queue) { buttons.Clear(); string paletteCollection = "palette-" + world.LocalPlayer.Country.Race; float2 origin = new float2(paletteOrigin.X + 9, paletteOrigin.Y + 9); 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).ToString()), new float2(origin.X - 9, origin.Y + 48 * w)); WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "bottom"), new float2(origin.X - 9, origin.Y - 1 + 48 * numActualRows)); // Icons string tooltipItem = null; foreach (var item in allBuildables) { var rect = new RectangleF(origin.X + x * 64, origin.Y + 48 * y, 64, 48); var drawPos = new float2(rect.Location); WidgetUtils.DrawSHP(iconSprites[item.Name], drawPos, worldRenderer); var firstOfThis = queue.AllQueued().FirstOrDefault(a => a.Item == item.Name); if (rect.Contains(Viewport.LastMousePos)) tooltipItem = item.Name; 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.DrawSHP(clock.Image, drawPos, 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) { var offset = -40; var digits = repeats.ToString(); foreach (var d in digits) { ready.PlayFetchIndex("groups", () => d - '0'); ready.Tick(); overlayBits.Add(Pair.New(ready.Image, overlayPos + new float2(offset, -14))); offset += 6; } } } else if (!buildableItems.Any(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++; } } if (x != 0) y++; foreach (var ob in overlayBits) WidgetUtils.DrawSHP(ob.First, ob.Second, worldRenderer); var font = Game.Renderer.Fonts["TinyBold"]; foreach (var tb in textBits) { var size = font.Measure(tb.Second); font.DrawTextWithContrast(tb.Second, tb.First - new float2( size.X / 2, 0 ), Color.White, Color.Black, 1); } // Tooltip if (tooltipItem != null && !paletteAnimating && paletteOpen) DrawProductionTooltip(world, tooltipItem, new float2(Game.viewport.Width, origin.Y + numActualRows * 48 + 9).ToInt2()); } // Palette Dock WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-top"), new float2(Game.viewport.Width - 14, origin.Y - 23)); for (int i = 0; i < numActualRows; i++) WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-" + (i % 4).ToString()), new float2(Game.viewport.Width - 14, origin.Y + 48 * i)); WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-bottom"), new float2(Game.viewport.Width - 14, origin.Y - 1 + 48 * numActualRows)); return 48 * y + 9; }
Action<MouseInput> HandleTabClick(ProductionQueue queue, World world) { return mi => { if (mi.Button != MouseButton.Left) return; Sound.Play(TabClick); var wasOpen = paletteOpen; paletteOpen = (CurrentQueue == queue && wasOpen) ? false : true; CurrentQueue = queue; if (wasOpen != paletteOpen) paletteAnimating = true; }; }
String ChooseInfantry(ProductionQueue queue) { String item = null; if (AI.p.Country.Race == "soviet") { int random = AI.random.Next() % 3; if (random == 0) { item = "e1"; } else if (random == 1) { item = "e2"; } else if (random == 2) { item = "e3"; } } else if (AI.p.Country.Race == "allies") { int random = AI.random.Next() % 4; if (random == 0) { item = "e1"; } else if (random == 1) { item = "e2"; } else if (random == 2) { item = "e3"; } else if (random == 3) { item = "e7"; } } var buildableThings = queue.BuildableItems(); if (buildableThings.Any(b => b.Name == item)) return item; // Return it only if we can actually build it return null; }
public void PlaceStructure(ProductionQueue queue, ProductionItem currentBuilding) { CPos? location = ChooseBuildLocation(currentBuilding.Item); if (location == null) { AI.Debug("AI: Nowhere to place or no adequate number {0}".F(currentBuilding.Item)); world.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1)); } else world.IssueOrder(new Order("PlaceBuilding", AI.p.PlayerActor, false) { TargetLocation = location.Value, TargetString = currentBuilding.Item }); // if (!HasAdequateNumber(currentBuilding.Item, ai.p)) // world.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1)); }
String ChooseVehicle(ProductionQueue queue) { String item = null; if (AI.p.Country.Race == "soviet") { int random = AI.random.Next() % 4; if (random == 0) { item = "3tnk"; } else if (random == 1) { item = "4tnk"; } else if (random == 2) { item = "ttnk"; } else if (random == 3) { item = "v2rl"; } } else if (AI.p.Country.Race == "allies") { int random = AI.random.Next() % 5; if (random == 0) { item = "1tnk"; } else if (random == 1) { item = "2tnk"; } else if (random == 2) { item = "apc"; } else if (random == 3) { item = "arty"; } else if (random == 4) { item = "jeep"; } } var buildableThings = queue.BuildableItems(); if (buildableThings.Any(b => b.Name == item)) return item; // Return it only if we can actually build it return null; }