mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Add option to limit squadron sizes and begin full.
Adding temporarily as an option to make sure it's not a terrible idea, but the old mode will probably go away. Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1583. Fixes https://github.com/dcs-liberation/dcs_liberation/issues/2808.
This commit is contained in:
parent
7f94b34277
commit
15fa73a514
@ -6,6 +6,7 @@ Saves from 6.x are not compatible with 7.0.
|
|||||||
|
|
||||||
* **[Engine]** Support for DCS 2.8.3.37556.
|
* **[Engine]** Support for DCS 2.8.3.37556.
|
||||||
* **[Engine]** Saved games are now a zip file of save assets for easier bug reporting. The new extension is .liberation.zip. Drag and drop that file into bug reports.
|
* **[Engine]** Saved games are now a zip file of save assets for easier bug reporting. The new extension is .liberation.zip. Drag and drop that file into bug reports.
|
||||||
|
* **[Campaign]** Added options to limit squadron sizes and to begin all squadrons at maximum strength. Maximum squadron size is defined during air wing configuration with default values provided by the campaign.
|
||||||
* **[Campaign AI]** Added an option to instruct the campaign AI to prefer fulfilling missions with squadrons which have a matching primary task. Previously distance from target held a stronger influence than task preference. Primary tasks for squadrons are set by campaign designers but are user-configurable.
|
* **[Campaign AI]** Added an option to instruct the campaign AI to prefer fulfilling missions with squadrons which have a matching primary task. Previously distance from target held a stronger influence than task preference. Primary tasks for squadrons are set by campaign designers but are user-configurable.
|
||||||
* **[Flight Planning]** Package TOT and composition can be modified after advancing time in Liberation.
|
* **[Flight Planning]** Package TOT and composition can be modified after advancing time in Liberation.
|
||||||
* **[Mission Generation]** Units on the front line are now hidden on MFDs.
|
* **[Mission Generation]** Units on the front line are now hidden on MFDs.
|
||||||
|
|||||||
@ -11,11 +11,15 @@ if TYPE_CHECKING:
|
|||||||
from game.theater import ConflictTheater
|
from game.theater import ConflictTheater
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_SQUADRON_SIZE = 12
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class SquadronConfig:
|
class SquadronConfig:
|
||||||
primary: FlightType
|
primary: FlightType
|
||||||
secondary: list[FlightType]
|
secondary: list[FlightType]
|
||||||
aircraft: list[str]
|
aircraft: list[str]
|
||||||
|
max_size: int
|
||||||
|
|
||||||
name: Optional[str]
|
name: Optional[str]
|
||||||
nickname: Optional[str]
|
nickname: Optional[str]
|
||||||
@ -39,6 +43,7 @@ class SquadronConfig:
|
|||||||
FlightType(data["primary"]),
|
FlightType(data["primary"]),
|
||||||
secondary,
|
secondary,
|
||||||
data.get("aircraft", []),
|
data.get("aircraft", []),
|
||||||
|
data.get("size", DEFAULT_SQUADRON_SIZE),
|
||||||
data.get("name", None),
|
data.get("name", None),
|
||||||
data.get("nickname", None),
|
data.get("nickname", None),
|
||||||
data.get("female_pilot_percentage", None),
|
data.get("female_pilot_percentage", None),
|
||||||
|
|||||||
@ -45,6 +45,7 @@ class DefaultSquadronAssigner:
|
|||||||
squadron = Squadron.create_from(
|
squadron = Squadron.create_from(
|
||||||
squadron_def,
|
squadron_def,
|
||||||
squadron_config.primary,
|
squadron_config.primary,
|
||||||
|
squadron_config.max_size,
|
||||||
control_point,
|
control_point,
|
||||||
self.coalition,
|
self.coalition,
|
||||||
self.game,
|
self.game,
|
||||||
|
|||||||
@ -158,14 +158,14 @@ class Coalition:
|
|||||||
# is handled correctly.
|
# is handled correctly.
|
||||||
self.transfers.perform_transfers()
|
self.transfers.perform_transfers()
|
||||||
|
|
||||||
def preinit_turn_0(self) -> None:
|
def preinit_turn_0(self, squadrons_start_full: bool) -> None:
|
||||||
"""Runs final Coalition initialization.
|
"""Runs final Coalition initialization.
|
||||||
|
|
||||||
Final initialization occurs before Game.initialize_turn runs for turn 0.
|
Final initialization occurs before Game.initialize_turn runs for turn 0.
|
||||||
"""
|
"""
|
||||||
self.air_wing.populate_for_turn_0()
|
self.air_wing.populate_for_turn_0(squadrons_start_full)
|
||||||
|
|
||||||
def initialize_turn(self) -> None:
|
def initialize_turn(self, is_turn_0: bool) -> None:
|
||||||
"""Processes coalition-specific turn initialization.
|
"""Processes coalition-specific turn initialization.
|
||||||
|
|
||||||
For more information on turn initialization in general, see the documentation
|
For more information on turn initialization in general, see the documentation
|
||||||
@ -184,7 +184,8 @@ class Coalition:
|
|||||||
with logged_duration("Transport planning"):
|
with logged_duration("Transport planning"):
|
||||||
self.transfers.plan_transports(self.game.conditions.start_time)
|
self.transfers.plan_transports(self.game.conditions.start_time)
|
||||||
|
|
||||||
self.plan_missions(self.game.conditions.start_time)
|
if not is_turn_0 or not self.game.settings.enable_squadron_aircraft_limits:
|
||||||
|
self.plan_missions(self.game.conditions.start_time)
|
||||||
self.plan_procurement()
|
self.plan_procurement()
|
||||||
|
|
||||||
def refund_outstanding_orders(self) -> None:
|
def refund_outstanding_orders(self) -> None:
|
||||||
|
|||||||
16
game/game.py
16
game/game.py
@ -296,7 +296,7 @@ class Game:
|
|||||||
if self.turn > 1:
|
if self.turn > 1:
|
||||||
self.conditions = self.generate_conditions()
|
self.conditions = self.generate_conditions()
|
||||||
|
|
||||||
def begin_turn_0(self) -> None:
|
def begin_turn_0(self, squadrons_start_full: bool) -> None:
|
||||||
"""Initialization for the first turn of the game."""
|
"""Initialization for the first turn of the game."""
|
||||||
from .sim import GameUpdateEvents
|
from .sim import GameUpdateEvents
|
||||||
|
|
||||||
@ -321,8 +321,9 @@ class Game:
|
|||||||
# Rotate the whole TGO with the new heading
|
# Rotate the whole TGO with the new heading
|
||||||
tgo.rotate(heading or tgo.heading)
|
tgo.rotate(heading or tgo.heading)
|
||||||
|
|
||||||
self.blue.preinit_turn_0()
|
self.blue.preinit_turn_0(squadrons_start_full)
|
||||||
self.red.preinit_turn_0()
|
self.red.preinit_turn_0(squadrons_start_full)
|
||||||
|
# TODO: Check for overfull bases.
|
||||||
# We don't need to actually stream events for turn zero because we haven't given
|
# We don't need to actually stream events for turn zero because we haven't given
|
||||||
# *any* state to the UI yet, so it will need to do a full draw once we do.
|
# *any* state to the UI yet, so it will need to do a full draw once we do.
|
||||||
self.initialize_turn(GameUpdateEvents())
|
self.initialize_turn(GameUpdateEvents())
|
||||||
@ -381,7 +382,10 @@ class Game:
|
|||||||
self.red.bullseye = Bullseye(player_cp.position)
|
self.red.bullseye = Bullseye(player_cp.position)
|
||||||
|
|
||||||
def initialize_turn(
|
def initialize_turn(
|
||||||
self, events: GameUpdateEvents, for_red: bool = True, for_blue: bool = True
|
self,
|
||||||
|
events: GameUpdateEvents,
|
||||||
|
for_red: bool = True,
|
||||||
|
for_blue: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Performs turn initialization for the specified players.
|
"""Performs turn initialization for the specified players.
|
||||||
|
|
||||||
@ -433,9 +437,9 @@ class Game:
|
|||||||
|
|
||||||
# Plan Coalition specific turn
|
# Plan Coalition specific turn
|
||||||
if for_blue:
|
if for_blue:
|
||||||
self.blue.initialize_turn()
|
self.blue.initialize_turn(self.turn == 0)
|
||||||
if for_red:
|
if for_red:
|
||||||
self.red.initialize_turn()
|
self.red.initialize_turn(self.turn == 0)
|
||||||
|
|
||||||
# Update cull zones
|
# Update cull zones
|
||||||
with logged_duration("Computing culling positions"):
|
with logged_duration("Computing culling positions"):
|
||||||
|
|||||||
@ -235,6 +235,8 @@ class ProcurementAi:
|
|||||||
):
|
):
|
||||||
if not squadron.can_provide_pilots(request.number):
|
if not squadron.can_provide_pilots(request.number):
|
||||||
continue
|
continue
|
||||||
|
if not squadron.has_aircraft_capacity_for(request.number):
|
||||||
|
continue
|
||||||
if squadron.location.unclaimed_parking() < request.number:
|
if squadron.location.unclaimed_parking() < request.number:
|
||||||
continue
|
continue
|
||||||
if self.threat_zones.threatened(squadron.location.position):
|
if self.threat_zones.threatened(squadron.location.position):
|
||||||
|
|||||||
@ -109,7 +109,11 @@ class AircraftPurchaseAdapter(PurchaseAdapter[Squadron]):
|
|||||||
return item.owned_aircraft
|
return item.owned_aircraft
|
||||||
|
|
||||||
def can_buy(self, item: Squadron) -> bool:
|
def can_buy(self, item: Squadron) -> bool:
|
||||||
return super().can_buy(item) and self.control_point.unclaimed_parking() > 0
|
return (
|
||||||
|
super().can_buy(item)
|
||||||
|
and self.control_point.unclaimed_parking() > 0
|
||||||
|
and item.has_aircraft_capacity_for(1)
|
||||||
|
)
|
||||||
|
|
||||||
def can_sell(self, item: Squadron) -> bool:
|
def can_sell(self, item: Squadron) -> bool:
|
||||||
return item.untasked_aircraft > 0
|
return item.untasked_aircraft > 0
|
||||||
|
|||||||
@ -264,6 +264,15 @@ class Settings:
|
|||||||
"this many pilots each turn up to the limit."
|
"this many pilots each turn up to the limit."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
# Feature flag for squadron limits.
|
||||||
|
enable_squadron_aircraft_limits: bool = boolean_option(
|
||||||
|
"Enable per-squadron aircraft limits",
|
||||||
|
CAMPAIGN_MANAGEMENT_PAGE,
|
||||||
|
PILOTS_AND_SQUADRONS_SECTION,
|
||||||
|
default=False,
|
||||||
|
remember_player_choice=True,
|
||||||
|
detail="If set, squadrons will be limited to a maximum number of aircraft.",
|
||||||
|
)
|
||||||
|
|
||||||
# HQ Automation
|
# HQ Automation
|
||||||
automate_runway_repair: bool = boolean_option(
|
automate_runway_repair: bool = boolean_option(
|
||||||
|
|||||||
@ -125,9 +125,9 @@ class AirWing:
|
|||||||
def squadron_at_index(self, index: int) -> Squadron:
|
def squadron_at_index(self, index: int) -> Squadron:
|
||||||
return list(self.iter_squadrons())[index]
|
return list(self.iter_squadrons())[index]
|
||||||
|
|
||||||
def populate_for_turn_0(self) -> None:
|
def populate_for_turn_0(self, squadrons_start_full: bool) -> None:
|
||||||
for squadron in self.iter_squadrons():
|
for squadron in self.iter_squadrons():
|
||||||
squadron.populate_for_turn_0()
|
squadron.populate_for_turn_0(squadrons_start_full)
|
||||||
|
|
||||||
def end_turn(self) -> None:
|
def end_turn(self) -> None:
|
||||||
for squadron in self.iter_squadrons():
|
for squadron in self.iter_squadrons():
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class Squadron:
|
|||||||
country: str
|
country: str
|
||||||
role: str
|
role: str
|
||||||
aircraft: AircraftType
|
aircraft: AircraftType
|
||||||
|
max_size: int
|
||||||
livery: Optional[str]
|
livery: Optional[str]
|
||||||
primary_task: FlightType
|
primary_task: FlightType
|
||||||
auto_assignable_mission_types: set[FlightType]
|
auto_assignable_mission_types: set[FlightType]
|
||||||
@ -161,10 +162,12 @@ class Squadron:
|
|||||||
self.current_roster.extend(new_pilots)
|
self.current_roster.extend(new_pilots)
|
||||||
self.available_pilots.extend(new_pilots)
|
self.available_pilots.extend(new_pilots)
|
||||||
|
|
||||||
def populate_for_turn_0(self) -> None:
|
def populate_for_turn_0(self, squadrons_start_full: bool) -> None:
|
||||||
if any(p.status is not PilotStatus.Active for p in self.pilot_pool):
|
if any(p.status is not PilotStatus.Active for p in self.pilot_pool):
|
||||||
raise ValueError("Squadrons can only be created with active pilots.")
|
raise ValueError("Squadrons can only be created with active pilots.")
|
||||||
self._recruit_pilots(self.settings.squadron_pilot_limit)
|
self._recruit_pilots(self.settings.squadron_pilot_limit)
|
||||||
|
if squadrons_start_full:
|
||||||
|
self.owned_aircraft = self.max_size
|
||||||
|
|
||||||
def end_turn(self) -> None:
|
def end_turn(self) -> None:
|
||||||
if self.destination is not None:
|
if self.destination is not None:
|
||||||
@ -202,7 +205,7 @@ class Squadron:
|
|||||||
return [p for p in self.current_roster if p.status != status]
|
return [p for p in self.current_roster if p.status != status]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_size(self) -> int:
|
def pilot_limit(self) -> int:
|
||||||
return self.settings.squadron_pilot_limit
|
return self.settings.squadron_pilot_limit
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -230,7 +233,7 @@ class Squadron:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def _number_of_unfilled_pilot_slots(self) -> int:
|
def _number_of_unfilled_pilot_slots(self) -> int:
|
||||||
return self.max_size - len(self.active_pilots)
|
return self.pilot_limit - len(self.active_pilots)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def number_of_available_pilots(self) -> int:
|
def number_of_available_pilots(self) -> int:
|
||||||
@ -334,6 +337,12 @@ class Squadron:
|
|||||||
def expected_size_next_turn(self) -> int:
|
def expected_size_next_turn(self) -> int:
|
||||||
return self.owned_aircraft + self.pending_deliveries
|
return self.owned_aircraft + self.pending_deliveries
|
||||||
|
|
||||||
|
def has_aircraft_capacity_for(self, n: int) -> bool:
|
||||||
|
if not self.settings.enable_squadron_aircraft_limits:
|
||||||
|
return True
|
||||||
|
remaining = self.max_size - self.owned_aircraft - self.pending_deliveries
|
||||||
|
return remaining >= n
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def arrival(self) -> ControlPoint:
|
def arrival(self) -> ControlPoint:
|
||||||
return self.location if self.destination is None else self.destination
|
return self.location if self.destination is None else self.destination
|
||||||
@ -424,6 +433,7 @@ class Squadron:
|
|||||||
cls,
|
cls,
|
||||||
squadron_def: SquadronDef,
|
squadron_def: SquadronDef,
|
||||||
primary_task: FlightType,
|
primary_task: FlightType,
|
||||||
|
max_size: int,
|
||||||
base: ControlPoint,
|
base: ControlPoint,
|
||||||
coalition: Coalition,
|
coalition: Coalition,
|
||||||
game: Game,
|
game: Game,
|
||||||
@ -435,6 +445,7 @@ class Squadron:
|
|||||||
squadron_def.country,
|
squadron_def.country,
|
||||||
squadron_def.role,
|
squadron_def.role,
|
||||||
squadron_def.aircraft,
|
squadron_def.aircraft,
|
||||||
|
max_size,
|
||||||
squadron_def.livery,
|
squadron_def.livery,
|
||||||
primary_task,
|
primary_task,
|
||||||
squadron_def.auto_assignable_mission_types,
|
squadron_def.auto_assignable_mission_types,
|
||||||
|
|||||||
@ -172,4 +172,7 @@ VERSION = _build_version_string()
|
|||||||
#:
|
#:
|
||||||
#: Version 10.6
|
#: Version 10.6
|
||||||
#: * Support in-line definitions of campaign-specific factions.
|
#: * Support in-line definitions of campaign-specific factions.
|
||||||
CAMPAIGN_FORMAT_VERSION = (10, 6)
|
#:
|
||||||
|
#: Version 10.7
|
||||||
|
#: * Support for defining squadron sizes.
|
||||||
|
CAMPAIGN_FORMAT_VERSION = (10, 7)
|
||||||
|
|||||||
@ -221,6 +221,15 @@ def parse_args() -> argparse.Namespace:
|
|||||||
"--auto-procurement", action="store_true", help="Automate bluefor procurement."
|
"--auto-procurement", action="store_true", help="Automate bluefor procurement."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
new_game.add_argument(
|
||||||
|
"--use-new-squadron-rules",
|
||||||
|
action="store_true",
|
||||||
|
help=(
|
||||||
|
"Limit the number of aircraft per squadron and begin the campaign with "
|
||||||
|
"them at full strength."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
new_game.add_argument(
|
new_game.add_argument(
|
||||||
"--inverted", action="store_true", help="Invert the campaign."
|
"--inverted", action="store_true", help="Invert the campaign."
|
||||||
)
|
)
|
||||||
@ -263,6 +272,7 @@ def create_game(
|
|||||||
start_date: datetime,
|
start_date: datetime,
|
||||||
restrict_weapons_by_date: bool,
|
restrict_weapons_by_date: bool,
|
||||||
advanced_iads: bool,
|
advanced_iads: bool,
|
||||||
|
use_new_squadron_rules: bool,
|
||||||
) -> Game:
|
) -> Game:
|
||||||
first_start = liberation_install.init()
|
first_start = liberation_install.init()
|
||||||
if first_start:
|
if first_start:
|
||||||
@ -297,6 +307,7 @@ def create_game(
|
|||||||
enable_frontline_cheats=cheats,
|
enable_frontline_cheats=cheats,
|
||||||
enable_base_capture_cheat=cheats,
|
enable_base_capture_cheat=cheats,
|
||||||
restrict_weapons_by_date=restrict_weapons_by_date,
|
restrict_weapons_by_date=restrict_weapons_by_date,
|
||||||
|
enable_squadron_aircraft_limits=use_new_squadron_rules,
|
||||||
),
|
),
|
||||||
GeneratorSettings(
|
GeneratorSettings(
|
||||||
start_date=start_date,
|
start_date=start_date,
|
||||||
@ -323,7 +334,7 @@ def create_game(
|
|||||||
lua_plugin_manager,
|
lua_plugin_manager,
|
||||||
)
|
)
|
||||||
game = generator.generate()
|
game = generator.generate()
|
||||||
game.begin_turn_0()
|
game.begin_turn_0(squadrons_start_full=use_new_squadron_rules)
|
||||||
return game
|
return game
|
||||||
|
|
||||||
|
|
||||||
@ -417,6 +428,7 @@ def main():
|
|||||||
args.date,
|
args.date,
|
||||||
args.restrict_weapons_by_date,
|
args.restrict_weapons_by_date,
|
||||||
args.advanced_iads,
|
args.advanced_iads,
|
||||||
|
args.use_new_squadron_rules,
|
||||||
)
|
)
|
||||||
if args.subcommand == "lint-weapons":
|
if args.subcommand == "lint-weapons":
|
||||||
lint_weapon_data_for_aircraft(AircraftType.named(args.aircraft))
|
lint_weapon_data_for_aircraft(AircraftType.named(args.aircraft))
|
||||||
|
|||||||
@ -27,10 +27,12 @@ from PySide6.QtWidgets import (
|
|||||||
QToolButton,
|
QToolButton,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
QWidget,
|
QWidget,
|
||||||
|
QSpinBox,
|
||||||
)
|
)
|
||||||
|
|
||||||
from game import Game
|
from game import Game
|
||||||
from game.ato.flighttype import FlightType
|
from game.ato.flighttype import FlightType
|
||||||
|
from game.campaignloader.campaignairwingconfig import DEFAULT_SQUADRON_SIZE
|
||||||
from game.coalition import Coalition
|
from game.coalition import Coalition
|
||||||
from game.dcs.aircrafttype import AircraftType
|
from game.dcs.aircrafttype import AircraftType
|
||||||
from game.squadrons import AirWing, Pilot, Squadron
|
from game.squadrons import AirWing, Pilot, Squadron
|
||||||
@ -127,6 +129,26 @@ class SquadronBaseSelector(QComboBox):
|
|||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
|
||||||
|
class SquadronSizeSpinner(QSpinBox):
|
||||||
|
def __init__(self, starting_size: int, parent: QWidget | None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
# Disable text editing, which wouldn't work in the first place, but also
|
||||||
|
# obnoxiously selects the text on change (highlighting it) and leaves a flashing
|
||||||
|
# cursor in the middle of the element when clicked.
|
||||||
|
self.lineEdit().setEnabled(False)
|
||||||
|
|
||||||
|
self.setMinimum(1)
|
||||||
|
self.setValue(starting_size)
|
||||||
|
|
||||||
|
# def sizeHint(self) -> QSize:
|
||||||
|
# # The default size hinting fails to deal with label width, and will truncate
|
||||||
|
# # "Paused".
|
||||||
|
# size = super().sizeHint()
|
||||||
|
# size.setWidth(86)
|
||||||
|
# return size
|
||||||
|
|
||||||
|
|
||||||
class SquadronConfigurationBox(QGroupBox):
|
class SquadronConfigurationBox(QGroupBox):
|
||||||
remove_squadron_signal = Signal(Squadron)
|
remove_squadron_signal = Signal(Squadron)
|
||||||
|
|
||||||
@ -166,9 +188,20 @@ class SquadronConfigurationBox(QGroupBox):
|
|||||||
reroll_nickname_button.clicked.connect(self.reroll_nickname)
|
reroll_nickname_button.clicked.connect(self.reroll_nickname)
|
||||||
nickname_edit_layout.addWidget(reroll_nickname_button, 1, 1, Qt.AlignTop)
|
nickname_edit_layout.addWidget(reroll_nickname_button, 1, 1, Qt.AlignTop)
|
||||||
|
|
||||||
left_column.addWidget(QLabel("Primary task:"))
|
task_and_size_row = QHBoxLayout()
|
||||||
|
left_column.addLayout(task_and_size_row)
|
||||||
|
|
||||||
|
size_column = QVBoxLayout()
|
||||||
|
left_column.addLayout(size_column)
|
||||||
|
size_column.addWidget(QLabel("Max size:"))
|
||||||
|
self.max_size_selector = SquadronSizeSpinner(self.squadron.max_size, self)
|
||||||
|
size_column.addWidget(self.max_size_selector)
|
||||||
|
|
||||||
|
task_column = QVBoxLayout()
|
||||||
|
left_column.addLayout(task_column)
|
||||||
|
task_column.addWidget(QLabel("Primary task:"))
|
||||||
self.primary_task_selector = PrimaryTaskSelector.for_squadron(self.squadron)
|
self.primary_task_selector = PrimaryTaskSelector.for_squadron(self.squadron)
|
||||||
left_column.addWidget(self.primary_task_selector)
|
task_column.addWidget(self.primary_task_selector)
|
||||||
|
|
||||||
left_column.addWidget(QLabel("Base:"))
|
left_column.addWidget(QLabel("Base:"))
|
||||||
self.base_selector = SquadronBaseSelector(
|
self.base_selector = SquadronBaseSelector(
|
||||||
@ -222,6 +255,7 @@ class SquadronConfigurationBox(QGroupBox):
|
|||||||
self.name_edit.setText(self.squadron.name)
|
self.name_edit.setText(self.squadron.name)
|
||||||
self.nickname_edit.setText(self.squadron.nickname)
|
self.nickname_edit.setText(self.squadron.nickname)
|
||||||
self.primary_task_selector.setCurrentText(self.squadron.primary_task.value)
|
self.primary_task_selector.setCurrentText(self.squadron.primary_task.value)
|
||||||
|
self.max_size_selector.setValue(self.squadron.max_size)
|
||||||
self.base_selector.setCurrentText(self.squadron.location.name)
|
self.base_selector.setCurrentText(self.squadron.location.name)
|
||||||
self.player_list.setText(
|
self.player_list.setText(
|
||||||
"<br />".join(p.name for p in self.claim_players_from_squadron())
|
"<br />".join(p.name for p in self.claim_players_from_squadron())
|
||||||
@ -246,6 +280,7 @@ class SquadronConfigurationBox(QGroupBox):
|
|||||||
squadron = Squadron.create_from(
|
squadron = Squadron.create_from(
|
||||||
selected_def,
|
selected_def,
|
||||||
self.squadron.primary_task,
|
self.squadron.primary_task,
|
||||||
|
self.squadron.max_size,
|
||||||
self.squadron.location,
|
self.squadron.location,
|
||||||
self.coalition,
|
self.coalition,
|
||||||
self.game,
|
self.game,
|
||||||
@ -292,6 +327,7 @@ class SquadronConfigurationBox(QGroupBox):
|
|||||||
def apply(self) -> Squadron:
|
def apply(self) -> Squadron:
|
||||||
self.squadron.name = self.name_edit.text()
|
self.squadron.name = self.name_edit.text()
|
||||||
self.squadron.nickname = self.nickname_edit.text()
|
self.squadron.nickname = self.nickname_edit.text()
|
||||||
|
self.squadron.max_size = self.max_size_selector.value()
|
||||||
if (primary_task := self.primary_task_selector.selected_task) is not None:
|
if (primary_task := self.primary_task_selector.selected_task) is not None:
|
||||||
self.squadron.primary_task = primary_task
|
self.squadron.primary_task = primary_task
|
||||||
else:
|
else:
|
||||||
@ -557,7 +593,12 @@ class AirWingConfigurationTab(QWidget):
|
|||||||
)
|
)
|
||||||
|
|
||||||
squadron = Squadron.create_from(
|
squadron = Squadron.create_from(
|
||||||
squadron_def, selected_task, selected_base, self.coalition, self.game
|
squadron_def,
|
||||||
|
selected_task,
|
||||||
|
DEFAULT_SQUADRON_SIZE,
|
||||||
|
selected_base,
|
||||||
|
self.coalition,
|
||||||
|
self.game,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add Squadron
|
# Add Squadron
|
||||||
|
|||||||
@ -155,6 +155,7 @@ class NewGameWizard(QtWidgets.QWizard):
|
|||||||
|
|
||||||
self.lua_plugin_manager.save_player_settings()
|
self.lua_plugin_manager.save_player_settings()
|
||||||
|
|
||||||
|
use_new_squadron_rules = self.field("use_new_squadron_rules")
|
||||||
logging.info("New campaign start date: %s", start_date.strftime("%m/%d/%Y"))
|
logging.info("New campaign start date: %s", start_date.strftime("%m/%d/%Y"))
|
||||||
settings = Settings(
|
settings = Settings(
|
||||||
player_income_multiplier=self.field("player_income_multiplier") / 10,
|
player_income_multiplier=self.field("player_income_multiplier") / 10,
|
||||||
@ -168,6 +169,7 @@ class NewGameWizard(QtWidgets.QWizard):
|
|||||||
),
|
),
|
||||||
automate_aircraft_reinforcements=self.field("automate_aircraft_purchases"),
|
automate_aircraft_reinforcements=self.field("automate_aircraft_purchases"),
|
||||||
supercarrier=self.field("supercarrier"),
|
supercarrier=self.field("supercarrier"),
|
||||||
|
enable_squadron_aircraft_limits=use_new_squadron_rules,
|
||||||
)
|
)
|
||||||
settings.save_player_settings()
|
settings.save_player_settings()
|
||||||
generator_settings = GeneratorSettings(
|
generator_settings = GeneratorSettings(
|
||||||
@ -223,7 +225,7 @@ class NewGameWizard(QtWidgets.QWizard):
|
|||||||
|
|
||||||
AirWingConfigurationDialog(self.generatedGame, self).exec_()
|
AirWingConfigurationDialog(self.generatedGame, self).exec_()
|
||||||
|
|
||||||
self.generatedGame.begin_turn_0()
|
self.generatedGame.begin_turn_0(squadrons_start_full=use_new_squadron_rules)
|
||||||
|
|
||||||
super(NewGameWizard, self).accept()
|
super(NewGameWizard, self).accept()
|
||||||
|
|
||||||
@ -603,6 +605,17 @@ class DifficultyAndAutomationOptions(QtWidgets.QWizardPage):
|
|||||||
self.registerField("enemy_starting_money", self.enemy_budget.starting_money)
|
self.registerField("enemy_starting_money", self.enemy_budget.starting_money)
|
||||||
economy_layout.addLayout(self.enemy_budget)
|
economy_layout.addLayout(self.enemy_budget)
|
||||||
|
|
||||||
|
new_squadron_rules = QtWidgets.QCheckBox("Enable new squadron rules")
|
||||||
|
new_squadron_rules.setChecked(default_settings.enable_squadron_aircraft_limits)
|
||||||
|
self.registerField("use_new_squadron_rules", new_squadron_rules)
|
||||||
|
economy_layout.addWidget(new_squadron_rules)
|
||||||
|
economy_layout.addWidget(
|
||||||
|
QLabel(
|
||||||
|
"With new squadron rules enabled, squadrons will not be able to exceed a maximum number of aircraft "
|
||||||
|
"(configurable), and the campaign will begin with all squadrons at full strength."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
assist_group = QtWidgets.QGroupBox("Player assists")
|
assist_group = QtWidgets.QGroupBox("Player assists")
|
||||||
layout.addWidget(assist_group)
|
layout.addWidget(assist_group)
|
||||||
assist_layout = QtWidgets.QGridLayout()
|
assist_layout = QtWidgets.QGridLayout()
|
||||||
|
|||||||
@ -9,7 +9,7 @@ recommended_enemy_faction: Russia 2010
|
|||||||
recommended_start_date: 2004-01-07
|
recommended_start_date: 2004-01-07
|
||||||
miz: black_sea.miz
|
miz: black_sea.miz
|
||||||
performance: 2
|
performance: 2
|
||||||
version: "10.2"
|
version: "10.7"
|
||||||
squadrons:
|
squadrons:
|
||||||
# Anapa-Vityazevo
|
# Anapa-Vityazevo
|
||||||
12:
|
12:
|
||||||
@ -20,16 +20,20 @@ squadrons:
|
|||||||
- primary: AEW&C
|
- primary: AEW&C
|
||||||
aircraft:
|
aircraft:
|
||||||
- A-50
|
- A-50
|
||||||
|
size: 2
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
- IL-78M
|
- IL-78M
|
||||||
|
size: 2
|
||||||
- primary: Transport
|
- primary: Transport
|
||||||
aircraft:
|
aircraft:
|
||||||
- IL-78MD
|
- IL-78MD
|
||||||
|
size: 4
|
||||||
- primary: Strike
|
- primary: Strike
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- Tu-160 Blackjack
|
- Tu-160 Blackjack
|
||||||
|
size: 4
|
||||||
# Krasnodar-Center
|
# Krasnodar-Center
|
||||||
13:
|
13:
|
||||||
- primary: BARCAP
|
- primary: BARCAP
|
||||||
@ -77,6 +81,7 @@ squadrons:
|
|||||||
- primary: Transport
|
- primary: Transport
|
||||||
aircraft:
|
aircraft:
|
||||||
- UH-60A
|
- UH-60A
|
||||||
|
size: 8
|
||||||
# Kobuleti
|
# Kobuleti
|
||||||
24:
|
24:
|
||||||
- primary: BARCAP
|
- primary: BARCAP
|
||||||
@ -99,16 +104,20 @@ squadrons:
|
|||||||
- primary: AEW&C
|
- primary: AEW&C
|
||||||
aircraft:
|
aircraft:
|
||||||
- E-3A
|
- E-3A
|
||||||
|
size: 2
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
- KC-135 Stratotanker
|
- KC-135 Stratotanker
|
||||||
|
size: 2
|
||||||
- primary: Transport
|
- primary: Transport
|
||||||
aircraft:
|
aircraft:
|
||||||
- C-17A
|
- C-17A
|
||||||
|
size: 4
|
||||||
- primary: Strike
|
- primary: Strike
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
aircraft:
|
aircraft:
|
||||||
- B-1B Lancer
|
- B-1B Lancer
|
||||||
|
size: 4
|
||||||
Blue CV:
|
Blue CV:
|
||||||
- primary: BARCAP
|
- primary: BARCAP
|
||||||
secondary: air-to-air
|
secondary: air-to-air
|
||||||
@ -129,6 +138,7 @@ squadrons:
|
|||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
aircraft:
|
aircraft:
|
||||||
- S-3B Tanker
|
- S-3B Tanker
|
||||||
|
size: 2
|
||||||
Blue LHA:
|
Blue LHA:
|
||||||
- primary: BAI
|
- primary: BAI
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
@ -148,6 +158,7 @@ squadrons:
|
|||||||
- primary: BAI
|
- primary: BAI
|
||||||
secondary: any
|
secondary: any
|
||||||
- primary: Refueling
|
- primary: Refueling
|
||||||
|
size: 2
|
||||||
Red LHA:
|
Red LHA:
|
||||||
- primary: BAI
|
- primary: BAI
|
||||||
secondary: air-to-ground
|
secondary: air-to-ground
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user