diff --git a/game/event/event.py b/game/event/event.py index eb2e53b7..f94ab408 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -374,7 +374,11 @@ class UnitsDeliveryEvent(Event): def skip(self) -> None: for k, v in self.units.items(): - info = Information("Ally Reinforcement", str(k.id) + " x " + str(v) + " at " + self.to_cp.name, self.game.turn) - self.game.informations.append(info) + if self.to_cp.captured: + name = "Ally " + else: + name = "Enemy " + self.game.message( + f"{name} reinforcements: {k.id} x {v} at {self.to_cp.name}") self.to_cp.base.commision_units(self.units) diff --git a/game/game.py b/game/game.py index 82dd998a..55d12d81 100644 --- a/game/game.py +++ b/game/game.py @@ -91,9 +91,7 @@ class Game: self.__destroyed_units: List[str] = [] self.savepath = "" self.budget = PLAYER_BUDGET_INITIAL - # The enemy currently doesn't buy anything on turn zero; they get - # pre-populated airbases that are generated by the new game generator. - self.enemy_budget = 0 + self.enemy_budget = PLAYER_BUDGET_INITIAL self.current_unit_id = 0 self.current_group_id = 0 @@ -110,6 +108,8 @@ class Game: cp.pending_unit_deliveries = self.units_delivery_event(cp) self.sanitize_sides() + # Turn 0 procurement. + self.plan_procurement() self.on_load() def generate_conditions(self) -> Conditions: @@ -229,24 +229,8 @@ class Game: control_point.process_turn() self.process_enemy_income() - self.enemy_budget = ProcurementAi( - self, - for_player=False, - faction=self.enemy_faction, - manage_runways=True, - manage_front_line=True, - manage_aircraft=True - ).spend_budget(self.enemy_budget) self.process_player_income() - self.budget = ProcurementAi( - self, - for_player=True, - faction=self.player_faction, - manage_runways=self.settings.automate_runway_repair, - manage_front_line=self.settings.automate_front_line_reinforcements, - manage_aircraft=self.settings.automate_aircraft_reinforcements - ).spend_budget(self.budget) if not no_action and self.turn > 1: for cp in self.theater.player_points(): @@ -288,6 +272,27 @@ class Game: gplanner.plan_groundwar() self.ground_planners[cp.id] = gplanner + self.plan_procurement() + + def plan_procurement(self) -> None: + self.budget = ProcurementAi( + self, + for_player=True, + faction=self.player_faction, + manage_runways=self.settings.automate_runway_repair, + manage_front_line=self.settings.automate_front_line_reinforcements, + manage_aircraft=self.settings.automate_aircraft_reinforcements + ).spend_budget(self.budget) + + self.enemy_budget = ProcurementAi( + self, + for_player=False, + faction=self.enemy_faction, + manage_runways=True, + manage_front_line=True, + manage_aircraft=True + ).spend_budget(self.enemy_budget) + def message(self, text: str) -> None: self.informations.append(Information(text, turn=self.turn)) diff --git a/game/procurement.py b/game/procurement.py index 9be0dcbc..5685d4bd 100644 --- a/game/procurement.py +++ b/game/procurement.py @@ -86,8 +86,8 @@ class ProcurementAi: break budget -= db.PRICES[unit] - cp.base.armor[unit] = cp.base.armor.get(unit, 0) + 1 - self.reinforcement_message(unit, cp, group_size=1) + assert cp.pending_unit_deliveries is not None + cp.pending_unit_deliveries.deliver({unit: 1}) if cp.base.total_armor >= armor_limit: candidates.remove(cp) @@ -127,8 +127,8 @@ class ProcurementAi: break budget -= db.PRICES[unit] * group_size - cp.base.aircraft[unit] = cp.base.aircraft.get(unit, 0) + group_size - self.reinforcement_message(unit, cp, group_size) + assert cp.pending_unit_deliveries is not None + cp.pending_unit_deliveries.deliver({unit: group_size}) if cp.base.total_aircraft >= aircraft_limit: candidates.remove(cp) @@ -137,15 +137,6 @@ class ProcurementAi: return budget - def reinforcement_message(self, unit_type: Type[UnitType], - control_point: ControlPoint, - group_size: int) -> None: - description = f"{unit_type.id} x {group_size} at {control_point.name}" - if self.is_player: - self.game.message(f"Our reinforcements: {description}") - else: - self.game.message(f"OPFOR reinforcements: {description}") - @property def owned_points(self) -> List[ControlPoint]: if self.is_player: diff --git a/game/theater/start_generator.py b/game/theater/start_generator.py index 110d6b5b..49f587cc 100644 --- a/game/theater/start_generator.py +++ b/game/theater/start_generator.py @@ -91,7 +91,6 @@ class GameGenerator: # Reset name generator namegen.reset() self.prepare_theater() - self.populate_red_airbases() game = Game(player_name=self.player, enemy_name=self.enemy, theater=self.theater, @@ -134,51 +133,6 @@ class GameGenerator: else: cp.captured = True - def populate_red_airbases(self) -> None: - for control_point in self.theater.enemy_points(): - if control_point.captured: - continue - self.populate_red_airbase(control_point) - - def populate_red_airbase(self, control_point: ControlPoint) -> None: - # Force reset cp on generation - control_point.base.aircraft = {} - control_point.base.armor = {} - control_point.base.aa = {} - control_point.base.commision_points = {} - control_point.base.strength = 1 - - # The tasks here are confusing. PinpointStrike for some reason means - # ground units. - for task in [PinpointStrike, CAP, CAS, AirDefence]: - if isinstance(control_point, OffMapSpawn): - # Off-map spawn locations start with no aircraft. - continue - - if IMPORTANCE_HIGH <= control_point.importance <= IMPORTANCE_LOW: - raise ValueError( - f"CP importance must be between {IMPORTANCE_LOW} and " - f"{IMPORTANCE_HIGH}, is {control_point.importance}") - - importance_factor = ((control_point.importance - IMPORTANCE_LOW) / - (IMPORTANCE_HIGH - IMPORTANCE_LOW)) - # noinspection PyTypeChecker - unit_types = db.choose_units(task, importance_factor, UNIT_VARIETY, - self.enemy) - if not unit_types: - continue - - count_log = math.log(control_point.importance + 0.01, - UNIT_COUNT_IMPORTANCE_LOG) - count = max((COUNT_BY_TASK[task] * - self.generator_settings.multiplier * - (count_log + 1)), - 1) - - count_per_type = max(int(float(count) / len(unit_types)), 1) - for unit_type in unit_types: - control_point.base.commision_units({unit_type: count_per_type}) - class LocationFinder: def __init__(self, game: Game, control_point: ControlPoint) -> None: