private void BuildQueen(GameState gameState, ZergBuilding hatchery, List <Command> commands) { if (gameState.Observation.PlayerCommon.Minerals < 150 || gameState.Observation.PlayerCommon.FoodUsed > gameState.Observation.PlayerCommon.FoodCap - 2) { return; } commands.Add(hatchery.Train(ZergUnitType.Queen)); }
private void Attack(GameState gameState, ZergBuilding hatchery, List <ZergUnit> soldiers, List <Command> commands) { // Initially, await X idle soldiers and send them toward the enemy's starting location. // Once they're there and have no further orders, send them to attack any sighted enemy unit/structure. // Once we run out of those, send them to scout every resource deposit until we find more. var enemyStartLocation = gameState.MapData.Raw.StartLocations.OrderByDescending(point => hatchery.GetDistance(point)).First(); var idleSoldiers = soldiers.Where(s => s.Raw.Orders.Count == 0).ToList(); if (!soldiers.Any(s => s.GetDistance(enemyStartLocation) < 5f) || gameState.EnemyUnits.Any(e => e.GetDistance(enemyStartLocation) < 10f)) { if (idleSoldiers.Count >= AttackThreshold) { foreach (var soldier in idleSoldiers) { commands.Add(soldier.AttackMove(enemyStartLocation.X, enemyStartLocation.Y)); } } return; } if (gameState.EnemyUnits.Count > 0) { foreach (var soldier in idleSoldiers) { commands.Add(soldier.AttackMove(gameState.EnemyUnits[0].X, gameState.EnemyUnits[0].Y)); } return; } var unscoutedLocations = gameState.MapData.Deposits.Select(d => d.Center).ToList(); foreach (var location in unscoutedLocations) { if (soldiers.Any(s => s.GetDistance(location) < 5f || s.Raw.Orders.Any(o => o.TargetWorldSpacePos.GetDistance(location) < 5f))) { continue; } if (idleSoldiers.Count == 0) { break; } commands.Add(idleSoldiers[0].AttackMove(location)); idleSoldiers.RemoveAt(0); } }
public IReadOnlyList <Command> Act(GameState gameState) { var commands = new List <Command>(); if (sleep > 0) { sleep--; return(commands); } ZergBuilding hatchery = null; ZergBuilding pool = null; var workers = new List <ZergUnit>(); var lings = new List <ZergUnit>(); var idleLarva = new List <ZergUnit>(); foreach (var unit in gameState.Units) { if (unit is ZergBuilding zergBuilding) { if (zergBuilding.ZergBuildingType == ZergBuildingType.Hatchery || zergBuilding.ZergBuildingType == ZergBuildingType.Lair || zergBuilding.ZergBuildingType == ZergBuildingType.Hive) { if (zergBuilding.X == primaryHatcheryX || zergBuilding.Y == primaryHatcheryY) { hatchery = zergBuilding; } else { if (first) { hatchery = zergBuilding; primaryHatcheryX = hatchery.X; primaryHatcheryY = hatchery.Y; } // we proooobably don't care about secondary hatcheries, but if we did they'd go here. } } if (zergBuilding.ZergBuildingType == ZergBuildingType.SpawningPool) { pool = zergBuilding; } } else if (unit is ZergUnit zUnit) { if (zUnit.ZergUnitType == ZergUnitType.Drone) { workers.Add(zUnit); } else if (zUnit.ZergUnitType == ZergUnitType.Zergling) { lings.Add(zUnit); } if (zUnit.ZergUnitType == ZergUnitType.Larva) { idleLarva.Add(zUnit); } } } if (hatchery == null) { // Accept death as inevitable. return(new List <Command>()); // TODO: Surrender? } Deposit closestDeposit = gameState.MapData.Deposits.OrderBy(d => hatchery.GetDistance(d.Center)).First(); var mineralDeposits = closestDeposit.Resources.Where(u => u.IsMineralDeposit).ToList(); // First update, ignore the default worker orders, which are to mass on the center mineral deposit // (this ends up causing problems since we have to keep track of who is harvesting what ourselves) if (first) { foreach (var worker in workers) { worker.Raw.Orders.Clear(); } workersByMineralDeposit = mineralDeposits.ToDictionary(m => m.Raw.Tag, m => new List <ulong>()); } if (pool == null) { TryBuildPool(gameState, workers, commands); } if (idleLarva.Any()) { if (pool?.IsBuilt == true) { BuildAllLings(gameState, idleLarva, commands); } if (gameState.Observation.PlayerCommon.FoodCap - gameState.Observation.PlayerCommon.FoodUsed <= 2 && !gameState.Units.Any(u => u is ZergUnit zU && zU.ZergUnitType == ZergUnitType.Cocoon && zU.RawType.Armor >= 10)) // HACK: Cocoons *also* signify Baneling, Ravager, Lurker, Overseer, and Broodlord, so we check for high-armor Cocoons, because Larva create the highest armor Cocoons. // if it's stupid, but it works... still stupid and a little shameful. { BuildOverlord(gameState, idleLarva, commands); } // Could not find a larva timer in the SC2 API. if (idleLarva.Count >= 3) { BuildWorker(gameState, idleLarva, commands); } } // This bot isn't exactly aiming for the stars in terms of the tech tree, so we can get away with this. Revisit if you're shamelessly bastardizing this code. BuildHatchery(gameState, workers, closestDeposit, commands); // TODO: Vespene is important for Zerg. commands = commands.Take(1).ToList(); // If we tell a worker to build something, make sure we don't think he's harvesting if (commands.Count == 1) { sleep = 1; RemoveWorkerFromHarvestAssignments(commands[0].Unit); } // No matter what else happens, we can always attack, and we should always set idle workers to harvest minerals Attack(gameState, hatchery, lings, commands); SetIdleWorkerToHarvest(gameState, workers, mineralDeposits, commands); if (first) { first = false; // Make sure workers don't automatically harvest minerals, since we're managing assignments ourselves commands.Add(hatchery.RallyWorkers(hatchery.Raw.Pos.X, hatchery.Raw.Pos.Y)); } return(commands); }
public IReadOnlyList <Command> Act(GameState gameState) { var commands = new List <Command>(); if (sleep > 0) { sleep--; return(commands); } ZergBuilding hatchery = null; ZergBuilding pool = null; var workers = new List <ZergUnit>(); var lings = new List <ZergUnit>(); var idleLarva = new List <ZergUnit>(); var queens = new List <ZergUnit>(); var secondaryHatcheries = new List <ZergBuilding>(); foreach (var unit in gameState.Units) { if (unit is ZergBuilding zergBuilding) { if (zergBuilding.ZergBuildingType == ZergBuildingType.Hatchery || zergBuilding.ZergBuildingType == ZergBuildingType.Lair || zergBuilding.ZergBuildingType == ZergBuildingType.Hive) { if (zergBuilding.X == primaryHatcheryX || zergBuilding.Y == primaryHatcheryY) { hatchery = zergBuilding; } else { if (primaryHatcheryX == -1.0f && primaryHatcheryY == -1.0f) { hatchery = zergBuilding; primaryHatcheryX = hatchery.X; primaryHatcheryY = hatchery.Y; } secondaryHatcheries.Add(zergBuilding); } } if (zergBuilding.ZergBuildingType == ZergBuildingType.SpawningPool) { pool = zergBuilding; } } else if (unit is ZergUnit zUnit) { if (zUnit.ZergUnitType == ZergUnitType.Drone) { workers.Add(zUnit); } else if (zUnit.ZergUnitType == ZergUnitType.Zergling) { lings.Add(zUnit); } else if (zUnit.ZergUnitType == ZergUnitType.Larva) { idleLarva.Add(zUnit); } else if (zUnit.ZergUnitType == ZergUnitType.Queen) { queens.Add(zUnit); } } } if (hatchery == null) { // Accept death as inevitable. return(new List <Command>()); // TODO: Surrender? } var hatcheries = secondaryHatcheries.ToList(); hatcheries.Add(hatchery); if (idleLarva.Any()) { BuildOverlord(gameState, idleLarva, commands); } if (pool == null) { TryBuildPool(gameState, workers, commands); } if (pool?.IsBuilt == true) { if (idleLarva.Any()) { if (pool?.IsBuilt == true) { BuildAllLings(gameState, idleLarva, commands); } } if (hatcheries.Count() > queens.Count() && !gameState.Units.Any(u => u.IsBuilding(ZergUnitType.Queen))) { BuildQueen(gameState, hatchery, commands); } } // This bot isn't exactly aiming for the stars in terms of the tech tree, so we can get away with this. Revisit if you're shamelessly bastardizing this code. // only expand hatcheries if mineral production >> zergling production. Also only build one because we don't expand. if (gameState.Observation.PlayerCommon.Minerals >= 1500) { BuildHatchery(gameState, workers, commands); } // TODO: Vespene is important for Zerg. commands = commands.Take(1).ToList(); // If we tell a worker to build something, make sure we don't think he's harvesting if (commands.Count == 1) { sleep = 1; economyBot.RemoveWorkerFromHarvestAssignments(commands[0].Unit); } economyBot.AutoBuildWorkers = !(gameState.Observation.PlayerCommon.FoodCap - gameState.Observation.PlayerCommon.FoodUsed < 3); commands.AddRange(economyBot.Act(gameState)); return(commands); }
public static bool IsSpawningLarva(this ZergBuilding hatchery) { return(hatchery.HasBuff(BuffType.SpawnLarva)); }