private bool ProduceAddOn(ProductionOrder order) { var Structure2x2 = unitTypeRepository.Get(BlizzardConstants.Unit.SupplyDepot); // Use as add-on substitute, as add-ons have a size of 8! var ids = techTree.GetProducersID(order.Unit); var targets = intelManager.StructuresSelf(ids).Where(b => b.AddOnTag == 0 && b.BuildProgress == 1f && b.Orders.Count == 0); var target = targets.FirstOrDefault(b => intelManager.GameMap.ValidPlacement(Structure2x2, new Point2D { X = b.Pos.X + 2.5f, Y = b.Pos.Y - 0.5f })); if (target == null && targets.Count() != 0) { return(LiftOff(order, targets.First())); } if (target == null || !ReserveRessource(order.Unit, false)) { return(false); } order.Status = ProductionOrder.OrderStatus.Commissioned; order.AssignedUnit = target; rawManager.QueueActions(RawCommand(order.Unit.AbilityId, order.AssignedUnit.Tag)); target.Orders.Add(new UnitOrder { }); return(true); }
private void QueueOrderInFront(ProductionOrder order) { #if DEBUG if (order.Unit != null && order.Unit.Race != GameConstants.ParticipantRace) { log.LogError($"ProductionManager: {order.Unit.Name} is a {order.Unit.Race} unit, playing as {GameConstants.ParticipantRace}!"); return; } #else if (order.Unit != null && order.Unit.Race != GameConstants.ParticipantRace) { return; } #endif var requirements = new List <ProductionOrder>(); AddRequirementsToList(requirements, order, order.LowPriority); lock (_orders) { for (int i = 0; i < requirements.Count; i++) { if (GetOrderOfType(_orders, requirements[i], out var moved)) { #if DEBUG log.LogWarning($"\t(Important {order.Unit?.Name}{order.Research?.Name}) => Prioritized {moved.Unit?.Name}{order.Research?.Name} from existing queue."); #endif _orders.Remove(moved); requirements[i] = moved; } } var copy = _orders.ToList(); // Clone _orders.Clear(); requirements.ForEach(r => _orders.Add(r)); _orders.Add(order); copy.ForEach(c => _orders.Add(c)); } }
private bool HasRequirements(ProductionOrder order) { if (order.RequiredAddOn != 0 && !techTree.HasUnit(order.RequiredAddOn)) { return(false); } if (order.Unit != null && !techTree.HasProducer(order.Unit)) { return(false); } if (order.Research != null && !techTree.HasProducer(order.Research)) { return(false); } var requiredBuildings = order.Unit == null ? new[] { techTree.GetProducer(order.Research) } : techTree.GetRequiredBuildings(order.Unit); if (requiredBuildings.Any() && !requiredBuildings.Any(b => techTree.HasUnit(b))) { return(false); } var requiredResearch = order.Research == null ? null : techTree.GetRequiredResearch(order.Research); if (requiredResearch != null && !techTree.HasResearch(requiredResearch)) { return(false); } return(true); }
private bool ProducedMorphed(ProductionOrder order) { IUnit target = null; var ids = techTree.GetProducersID(order.Unit); if (IsStructure(ids.First())) { target = intelManager.StructuresSelf(ids).FirstOrDefault(u => u.Orders.Count == 0); } else { target = intelManager.UnitsSelf(ids).FirstOrDefault(u => u.Orders.Count == 0); } if (target == null || !ReserveRessource(order.Unit, false)) { return(false); } ; target.Orders.Add(new UnitOrder { }); if (target.UnitType == BlizzardConstants.Unit.Larva) { order.Status = ProductionOrder.OrderStatus.Commissioned; } else { order.Status = ProductionOrder.OrderStatus.Producing; order.OrderedUnit = target; } order.AssignedUnit = target; rawManager.QueueActions(RawCommand(order.Unit.AbilityId, order.AssignedUnit.Tag)); return(true); }
private bool ProduceBuilding(ProductionOrder order) { IPosition targetPosition; if (order.Position != null && intelManager.GameMap.ValidPlacement(order.Unit, order.Position, order.Spacing)) { targetPosition = order; } else { targetPosition = intelManager.GameMap.FindPlacement(order.Unit, order.Position ?? intelManager.PrimaryColony.Point, order.Spacing); } var worker = GetWorker(targetPosition); if (worker == null || targetPosition == null) { return(false); } if (!ReserveRessource(order.Unit)) { return(false); } order.Status = ProductionOrder.OrderStatus.Commissioned; order.AssignedUnit = worker; intelManager.GameMap.Reserve(order.Unit, targetPosition.Point); rawManager.QueueActions(RawCommand(order.Unit.AbilityId, worker.Tag, targetPosition.Point)); return(true); }
private bool ProduceVespene(ProductionOrder order) { var colony = order.Position == null ? intelManager.PrimaryColony : order.Position.GetClosest(intelManager.Colonies); var refineries = colony.Structures.Where(b => GameConstants.IsVespeneGeyserBuilding(b.UnitType)); var target = colony.Vespene.FirstOrDefault(v => !refineries.Any(r => r.Pos.X == v.Pos.X && r.Pos.Y == v.Pos.Y)); var worker = GetWorker(target); #if DEBUG if (target == null) { log.LogError($"ProductionManager: No available vespene geyser for {order.Unit.Name} at colony {colony.Id}"); return(false); } if (worker == null) { log.LogWarning($"ProductionManager: No worker found for {order.Unit.Name}"); return(false); } if (!ReserveRessource(order.Unit)) { return(false); } #else if (target == null || worker == null || !ReserveRessource(order.Unit)) { return(false); } #endif order.Status = ProductionOrder.OrderStatus.Commissioned; order.AssignedUnit = worker; rawManager.QueueActions(RawCommand(order.Unit.AbilityId, worker.Tag, target.Tag)); return(true); }
private bool GetOrderOfType(List <ProductionOrder> orders, ProductionOrder order, out ProductionOrder moved) { if (order.Type == ProductionOrder.BuildType.Research) { moved = orders.Where(o => o.Research?.UpgradeId == order.Research.UpgradeId).FirstOrDefault(); } else { moved = orders.Where(o => o.Unit?.UnitId == order.Unit.UnitId).FirstOrDefault(); } return(moved != null); }
private bool ResearchUpgrade(ProductionOrder order) { IUnit target = intelManager.StructuresSelf(techTree.GetProducer(order.Research).UnitId).FirstOrDefault(b => b.BuildProgress == 1f && b.Orders.Count == 0); if (target == null || !ReserveRessource(order.Research)) { return(false); } order.Status = ProductionOrder.OrderStatus.Built; //TODO: Not built... producing rawManager.QueueActions(RawCommand(order.Research.AbilityId, target.Tag)); return(true); }
private void QueueOrder(ProductionOrder order) { #if DEBUG if (order.Unit != null && order.Unit.Race != GameConstants.ParticipantRace) { log.LogError($"ProductionManager: {order.Unit.Name} is a {order.Unit.Race} unit, playing as {GameConstants.ParticipantRace}!"); return; } #else if (order.Unit != null && order.Unit.Race != GameConstants.ParticipantRace) { return; } #endif lock (_orders) { AddRequirementsToList(_orders, order, order.LowPriority); _orders.Add(order); } }
private bool CanAfford(ProductionOrder order) { if (order.Unit?.FoodRequired != 0 && order.Unit?.FoodRequired > currentRessources.Supply) { return(false); } var minerals = order.Unit == null ? order.Research.MineralCost : order.Unit.MineralCost; if (minerals != 0 && minerals > currentRessources.Minerals) { return(false); } var vespene = order.Unit == null ? order.Research.VespeneCost : order.Unit.VespeneCost; if (vespene != 0 && vespene > currentRessources.Vespene) { return(false); } return(true); }
private bool Produce(ProductionOrder order) { if (!CanAfford(order)) { return(false); } if (!HasRequirements(order)) { return(false); } switch (order.Type) { case ProductionOrder.BuildType.Structure: if (order.Unit.UnitId == GameConstants.RaceRefinery) { return(ProduceVespene(order)); } else { return(ProduceBuilding(order)); } case ProductionOrder.BuildType.Unit: return(ProduceUnit(order)); case ProductionOrder.BuildType.Morphed: return(ProducedMorphed(order)); case ProductionOrder.BuildType.AddOn: return(ProduceAddOn(order)); case ProductionOrder.BuildType.Research: return(ResearchUpgrade(order)); default: throw new System.NotImplementedException(); } }
private bool LiftOff(ProductionOrder order, IUnit target) { var position = intelManager.GameMap.FindPlacementWithAddOn(target.Point); if (position == null || !ReserveRessource(order.Unit, false)) { return(false); } #if DEBUG log.LogWarning($"ProductionManager: Relocating {target.Tag} to X:{position.Point.X} Y:{position.Point.Y} ({order.Unit.Name})"); #endif order.Status = ProductionOrder.OrderStatus.Commissioned; order.AssignedUnit = target; var Structure2x2 = unitTypeRepository.Get(BlizzardConstants.Unit.SupplyDepot); // Use as add-on substitute, as add-ons have a size of 8! intelManager.GameMap.Reserve(order.Unit, position.Point); intelManager.GameMap.Reserve(Structure2x2, new Point2D { X = position.Point.X + 2.5f, Y = position.Point.Y - 0.5f }); rawManager.QueueActions(RawCommand(order.Unit.AbilityId, order.AssignedUnit.Tag, position.Point)); target.Orders.Add(new UnitOrder { }); return(true); }
private bool ProduceUnit(ProductionOrder order) { var ids = techTree.GetProducersID(order.Unit); IUnit producer = null; if (GameConstants.RequiresTechLab(order.Unit.UnitId)) { producer = intelManager.StructuresSelf(ids).FirstOrDefault(b => b.AddOnTag != 0 && b.Orders.Count == 0 && GameConstants.IsTechLab(GetBuilding(b.AddOnTag).UnitType)); } else { producer = intelManager.StructuresSelf(ids).FirstOrDefault(b => b.BuildProgress == 1f && ((b.Orders.Count == 0) || (b.AddOnTag != 0 && GameConstants.IsReactor(GetBuilding(b.AddOnTag).UnitType) && b.Orders.Count < 2 && !GameConstants.IsReactorAbility(b.Orders.First().AbilityId)))); } if (producer == null || !ReserveRessource(order.Unit, false)) { return(false); } producer.Orders.Add(new UnitOrder()); // Fake order to prevent adding multiple units in same game loop order.Status = ProductionOrder.OrderStatus.Commissioned; rawManager.QueueActions(RawCommand(order.Unit.AbilityId, producer.Tag)); return(true); }
private List <ProductionOrder> AddRequirementsToList(List <ProductionOrder> queue, ProductionOrder order, bool canSkip) { var requiredUnits = new List <UnitTypeData>(); var requiredTech = new List <UpgradeData>(); if (order.Type == ProductionOrder.BuildType.Research) { var tech = techTree.GetRequiredResearch(order.Research); if (tech != null && !techTree.HasResearch(tech) && !IsQueued(queue, tech)) { requiredTech.Add(tech); } var unit = techTree.GetProducer(order.Research); if (unit != null && !techTree.HasUnit(unit) && !IsQueued(queue, unit)) { requiredUnits.Add(unit); } unit = techTree.GetRequiredBuilding(order.Research); if (unit != null && !techTree.HasUnit(unit) && !IsQueued(queue, unit)) { requiredUnits.Add(unit); } } else { var units = techTree.GetProducers(order.Unit); if (units.Any() && !units.Any(unit => techTree.HasUnit(unit) || IsQueued(queue, unit))) { requiredUnits.Add(units.First()); } units = techTree.GetRequiredBuildings(order.Unit); if (units.Any() && !units.Any(unit => techTree.HasUnit(unit) || IsQueued(queue, unit))) { requiredUnits.Add(units.First()); } if (order.RequiredAddOn != 0 && !(techTree.HasUnit(order.RequiredAddOn) || IsUnitQueued(queue, order.RequiredAddOn))) { requiredUnits.Add(unitTypeRepository.Get(order.RequiredAddOn)); } } if (requiredUnits.Count == 0 && requiredTech.Count == 0) { return(queue); } #if DEBUG log.LogWarning($"ProductionManager: The queued {order.Unit?.Name}{order.Research?.Name} have unmet requirements - adding them to queue:"); #endif requiredUnits.ForEach(u => { #if DEBUG log.LogWarning($"\t{order.Unit?.Name}{order.Research?.Name} => {u.Name} (Structure/Unit)"); #endif QueueRequirementsUnit(queue, u, canSkip, "\t\t"); }); requiredTech.ForEach(t => { #if DEBUG log.LogWarning($"\t{order.Unit?.Name}{order.Research?.Name} => {t.Name} (Research)"); #endif QueueRequirementsTechnology(queue, t, canSkip, "\t\t"); }); return(queue); }