mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9520b76246 | ||
|
|
67183c31da | ||
|
|
54759f1f94 | ||
|
|
0fcf308079 | ||
|
|
1ad27e27ea | ||
|
|
eae5e1af30 | ||
|
|
b268d09432 | ||
|
|
220b83a22d | ||
|
|
83530af35d | ||
|
|
00475d767b | ||
|
|
1a8faff717 | ||
|
|
68e0d43a1d | ||
|
|
0510af8b6b | ||
|
|
c54ac4e21a | ||
|
|
bbc41f4c1a | ||
|
|
8bc8eb0e28 | ||
|
|
86f647cc6d | ||
|
|
2f16916ac4 | ||
|
|
06044dd4c3 | ||
|
|
c46cce01b6 | ||
|
|
d78e570d9d | ||
|
|
f4a1908088 | ||
|
|
23341e69fa | ||
|
|
11fc28ad3a | ||
|
|
9b96b7be26 | ||
|
|
f7ee923cbf | ||
|
|
3d788e3ae8 | ||
|
|
624f2a00fd | ||
|
|
6c3cbbf0de | ||
|
|
96d0b2b7d9 | ||
|
|
855d269420 | ||
|
|
c0748e2a3e | ||
|
|
9f10ecc884 | ||
|
|
31c80dfd02 | ||
|
|
362ce66f80 | ||
|
|
96ee73dd50 | ||
|
|
f82fc3a930 | ||
|
|
cf575fba2a | ||
|
|
96f940bc59 | ||
|
|
98c71c255b | ||
|
|
0e5567ceee | ||
|
|
2832ece316 | ||
|
|
5cfd6c86f3 | ||
|
|
27ef269435 | ||
|
|
8b46ef5e35 | ||
|
|
e243d074ff | ||
|
|
cc39e6579b | ||
|
|
d7eaf1330f | ||
|
|
c44ea0025d | ||
|
|
1216c90891 | ||
|
|
ea80ddc321 | ||
|
|
121ca20edb | ||
|
|
e4586add72 | ||
|
|
32b2e40b37 | ||
|
|
e8190748eb | ||
|
|
d2aa615133 | ||
|
|
756602e682 | ||
|
|
204950e487 | ||
|
|
6290607eb6 | ||
|
|
afad73ac27 | ||
|
|
52fbc75e1c | ||
|
|
5c5af40bd5 | ||
|
|
d1f66ed040 | ||
|
|
6467193c88 | ||
|
|
b2670ba30b |
25
changelog.md
25
changelog.md
@@ -2,16 +2,39 @@
|
||||
|
||||
## Features/Improvements
|
||||
* **[Campaigns]** Ability to define invisible FOBs
|
||||
* **[Campaigns]** Ability to define influence zones for Control Points
|
||||
* **[Plugins]** Improvements to AI support for EW Script 2.0
|
||||
* **[Plugins]** Add moose as a base plugin
|
||||
* **[Config]** New preference setting to trigger the first-start window on every start (could help in scenarios multiple Retribution instances need to run concurrently)
|
||||
* **[Modding]** Update Grinelli Designs F-22A Mod to 2.0.0 (May 2025)
|
||||
* **[Campaign Design]** Added support for Germany Cold War terrain by Ugra Media
|
||||
* **[Options]** New option to control EPLRS-task injection in mission generator
|
||||
* **[Modding]** Add Tornado F3 ADV (v1.0, requires FC3 fix)
|
||||
* **[Modding]** Add Military Aircraft Mod 1.7.2 (See VSN Discord)
|
||||
* **[Payload Editor]** Add Sniper POD
|
||||
* **[Modding]** Update SU-30 mod to v2.8.04 Beta + CWS 3.72
|
||||
* **[Plugins]** EW Script - DEAD added to applicable flight types.
|
||||
* **[Plugins]** EW Script - Offensive Jamming restricted to aircraft with ALQ99/249 pods, or "has_built_in_jamming: true" in aircarft yaml (AI and Player)
|
||||
* **[Modding]** Update to CJS Super Hornet Mod v2.4.4
|
||||
* **[Engine]** Support for DCS 2.9.20.15010, including MiG-29A Fulcrum support.
|
||||
* **[Campaigns]** Ability to define neutral FOBs and Airfields
|
||||
* **[Modding]** Add Airboss Moose Module
|
||||
* **[AirWing]** Use aircraft display names for easier differentiation between modules
|
||||
|
||||
## Fixes
|
||||
* **[Flight Plans]** Fixed a bug when a package was created with only escort flights
|
||||
* **[Flight Plans]** Fixed bugs wrt planning escort flights
|
||||
* **[Flight Plans]** Added AntiShipStrike as a fallback task for OCA/Aircraft to fix a bug where the S-3B could not do OCA/Aircraft
|
||||
* **[Squadrons]** Fixed a bug where loading an air wing config would not properly load all squadrons
|
||||
* **[Flight Plans]** Fixed a bug where SEAD flights would fire one ARM and RTB
|
||||
* **[Plugins]** EW Script - Fix radar detection routine.
|
||||
* **[Campaign]** Fixed a bug where sinking a destroyer in a carrier group would cause squadrons to be removed from the carrier
|
||||
* **[Engine]** Fixed a bug with transfers to Helipads
|
||||
* **[Engine]** Fixed a bug with parking allocation
|
||||
* **[Flight Plans]** Fixed a bug where divert airfield was broken for opfor
|
||||
* **[Engine]** Fixed a bug with state.json loading wrt transfers
|
||||
* **[Engine]** Fixed a bug wrt pretense generation and moose script conflicts
|
||||
* **[Engine]** Fixed a bug where frontline debriefing was not properly calculated
|
||||
* **[Mission Generation]** Fixed an issue where blue and red units spawned next to each other on frontlines
|
||||
|
||||
# Retribution v1.4.1 (hotfix)
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class ArmedForces:
|
||||
# all layouts which are usable by the given faction.
|
||||
for layout in LAYOUTS.layouts:
|
||||
if layout.generic and layout.usable_by_faction(faction):
|
||||
# Creates a faction compatible GorceGroup
|
||||
# Creates a faction compatible ForceGroup
|
||||
self.add_or_update_force_group(ForceGroup.for_layout(layout, faction))
|
||||
|
||||
# Add all preset groups afterwards to prevent them being merged with generics
|
||||
|
||||
@@ -258,6 +258,9 @@ class ForceGroup:
|
||||
if unit_count == 0:
|
||||
# No units to be created so dont create a theater group for them
|
||||
return
|
||||
# If the control point is neutral, don't create any units at all
|
||||
if ground_object.control_point.captured.is_neutral:
|
||||
return
|
||||
# Generate Units
|
||||
fixed_pos = FIXED_POS_ARG in unit_group.name
|
||||
fixed_hdg = FIXED_HDG_ARG in unit_group.name
|
||||
|
||||
@@ -35,6 +35,7 @@ if TYPE_CHECKING:
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.sim.simulationresults import SimulationResults
|
||||
from game.squadrons import Squadron, Pilot
|
||||
from game.theater.player import Player
|
||||
from game.transfers import TransferOrder
|
||||
from game.data.weapons import WeaponType
|
||||
from .flightmember import FlightMember
|
||||
@@ -174,7 +175,7 @@ class Flight(
|
||||
self.roster = FlightMembers.from_roster(self, self.roster)
|
||||
|
||||
@property
|
||||
def blue(self) -> bool:
|
||||
def blue(self) -> Player:
|
||||
return self.squadron.player
|
||||
|
||||
@property
|
||||
|
||||
@@ -23,7 +23,13 @@ class EscortFlightPlan(FormationAttackFlightPlan):
|
||||
|
||||
@property
|
||||
def split_time(self) -> datetime:
|
||||
if self.package.primary_flight and self.package.primary_flight.flight_plan:
|
||||
# Avoid infinite recursion when this escort flight is itself the primary flight
|
||||
# This can happen when only escort flights remain in a package
|
||||
if (
|
||||
self.package.primary_flight
|
||||
and self.package.primary_flight != self.flight
|
||||
and self.package.primary_flight.flight_plan
|
||||
):
|
||||
return self.package.primary_flight.flight_plan.mission_departure_time
|
||||
else:
|
||||
return super().split_time
|
||||
|
||||
@@ -11,7 +11,7 @@ from ..packagewaypoints import PackageWaypoints
|
||||
if TYPE_CHECKING:
|
||||
from game.coalition import Coalition
|
||||
from game.data.doctrine import Doctrine
|
||||
from game.theater import ConflictTheater
|
||||
from game.theater import ConflictTheater, Player
|
||||
from game.threatzones import ThreatZones
|
||||
from ..flight import Flight
|
||||
from ..package import Package
|
||||
@@ -38,7 +38,7 @@ class IBuilder(ABC, Generic[FlightPlanT, LayoutT]):
|
||||
self._generate_package_waypoints_if_needed(dump_debug_info)
|
||||
self._flight_plan = self.build(dump_debug_info)
|
||||
except NavMeshError as ex:
|
||||
color = "blue" if self.flight.squadron.player else "red"
|
||||
color = "blue" if self.flight.squadron.player.is_blue else "red"
|
||||
raise PlanningError(
|
||||
f"Could not plan {color} {self.flight.flight_type.value} from "
|
||||
f"{self.flight.departure} to {self.package.target}"
|
||||
@@ -71,7 +71,7 @@ class IBuilder(ABC, Generic[FlightPlanT, LayoutT]):
|
||||
return self.flight.coalition
|
||||
|
||||
@property
|
||||
def is_player(self) -> bool:
|
||||
def is_player(self) -> Player:
|
||||
return self.coalition.player
|
||||
|
||||
@property
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Optional, TYPE_CHECKING, Union
|
||||
@@ -26,6 +25,7 @@ class SquadronConfig:
|
||||
name: Optional[str]
|
||||
nickname: Optional[str]
|
||||
female_pilot_percentage: Optional[int]
|
||||
aircraft_type: Optional[str]
|
||||
|
||||
@property
|
||||
def auto_assignable(self) -> set[FlightType]:
|
||||
@@ -51,6 +51,7 @@ class SquadronConfig:
|
||||
data.get("name", None),
|
||||
data.get("nickname", None),
|
||||
data.get("female_pilot_percentage", None),
|
||||
data.get("aircraft_type", None),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -83,15 +84,14 @@ class CampaignAirWingConfig:
|
||||
try:
|
||||
base = theater.control_point_named(base_id)
|
||||
except:
|
||||
if base_id == "Red CV":
|
||||
base = next((c for c in carriers if not c.captured), None)
|
||||
elif base_id == "Blue CV":
|
||||
base = next((c for c in carriers if c.captured), None)
|
||||
elif base_id == "Red LHA":
|
||||
base = next((l for l in lhas if not l.captured), None)
|
||||
elif base_id == "Blue LHA":
|
||||
base = next((l for l in lhas if l.captured), None)
|
||||
|
||||
logging.warning(
|
||||
f"Control point {base_id} not found, trying to match by full name"
|
||||
)
|
||||
if not base:
|
||||
try:
|
||||
base = theater.control_point_by_full_name(base_id)
|
||||
except KeyError:
|
||||
logging.error(f"Control point {base_id} not found, skipping")
|
||||
for squadron_data in squadron_configs:
|
||||
if base is None:
|
||||
logging.warning(
|
||||
|
||||
@@ -60,7 +60,7 @@ class DefaultSquadronAssigner:
|
||||
) -> Optional[SquadronDef]:
|
||||
for preferred_aircraft in config.aircraft:
|
||||
squadron_def = self.find_preferred_squadron(
|
||||
preferred_aircraft, config.primary, control_point
|
||||
preferred_aircraft, config.aircraft_type, config.primary, control_point
|
||||
)
|
||||
if squadron_def is not None:
|
||||
return squadron_def
|
||||
@@ -78,7 +78,11 @@ class DefaultSquadronAssigner:
|
||||
)
|
||||
|
||||
def find_preferred_squadron(
|
||||
self, preferred_aircraft: str, task: FlightType, control_point: ControlPoint
|
||||
self,
|
||||
preferred_aircraft: str,
|
||||
aircraft_type: Optional[str],
|
||||
task: FlightType,
|
||||
control_point: ControlPoint,
|
||||
) -> Optional[SquadronDef]:
|
||||
# Attempt to find a squadron with the name in the request.
|
||||
squadron_def = self.find_squadron_by_name(
|
||||
@@ -90,7 +94,7 @@ class DefaultSquadronAssigner:
|
||||
# If the name didn't match a squadron available to this coalition, try to find
|
||||
# an aircraft with the matching name that meets the requirements.
|
||||
try:
|
||||
aircraft = AircraftType.named(preferred_aircraft)
|
||||
aircraft = AircraftType.named(aircraft_type or preferred_aircraft)
|
||||
except KeyError:
|
||||
logging.warning(
|
||||
"%s is neither a compatible squadron or a known aircraft type, "
|
||||
|
||||
@@ -26,6 +26,7 @@ from game.theater.controlpoint import (
|
||||
Carrier,
|
||||
ControlPoint,
|
||||
ControlPointType,
|
||||
Player,
|
||||
Fob,
|
||||
Lha,
|
||||
OffMapSpawn,
|
||||
@@ -56,6 +57,7 @@ class MizCampaignLoader:
|
||||
FOB_UNIT_TYPE = Unarmed.SKP_11.id
|
||||
FARP_HELIPADS_TYPE = ["Invisible FARP", "SINGLE_HELIPAD", "FARP"]
|
||||
INVISIBLE_FOB_UNIT_TYPE = Unarmed.M_818.id
|
||||
NEUTRAL_FOB_UNIT_TYPE = Unarmed.KrAZ6322.id
|
||||
|
||||
OFFSHORE_STRIKE_TARGET_UNIT_TYPE = Fortification.Oil_platform.id
|
||||
SHIP_UNIT_TYPE = USS_Arleigh_Burke_IIa.id
|
||||
@@ -123,9 +125,13 @@ class MizCampaignLoader:
|
||||
def control_point_from_airport(
|
||||
self, airport: Airport, ctld_zones: List[Tuple[Point, float]]
|
||||
) -> ControlPoint:
|
||||
cp = Airfield(
|
||||
airport, self.theater, starts_blue=airport.is_blue(), ctld_zones=ctld_zones
|
||||
)
|
||||
if airport.dynamic_spawn:
|
||||
starting_coalition = Player.NEUTRAL
|
||||
elif airport.is_blue():
|
||||
starting_coalition = Player.BLUE
|
||||
else:
|
||||
starting_coalition = Player.RED
|
||||
cp = Airfield(airport, self.theater, starting_coalition, ctld_zones=ctld_zones)
|
||||
|
||||
# Use the unlimited aircraft option to determine if an airfield should
|
||||
# be owned by the player when the campaign is "inverted".
|
||||
@@ -133,47 +139,54 @@ class MizCampaignLoader:
|
||||
|
||||
return cp
|
||||
|
||||
def country(self, blue: bool) -> Country:
|
||||
country = self.mission.country(
|
||||
self.BLUE_COUNTRY.name if blue else self.RED_COUNTRY.name
|
||||
)
|
||||
def country(self, blue: Player) -> Country:
|
||||
if blue.is_blue:
|
||||
country = self.mission.country(self.BLUE_COUNTRY.name)
|
||||
else:
|
||||
country = self.mission.country(self.RED_COUNTRY.name)
|
||||
# Should be guaranteed because we initialized them.
|
||||
assert country
|
||||
return country
|
||||
|
||||
@property
|
||||
def blue(self) -> Country:
|
||||
return self.country(blue=True)
|
||||
return self.country(blue=Player.BLUE)
|
||||
|
||||
@property
|
||||
def red(self) -> Country:
|
||||
return self.country(blue=False)
|
||||
return self.country(blue=Player.RED)
|
||||
|
||||
def off_map_spawns(self, blue: bool) -> Iterator[PlaneGroup]:
|
||||
def off_map_spawns(self, blue: Player) -> Iterator[PlaneGroup]:
|
||||
for group in self.country(blue).plane_group:
|
||||
if group.units[0].type == self.OFF_MAP_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
def carriers(self, blue: bool) -> Iterator[ShipGroup]:
|
||||
def carriers(self, blue: Player) -> Iterator[ShipGroup]:
|
||||
for group in self.country(blue).ship_group:
|
||||
if group.units[0].type == self.CV_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
def lhas(self, blue: bool) -> Iterator[ShipGroup]:
|
||||
def lhas(self, blue: Player) -> Iterator[ShipGroup]:
|
||||
for group in self.country(blue).ship_group:
|
||||
if group.units[0].type == self.LHA_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
def fobs(self, blue: bool) -> Iterator[VehicleGroup]:
|
||||
def fobs(self, blue: Player) -> Iterator[VehicleGroup]:
|
||||
for group in self.country(blue).vehicle_group:
|
||||
if group.units[0].type == self.FOB_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
def invisible_fobs(self, blue: bool) -> Iterator[VehicleGroup]:
|
||||
def invisible_fobs(self, blue: Player) -> Iterator[VehicleGroup]:
|
||||
for group in self.country(blue).vehicle_group:
|
||||
if group.units[0].type == self.INVISIBLE_FOB_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
@property
|
||||
def neutral_fobs(self) -> Iterator[VehicleGroup]:
|
||||
for group in self.red.vehicle_group:
|
||||
if group.units[0].type == self.NEUTRAL_FOB_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
@property
|
||||
def ships(self) -> Iterator[ShipGroup]:
|
||||
for group in self.red.ship_group:
|
||||
@@ -290,12 +303,12 @@ class MizCampaignLoader:
|
||||
def control_points(self) -> dict[UUID, ControlPoint]:
|
||||
control_points = {}
|
||||
for airport in self.mission.terrain.airport_list():
|
||||
if airport.is_blue() or airport.is_red():
|
||||
if airport.is_blue() or airport.is_red() or airport.is_neutral():
|
||||
ctld_zones = self.get_ctld_zones(airport.name)
|
||||
control_point = self.control_point_from_airport(airport, ctld_zones)
|
||||
control_points[control_point.id] = control_point
|
||||
|
||||
for blue in (False, True):
|
||||
for blue in (Player.RED, Player.BLUE):
|
||||
for group in self.off_map_spawns(blue):
|
||||
control_point = OffMapSpawn(
|
||||
str(group.name), group.position, self.theater, starts_blue=blue
|
||||
@@ -339,6 +352,18 @@ class MizCampaignLoader:
|
||||
control_point.captured_invert = fob.late_activation
|
||||
control_points[control_point.id] = control_point
|
||||
|
||||
for fob in self.neutral_fobs:
|
||||
ctld_zones = self.get_ctld_zones(fob.name)
|
||||
control_point = Fob(
|
||||
str(fob.name),
|
||||
fob.position,
|
||||
self.theater,
|
||||
starts_blue=Player.NEUTRAL,
|
||||
ctld_zones=ctld_zones,
|
||||
)
|
||||
control_point.captured_invert = fob.late_activation
|
||||
control_points[control_point.id] = control_point
|
||||
|
||||
if self.cp_influence_zones:
|
||||
for cp in control_points.values():
|
||||
for influence_radius in self.cp_influence_zones:
|
||||
@@ -348,13 +373,13 @@ class MizCampaignLoader:
|
||||
|
||||
@property
|
||||
def front_line_path_groups(self) -> Iterator[VehicleGroup]:
|
||||
for group in self.country(blue=True).vehicle_group:
|
||||
for group in self.country(blue=Player.BLUE).vehicle_group:
|
||||
if group.units[0].type == self.FRONT_LINE_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
@property
|
||||
def shipping_lane_groups(self) -> Iterator[ShipGroup]:
|
||||
for group in self.country(blue=True).ship_group:
|
||||
for group in self.country(blue=Player.BLUE).ship_group:
|
||||
if group.units[0].type == self.SHIPPING_LANE_UNIT_TYPE:
|
||||
yield group
|
||||
|
||||
@@ -378,7 +403,7 @@ class MizCampaignLoader:
|
||||
|
||||
@property
|
||||
def cp_convoy_spawns(self) -> Iterator[VehicleGroup]:
|
||||
for group in self.country(blue=True).vehicle_group:
|
||||
for group in self.country(blue=Player.BLUE).vehicle_group:
|
||||
if group.units[0].type == self.CP_CONVOY_SPAWN_TYPE:
|
||||
yield group
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from game.procurement import AircraftProcurementRequest, ProcurementAi
|
||||
from game.profiling import MultiEventTracer, logged_duration
|
||||
from game.squadrons import AirWing
|
||||
from game.theater.bullseye import Bullseye
|
||||
from game.theater.player import Player
|
||||
from game.theater.transitnetwork import TransitNetwork, TransitNetworkBuilder
|
||||
from game.threatzones import ThreatZones
|
||||
from game.transfers import PendingTransfers
|
||||
@@ -32,7 +33,7 @@ if TYPE_CHECKING:
|
||||
|
||||
class Coalition:
|
||||
def __init__(
|
||||
self, game: Game, faction: Faction, budget: float, player: bool
|
||||
self, game: Game, faction: Faction, budget: float, player: Player
|
||||
) -> None:
|
||||
self.game = game
|
||||
self.player = player
|
||||
@@ -68,9 +69,11 @@ class Coalition:
|
||||
|
||||
@property
|
||||
def coalition_id(self) -> int:
|
||||
if self.player:
|
||||
if self.player.is_blue:
|
||||
return 2
|
||||
return 1
|
||||
elif self.player.is_red:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def opponent(self) -> Coalition:
|
||||
@@ -95,12 +98,23 @@ class Coalition:
|
||||
state = self.__dict__.copy()
|
||||
# Avoid persisting any volatile types that can be deterministically
|
||||
# recomputed on load for the sake of save compatibility.
|
||||
del state["_threat_zone"]
|
||||
del state["_navmesh"]
|
||||
del state["faker"]
|
||||
# TODO: Figure out why this is needed after adding neutral point support
|
||||
if state["player"] != Player.NEUTRAL:
|
||||
del state["_threat_zone"]
|
||||
del state["_navmesh"]
|
||||
return state
|
||||
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
# Migration: Convert old boolean player values to Player enum
|
||||
if "player" in state and isinstance(state["player"], bool):
|
||||
from game.theater.player import Player
|
||||
|
||||
if state["player"]:
|
||||
state["player"] = Player.BLUE
|
||||
else:
|
||||
state["player"] = Player.RED
|
||||
|
||||
self.__dict__.update(state)
|
||||
# Regenerate any state that was not persisted.
|
||||
self.on_load()
|
||||
@@ -203,7 +217,7 @@ class Coalition:
|
||||
squadron.refund_orders()
|
||||
|
||||
def plan_missions(self, now: datetime) -> None:
|
||||
color = "Blue" if self.player else "Red"
|
||||
color = "Blue" if self.player.is_blue else "Red"
|
||||
with MultiEventTracer() as tracer:
|
||||
with tracer.trace(f"{color} mission planning"):
|
||||
with tracer.trace(f"{color} mission identification"):
|
||||
@@ -220,7 +234,7 @@ class Coalition:
|
||||
# to ground forces and 1400 to aircraft. After that the budget will be spent
|
||||
# proportionally based on how much is already invested.
|
||||
|
||||
if self.player:
|
||||
if self.player.is_blue:
|
||||
manage_runways = self.game.settings.automate_runway_repair
|
||||
manage_front_line = self.game.settings.automate_front_line_reinforcements
|
||||
manage_aircraft = self.game.settings.automate_aircraft_reinforcements
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import math
|
||||
import operator
|
||||
from collections.abc import Iterable, Iterator
|
||||
@@ -16,6 +17,7 @@ from game.theater import (
|
||||
OffMapSpawn,
|
||||
ParkingType,
|
||||
NavalControlPoint,
|
||||
Player,
|
||||
)
|
||||
from game.theater.theatergroundobject import (
|
||||
BuildingGroundObject,
|
||||
@@ -35,7 +37,7 @@ MissionTargetType = TypeVar("MissionTargetType", bound=MissionTarget)
|
||||
class ObjectiveFinder:
|
||||
"""Identifies potential objectives for the mission planner."""
|
||||
|
||||
def __init__(self, game: Game, is_player: bool) -> None:
|
||||
def __init__(self, game: Game, is_player: Player) -> None:
|
||||
self.game = game
|
||||
self.is_player = is_player
|
||||
|
||||
@@ -154,7 +156,7 @@ class ObjectiveFinder:
|
||||
airfields_in_proximity = self.closest_airfields_to(cp)
|
||||
airbase_threat_range = self.game.settings.airbase_threat_range
|
||||
if (
|
||||
not self.is_player
|
||||
self.is_player.is_red
|
||||
and randint(1, 100)
|
||||
> self.game.settings.opfor_autoplanner_aggressiveness
|
||||
):
|
||||
@@ -216,7 +218,7 @@ class ObjectiveFinder:
|
||||
|
||||
def farthest_friendly_control_point(self) -> ControlPoint:
|
||||
"""Finds the friendly control point that is farthest from any threats."""
|
||||
threat_zones = self.game.threat_zone_for(not self.is_player)
|
||||
threat_zones = self.game.threat_zone_for(self.is_player.opponent)
|
||||
|
||||
farthest = None
|
||||
max_distance = meters(0)
|
||||
@@ -234,7 +236,7 @@ class ObjectiveFinder:
|
||||
|
||||
def closest_friendly_control_point(self) -> ControlPoint:
|
||||
"""Finds the friendly control point that is closest to any threats."""
|
||||
threat_zones = self.game.threat_zone_for(not self.is_player)
|
||||
threat_zones = self.game.threat_zone_for(self.is_player.opponent)
|
||||
|
||||
closest = None
|
||||
min_distance = meters(math.inf)
|
||||
@@ -258,14 +260,37 @@ class ObjectiveFinder:
|
||||
return (
|
||||
c
|
||||
for c in self.game.theater.controlpoints
|
||||
if not c.is_friendly(self.is_player)
|
||||
if not c.is_friendly(self.is_player) and c.captured != Player.NEUTRAL
|
||||
)
|
||||
|
||||
def prioritized_points(self) -> list[ControlPoint]:
|
||||
prioritized = []
|
||||
capturable_later = []
|
||||
isolated = []
|
||||
for cp in self.game.theater.control_points_for(not self.is_player):
|
||||
for cp in self.game.theater.control_points_for(self.is_player.opponent):
|
||||
if cp.is_isolated:
|
||||
isolated.append(cp)
|
||||
continue
|
||||
if cp.has_active_frontline:
|
||||
prioritized.append(cp)
|
||||
else:
|
||||
capturable_later.append(cp)
|
||||
prioritized.extend(self._targets_by_range(capturable_later))
|
||||
prioritized.extend(self._targets_by_range(isolated))
|
||||
return prioritized
|
||||
|
||||
def air_assault_targets(self) -> list[ControlPoint]:
|
||||
"""Returns control points suitable for air assault missions, including neutral bases."""
|
||||
prioritized = []
|
||||
capturable_later = []
|
||||
isolated = []
|
||||
|
||||
combined_control_points = itertools.chain(
|
||||
self.game.theater.control_points_for(self.is_player.opponent),
|
||||
self.game.theater.control_points_for(Player.NEUTRAL),
|
||||
)
|
||||
|
||||
for cp in combined_control_points:
|
||||
if cp.is_isolated:
|
||||
isolated.append(cp)
|
||||
continue
|
||||
|
||||
@@ -43,7 +43,9 @@ class PackageFulfiller:
|
||||
|
||||
@property
|
||||
def is_player(self) -> bool:
|
||||
return self.coalition.player
|
||||
if self.coalition.player.is_blue:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def ato(self) -> AirTaskingOrder:
|
||||
|
||||
@@ -10,7 +10,7 @@ from game.commander.tasks.compound.reduceenemyfrontlinecapacity import (
|
||||
from game.commander.tasks.primitive.breakthroughattack import BreakthroughAttack
|
||||
from game.commander.theaterstate import TheaterState
|
||||
from game.htn import CompoundTask, Method
|
||||
from game.theater import ControlPoint, FrontLine
|
||||
from game.theater import ControlPoint, FrontLine, Player
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -26,12 +26,12 @@ class CaptureBase(CompoundTask[TheaterState]):
|
||||
def enemy_cp(self, state: TheaterState) -> ControlPoint:
|
||||
return self.front_line.control_point_hostile_to(state.context.coalition.player)
|
||||
|
||||
def units_deployable(self, state: TheaterState, player: bool) -> int:
|
||||
def units_deployable(self, state: TheaterState, player: Player) -> int:
|
||||
cp = self.front_line.control_point_friendly_to(player)
|
||||
ammo_depots = list(state.ammo_dumps_at(cp))
|
||||
return cp.deployable_front_line_units_with(len(ammo_depots))
|
||||
|
||||
def unit_cap(self, state: TheaterState, player: bool) -> int:
|
||||
def unit_cap(self, state: TheaterState, player: Player) -> int:
|
||||
cp = self.front_line.control_point_friendly_to(player)
|
||||
ammo_depots = list(state.ammo_dumps_at(cp))
|
||||
return cp.front_line_capacity_with(len(ammo_depots))
|
||||
|
||||
@@ -11,10 +11,11 @@ from game.theater import FrontLine
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.coalition import Coalition
|
||||
from game.theater.player import Player
|
||||
|
||||
|
||||
class FrontLineStanceTask(TheaterCommanderTask, ABC):
|
||||
def __init__(self, front_line: FrontLine, player: bool) -> None:
|
||||
def __init__(self, front_line: FrontLine, player: Player) -> None:
|
||||
self.front_line = front_line
|
||||
self.friendly_cp = self.front_line.control_point_friendly_to(player)
|
||||
self.enemy_cp = self.front_line.control_point_hostile_to(player)
|
||||
@@ -26,7 +27,7 @@ class FrontLineStanceTask(TheaterCommanderTask, ABC):
|
||||
@staticmethod
|
||||
def management_allowed(state: TheaterState) -> bool:
|
||||
return (
|
||||
not state.context.coalition.player
|
||||
not state.context.coalition.player.is_blue
|
||||
or state.context.settings.automate_front_line_stance
|
||||
)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]):
|
||||
|
||||
def preconditions_met(self, state: TheaterState) -> bool:
|
||||
if (
|
||||
state.context.coalition.player
|
||||
state.context.coalition.player.is_blue
|
||||
and state.context.settings.auto_ato_behavior is AutoAtoBehavior.Disabled
|
||||
):
|
||||
return False
|
||||
@@ -102,7 +102,7 @@ class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]):
|
||||
return 1
|
||||
|
||||
def fulfill_mission(self, state: TheaterState) -> bool:
|
||||
color = "blue" if state.context.coalition.player else "red"
|
||||
color = "blue" if state.context.coalition.player.is_blue else "red"
|
||||
self.propose_flights()
|
||||
fulfiller = PackageFulfiller(
|
||||
state.context.coalition,
|
||||
@@ -214,7 +214,7 @@ class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]):
|
||||
settings = state.context.coalition.game.settings
|
||||
margin = 100 - (
|
||||
settings.ownfor_autoplanner_aggressiveness
|
||||
if state.context.coalition.player
|
||||
if state.context.coalition.player.is_blue
|
||||
else settings.opfor_autoplanner_aggressiveness
|
||||
)
|
||||
threat_range = iads_threat.max_threat_range() * (margin / 100)
|
||||
|
||||
@@ -12,7 +12,7 @@ from game.theater import MissionTarget
|
||||
class PlanAewc(PackagePlanningTask[MissionTarget]):
|
||||
def preconditions_met(self, state: TheaterState) -> bool:
|
||||
if (
|
||||
state.context.coalition.player
|
||||
state.context.coalition.player.is_blue
|
||||
and not state.context.settings.auto_ato_behavior_awacs
|
||||
):
|
||||
return False
|
||||
|
||||
@@ -6,7 +6,7 @@ from game.ato.flighttype import FlightType
|
||||
from game.commander.missionproposals import EscortType
|
||||
from game.commander.tasks.packageplanningtask import PackagePlanningTask
|
||||
from game.commander.theaterstate import TheaterState
|
||||
from game.theater import FrontLine
|
||||
from game.theater import FrontLine, Player
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -19,9 +19,8 @@ class PlanCas(PackagePlanningTask[FrontLine]):
|
||||
# An exception is made for turn zero since that's not being truly planned, but
|
||||
# just to determine what missions should be planned on turn 1 (when there *will*
|
||||
# be ground units) and what aircraft should be ordered.
|
||||
enemy_cp = self.target.control_point_friendly_to(
|
||||
player=not state.context.coalition.player
|
||||
)
|
||||
player = state.context.coalition.player.opponent
|
||||
enemy_cp = self.target.control_point_friendly_to(player)
|
||||
if enemy_cp.deployable_front_line_units == 0 and state.context.turn > 0:
|
||||
return False
|
||||
return super().preconditions_met(state)
|
||||
|
||||
@@ -14,7 +14,7 @@ MARGIN = 4 # assume 4 aircraft can land without refueling
|
||||
class PlanRecovery(PackagePlanningTask[ControlPoint]):
|
||||
def preconditions_met(self, state: TheaterState) -> bool:
|
||||
if (
|
||||
state.context.coalition.player
|
||||
state.context.coalition.player.is_blue
|
||||
and not state.context.settings.auto_ato_behavior_tankers
|
||||
):
|
||||
return False
|
||||
|
||||
@@ -12,7 +12,7 @@ from game.theater import MissionTarget
|
||||
class PlanRefueling(PackagePlanningTask[MissionTarget]):
|
||||
def preconditions_met(self, state: TheaterState) -> bool:
|
||||
if (
|
||||
state.context.coalition.player
|
||||
state.context.coalition.player.is_blue
|
||||
and not state.context.settings.auto_ato_behavior_tankers
|
||||
):
|
||||
return False
|
||||
|
||||
@@ -56,7 +56,7 @@ https://en.wikipedia.org/wiki/Hierarchical_task_network
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from game.ato.starttype import StartType
|
||||
from game.commander.tasks.compound.nextaction import PlanNextAction
|
||||
@@ -67,10 +67,11 @@ from game.profiling import MultiEventTracer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.theater.player import Player
|
||||
|
||||
|
||||
class TheaterCommander(Planner[TheaterState, TheaterCommanderTask]):
|
||||
def __init__(self, game: Game, player: bool) -> None:
|
||||
def __init__(self, game: Game, player: Player) -> None:
|
||||
super().__init__(
|
||||
PlanNextAction(
|
||||
aircraft_cold_start=game.settings.default_start_type is StartType.COLD
|
||||
@@ -79,6 +80,18 @@ class TheaterCommander(Planner[TheaterState, TheaterCommanderTask]):
|
||||
self.game = game
|
||||
self.player = player
|
||||
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
# Migration: Convert old boolean player values to Player enum
|
||||
if "player" in state and isinstance(state["player"], bool):
|
||||
from game.theater.player import Player
|
||||
|
||||
if state["player"]:
|
||||
state["player"] = Player.BLUE
|
||||
else:
|
||||
state["player"] = Player.RED
|
||||
|
||||
self.__dict__.update(state)
|
||||
|
||||
def plan_missions(self, now: datetime, tracer: MultiEventTracer) -> None:
|
||||
state = TheaterState.from_game(self.game, self.player, now, tracer)
|
||||
while True:
|
||||
|
||||
@@ -20,6 +20,7 @@ from game.theater import (
|
||||
ControlPoint,
|
||||
FrontLine,
|
||||
MissionTarget,
|
||||
Player,
|
||||
)
|
||||
from game.theater.theatergroundobject import (
|
||||
BuildingGroundObject,
|
||||
@@ -152,11 +153,12 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
|
||||
@classmethod
|
||||
def from_game(
|
||||
cls, game: Game, player: bool, now: datetime, tracer: MultiEventTracer
|
||||
cls, game: Game, player: Player, now: datetime, tracer: MultiEventTracer
|
||||
) -> TheaterState:
|
||||
coalition = game.coalition_for(player)
|
||||
finder = ObjectiveFinder(game, player)
|
||||
ordered_capturable_points = finder.prioritized_points()
|
||||
air_assault_capturable_points = finder.air_assault_targets()
|
||||
|
||||
context = PersistentContext(
|
||||
game.db,
|
||||
@@ -176,7 +178,7 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
|
||||
battle_postitions: Dict[ControlPoint, BattlePositions] = {
|
||||
cp: BattlePositions.for_control_point(cp)
|
||||
for cp in ordered_capturable_points
|
||||
for cp in air_assault_capturable_points
|
||||
}
|
||||
|
||||
vulnerable_control_points = [
|
||||
@@ -213,8 +215,8 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
)
|
||||
),
|
||||
strike_targets=list(finder.strike_targets()),
|
||||
enemy_barcaps=list(game.theater.control_points_for(not player)),
|
||||
threat_zones=game.threat_zone_for(not player),
|
||||
enemy_barcaps=list(game.theater.control_points_for(player.opponent)),
|
||||
threat_zones=game.threat_zone_for(player.opponent),
|
||||
vulnerable_control_points=vulnerable_control_points,
|
||||
control_point_priority_queue=ordered_capturable_points,
|
||||
priority_cp=(
|
||||
|
||||
@@ -123,6 +123,7 @@ class WeaponType(Enum):
|
||||
TGP = "TGP"
|
||||
DECOY = "DECOY"
|
||||
JAMMER = "JAMMER"
|
||||
OFFENSIVE_JAMMER = "OFFENSIVE_JAMMER"
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ from game.radio.channels import (
|
||||
KiowaChannelNamer,
|
||||
ARC5RadioChannelAllocator,
|
||||
ARC5ChannelNamer,
|
||||
FulcrumChannelNamer,
|
||||
)
|
||||
from game.utils import (
|
||||
Distance,
|
||||
@@ -122,6 +123,7 @@ class RadioConfig:
|
||||
"a10c-ii": WarthogChannelNamer,
|
||||
"phantom": PhantomChannelNamer,
|
||||
"kiowa": KiowaChannelNamer,
|
||||
"fulcrum": FulcrumChannelNamer,
|
||||
}[config.get("namer", "default")]
|
||||
|
||||
|
||||
@@ -233,10 +235,14 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
# when no TGP is mounted on any station.
|
||||
has_built_in_target_pod: bool
|
||||
|
||||
# indicates if the aircraft has a built-in jammer allowing EWJamming to be used
|
||||
# indicates if the aircraft has a built-in jammer allowing Defensive EWJamming to be used
|
||||
# without the need for a jamming pod
|
||||
has_built_in_ecm: bool
|
||||
|
||||
# Indicates if the aircraft has a built in jammer allowing Offensive EWJamming to be used
|
||||
# without the need for a jamming pod
|
||||
has_built_in_jamming: bool
|
||||
|
||||
task_priorities: dict[FlightType, int]
|
||||
laser_code_configs: list[LaserCodeConfig]
|
||||
|
||||
@@ -600,6 +606,7 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
task_priorities=task_priorities,
|
||||
has_built_in_target_pod=data.get("has_built_in_target_pod", False),
|
||||
has_built_in_ecm=data.get("has_built_in_ecm", False),
|
||||
has_built_in_jamming=data.get("has_built_in_jamming", False),
|
||||
laser_code_configs=[
|
||||
LaserCodeConfig.from_yaml(d) for d in data.get("laser_codes", [])
|
||||
],
|
||||
|
||||
@@ -16,7 +16,7 @@ from uuid import UUID
|
||||
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.theater import Airfield, ControlPoint
|
||||
from game.theater import Airfield, ControlPoint, Player
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@@ -45,9 +45,9 @@ class AirLosses:
|
||||
def losses(self) -> Iterator[FlyingUnit]:
|
||||
return itertools.chain(self.player, self.enemy)
|
||||
|
||||
def by_type(self, player: bool) -> Dict[AircraftType, int]:
|
||||
def by_type(self, player: Player) -> Dict[AircraftType, int]:
|
||||
losses_by_type: Dict[AircraftType, int] = defaultdict(int)
|
||||
losses = self.player if player else self.enemy
|
||||
losses = self.player if player.is_blue else self.enemy
|
||||
for loss in losses:
|
||||
losses_by_type[loss.flight.unit_type] += 1
|
||||
return losses_by_type
|
||||
@@ -87,7 +87,7 @@ class GroundLosses:
|
||||
@dataclass(frozen=True)
|
||||
class BaseCaptureEvent:
|
||||
control_point: ControlPoint
|
||||
captured_by_player: bool
|
||||
captured_by_player: Player
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -166,7 +166,7 @@ class Debriefing:
|
||||
|
||||
def merge_simulation_results(self, results: SimulationResults) -> None:
|
||||
for air_loss in results.air_losses:
|
||||
if air_loss.flight.squadron.player:
|
||||
if air_loss.flight.squadron.player.is_blue:
|
||||
self.air_losses.player.append(air_loss)
|
||||
else:
|
||||
self.air_losses.enemy.append(air_loss)
|
||||
@@ -209,9 +209,9 @@ class Debriefing:
|
||||
def casualty_count(self, control_point: ControlPoint) -> int:
|
||||
return len([x for x in self.front_line_losses if x.origin == control_point])
|
||||
|
||||
def front_line_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
def front_line_losses_by_type(self, player: Player) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
if player.is_blue:
|
||||
losses = self.ground_losses.player_front_line
|
||||
else:
|
||||
losses = self.ground_losses.enemy_front_line
|
||||
@@ -219,9 +219,9 @@ class Debriefing:
|
||||
losses_by_type[loss.unit_type] += 1
|
||||
return losses_by_type
|
||||
|
||||
def convoy_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
def convoy_losses_by_type(self, player: Player) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
if player.is_blue:
|
||||
losses = self.ground_losses.player_convoy
|
||||
else:
|
||||
losses = self.ground_losses.enemy_convoy
|
||||
@@ -229,9 +229,9 @@ class Debriefing:
|
||||
losses_by_type[loss.unit_type] += 1
|
||||
return losses_by_type
|
||||
|
||||
def cargo_ship_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
def cargo_ship_losses_by_type(self, player: Player) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
if player.is_blue:
|
||||
ships = self.ground_losses.player_cargo_ships
|
||||
else:
|
||||
ships = self.ground_losses.enemy_cargo_ships
|
||||
@@ -240,9 +240,9 @@ class Debriefing:
|
||||
losses_by_type[unit_type] += count
|
||||
return losses_by_type
|
||||
|
||||
def airlift_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]:
|
||||
def airlift_losses_by_type(self, player: Player) -> dict[GroundUnitType, int]:
|
||||
losses_by_type: dict[GroundUnitType, int] = defaultdict(int)
|
||||
if player:
|
||||
if player.is_blue:
|
||||
losses = self.ground_losses.player_airlifts
|
||||
else:
|
||||
losses = self.ground_losses.enemy_airlifts
|
||||
@@ -251,9 +251,9 @@ class Debriefing:
|
||||
losses_by_type[unit_type] += 1
|
||||
return losses_by_type
|
||||
|
||||
def ground_object_losses_by_type(self, player: bool) -> Dict[str, int]:
|
||||
def ground_object_losses_by_type(self, player: Player) -> Dict[str, int]:
|
||||
losses_by_type: Dict[str, int] = defaultdict(int)
|
||||
if player:
|
||||
if player.is_blue:
|
||||
losses = self.ground_losses.player_ground_objects
|
||||
else:
|
||||
losses = self.ground_losses.enemy_ground_objects
|
||||
@@ -261,9 +261,9 @@ class Debriefing:
|
||||
losses_by_type[loss.theater_unit.type.id] += 1
|
||||
return losses_by_type
|
||||
|
||||
def scenery_losses_by_type(self, player: bool) -> Dict[str, int]:
|
||||
def scenery_losses_by_type(self, player: Player) -> Dict[str, int]:
|
||||
losses_by_type: Dict[str, int] = defaultdict(int)
|
||||
if player:
|
||||
if player.is_blue:
|
||||
losses = self.ground_losses.player_scenery
|
||||
else:
|
||||
losses = self.ground_losses.enemy_scenery
|
||||
@@ -279,7 +279,7 @@ class Debriefing:
|
||||
if aircraft is None:
|
||||
logging.error(f"Could not find Flight matching {unit_name}")
|
||||
continue
|
||||
if aircraft.flight.departure.captured:
|
||||
if aircraft.flight.departure.captured.is_blue:
|
||||
player_losses.append(aircraft)
|
||||
else:
|
||||
enemy_losses.append(aircraft)
|
||||
@@ -290,7 +290,7 @@ class Debriefing:
|
||||
for unit_name in self.state_data.killed_ground_units:
|
||||
front_line_unit = self.unit_map.front_line_unit(unit_name)
|
||||
if front_line_unit is not None:
|
||||
if front_line_unit.origin.captured:
|
||||
if front_line_unit.origin.captured.is_blue:
|
||||
losses.player_front_line.append(front_line_unit)
|
||||
else:
|
||||
losses.enemy_front_line.append(front_line_unit)
|
||||
@@ -298,7 +298,7 @@ class Debriefing:
|
||||
|
||||
convoy_unit = self.unit_map.convoy_unit(unit_name)
|
||||
if convoy_unit is not None:
|
||||
if convoy_unit.convoy.player_owned:
|
||||
if convoy_unit.convoy.player_owned.is_blue:
|
||||
losses.player_convoy.append(convoy_unit)
|
||||
else:
|
||||
losses.enemy_convoy.append(convoy_unit)
|
||||
@@ -306,7 +306,7 @@ class Debriefing:
|
||||
|
||||
cargo_ship = self.unit_map.cargo_ship(unit_name)
|
||||
if cargo_ship is not None:
|
||||
if cargo_ship.player_owned:
|
||||
if cargo_ship.player_owned.is_blue:
|
||||
losses.player_cargo_ships.append(cargo_ship)
|
||||
else:
|
||||
losses.enemy_cargo_ships.append(cargo_ship)
|
||||
@@ -314,7 +314,9 @@ class Debriefing:
|
||||
|
||||
ground_object = self.unit_map.theater_units(unit_name)
|
||||
if ground_object is not None:
|
||||
if ground_object.theater_unit.ground_object.is_friendly(to_player=True):
|
||||
if ground_object.theater_unit.ground_object.is_friendly(
|
||||
to_player=Player.BLUE
|
||||
):
|
||||
losses.player_ground_objects.append(ground_object)
|
||||
else:
|
||||
losses.enemy_ground_objects.append(ground_object)
|
||||
@@ -323,7 +325,9 @@ class Debriefing:
|
||||
scenery_object = self.unit_map.scenery_object(unit_name)
|
||||
# Try appending object to the name, because we do this for building statics.
|
||||
if scenery_object is not None:
|
||||
if scenery_object.ground_unit.ground_object.is_friendly(to_player=True):
|
||||
if scenery_object.ground_unit.ground_object.is_friendly(
|
||||
to_player=Player.BLUE
|
||||
):
|
||||
losses.player_scenery.append(scenery_object)
|
||||
else:
|
||||
losses.enemy_scenery.append(scenery_object)
|
||||
@@ -331,9 +335,9 @@ class Debriefing:
|
||||
|
||||
airfield = self.unit_map.airfield(unit_name)
|
||||
if airfield is not None:
|
||||
if airfield.captured:
|
||||
if airfield.captured.is_blue:
|
||||
losses.player_airfields.append(airfield)
|
||||
else:
|
||||
elif airfield.captured.is_red:
|
||||
losses.enemy_airfields.append(airfield)
|
||||
continue
|
||||
|
||||
@@ -349,7 +353,7 @@ class Debriefing:
|
||||
for unit_name in self.state_data.killed_aircraft:
|
||||
airlift_unit = self.unit_map.airlift_unit(unit_name)
|
||||
if airlift_unit is not None:
|
||||
if airlift_unit.transfer.player:
|
||||
if airlift_unit.transfer.player.is_blue:
|
||||
losses.player_airlifts.append(airlift_unit)
|
||||
else:
|
||||
losses.enemy_airlifts.append(airlift_unit)
|
||||
@@ -377,8 +381,10 @@ class Debriefing:
|
||||
# Captured base is not a part of the campaign. This happens when neutral
|
||||
# bases are near the conflict. Nothing to do.
|
||||
continue
|
||||
|
||||
captured_by_player = int(new_owner_id_str) == blue_coalition_id
|
||||
if int(new_owner_id_str) == blue_coalition_id:
|
||||
captured_by_player = Player.BLUE
|
||||
else:
|
||||
captured_by_player = Player.RED
|
||||
if control_point.is_friendly(to_player=captured_by_player):
|
||||
# Base is currently friendly to the new owner. Was captured and
|
||||
# recaptured in the same mission. Nothing to do.
|
||||
|
||||
@@ -865,6 +865,16 @@ class Faction:
|
||||
# MiG-31BM
|
||||
if not mod_settings.mig31bm_foxhound:
|
||||
self.remove_aircraft("MiG-31BM")
|
||||
# Mlitary Aircraft Mod 1.7.1
|
||||
if not mod_settings.mam:
|
||||
self.remove_aircraft("A400M_Atlas")
|
||||
self.remove_aircraft("B2_Spirit")
|
||||
self.remove_aircraft("C2A_Greyhound")
|
||||
self.remove_aircraft("C5_Galaxy")
|
||||
self.remove_aircraft("KC_10_Extender")
|
||||
self.remove_aircraft("KC_10_Extender_D")
|
||||
self.remove_aircraft("P3C_Orion")
|
||||
self.remove_aircraft("V22_Osprey")
|
||||
# Tornado f.3 ADV (1.0)
|
||||
if not mod_settings.tornado_adv:
|
||||
self.remove_aircraft("Tornado_ADV")
|
||||
|
||||
51
game/game.py
51
game/game.py
@@ -4,9 +4,10 @@ import itertools
|
||||
import logging
|
||||
import math
|
||||
from collections.abc import Iterator
|
||||
from copy import deepcopy
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from enum import Enum
|
||||
from typing import Any, List, TYPE_CHECKING, Type, Union, cast
|
||||
from typing import Any, List, TYPE_CHECKING, Union, cast
|
||||
from uuid import UUID
|
||||
|
||||
from dcs.countries import Switzerland, USAFAggressors, UnitedNationsPeacekeepers
|
||||
@@ -32,7 +33,7 @@ from .infos.information import Information
|
||||
from .lasercodes.lasercoderegistry import LaserCodeRegistry
|
||||
from .profiling import logged_duration
|
||||
from .settings import Settings
|
||||
from .theater import ConflictTheater
|
||||
from .theater import ConflictTheater, Player
|
||||
from .theater.bullseye import Bullseye
|
||||
from .theater.theatergroundobject import (
|
||||
EwrGroundObject,
|
||||
@@ -138,8 +139,11 @@ class Game:
|
||||
self.conditions = self.generate_conditions(forced_time=start_time)
|
||||
|
||||
self.sanitize_sides(player_faction, enemy_faction)
|
||||
self.blue = Coalition(self, player_faction, player_budget, player=True)
|
||||
self.red = Coalition(self, enemy_faction, enemy_budget, player=False)
|
||||
self.blue = Coalition(self, player_faction, player_budget, player=Player.BLUE)
|
||||
self.red = Coalition(self, enemy_faction, enemy_budget, player=Player.RED)
|
||||
neutral_faction = deepcopy(player_faction)
|
||||
neutral_faction.country = self.neutral_country
|
||||
self.neutral = Coalition(self, neutral_faction, 0, player=Player.NEUTRAL)
|
||||
self.blue.set_opponent(self.red)
|
||||
self.red.set_opponent(self.blue)
|
||||
|
||||
@@ -178,10 +182,10 @@ class Game:
|
||||
def point_in_world(self, x: float, y: float) -> Point:
|
||||
return Point(x, y, self.theater.terrain)
|
||||
|
||||
def ato_for(self, player: bool) -> AirTaskingOrder:
|
||||
def ato_for(self, player: Player) -> AirTaskingOrder:
|
||||
return self.coalition_for(player).ato
|
||||
|
||||
def transit_network_for(self, player: bool) -> TransitNetwork:
|
||||
def transit_network_for(self, player: Player) -> TransitNetwork:
|
||||
return self.coalition_for(player).transit_network
|
||||
|
||||
def generate_conditions(self, forced_time: time | None = None) -> Conditions:
|
||||
@@ -209,32 +213,35 @@ class Game:
|
||||
else:
|
||||
enemy_faction.country = country_with_name("Russia")
|
||||
|
||||
def faction_for(self, player: bool) -> Faction:
|
||||
def faction_for(self, player: Player) -> Faction:
|
||||
return self.coalition_for(player).faction
|
||||
|
||||
def faker_for(self, player: bool) -> Faker:
|
||||
def faker_for(self, player: Player) -> Faker:
|
||||
return self.coalition_for(player).faker
|
||||
|
||||
def air_wing_for(self, player: bool) -> AirWing:
|
||||
def air_wing_for(self, player: Player) -> AirWing:
|
||||
return self.coalition_for(player).air_wing
|
||||
|
||||
@property
|
||||
def neutral_country(self) -> Type[Country]:
|
||||
def neutral_country(self) -> Country:
|
||||
"""Return the best fitting country that can be used as neutral faction in the generated mission"""
|
||||
countries_in_use = {self.red.faction.country, self.blue.faction.country}
|
||||
if UnitedNationsPeacekeepers not in countries_in_use:
|
||||
return UnitedNationsPeacekeepers
|
||||
elif Switzerland.name not in countries_in_use:
|
||||
return Switzerland
|
||||
if UnitedNationsPeacekeepers() not in countries_in_use:
|
||||
return UnitedNationsPeacekeepers()
|
||||
elif Switzerland() not in countries_in_use:
|
||||
return Switzerland()
|
||||
else:
|
||||
return USAFAggressors
|
||||
return USAFAggressors()
|
||||
|
||||
def coalition_for(self, player: bool) -> Coalition:
|
||||
if player:
|
||||
def coalition_for(self, player: Player) -> Coalition:
|
||||
if player.is_neutral:
|
||||
return self.neutral
|
||||
elif player.is_blue:
|
||||
return self.blue
|
||||
return self.red
|
||||
else:
|
||||
return self.red
|
||||
|
||||
def adjust_budget(self, amount: float, player: bool) -> None:
|
||||
def adjust_budget(self, amount: float, player: Player) -> None:
|
||||
self.coalition_for(player).adjust_budget(amount)
|
||||
|
||||
def on_load(self, game_still_initializing: bool = False) -> None:
|
||||
@@ -489,7 +496,7 @@ class Game:
|
||||
self.current_group_id += 1
|
||||
return self.current_group_id
|
||||
|
||||
def compute_transit_network_for(self, player: bool) -> TransitNetwork:
|
||||
def compute_transit_network_for(self, player: Player) -> TransitNetwork:
|
||||
return TransitNetworkBuilder(self.theater, player).build()
|
||||
|
||||
def compute_threat_zones(self, events: GameUpdateEvents) -> None:
|
||||
@@ -498,10 +505,10 @@ class Game:
|
||||
self.blue.compute_nav_meshes(events)
|
||||
self.red.compute_nav_meshes(events)
|
||||
|
||||
def threat_zone_for(self, player: bool) -> ThreatZones:
|
||||
def threat_zone_for(self, player: Player) -> ThreatZones:
|
||||
return self.coalition_for(player).threat_zone
|
||||
|
||||
def navmesh_for(self, player: bool) -> NavMesh:
|
||||
def navmesh_for(self, player: Player) -> NavMesh:
|
||||
return self.coalition_for(player).nav_mesh
|
||||
|
||||
def compute_unculled_zones(self, events: GameUpdateEvents) -> None:
|
||||
|
||||
@@ -66,7 +66,7 @@ class GroundUnitOrders:
|
||||
bought_units: dict[GroundUnitType, int] = {}
|
||||
units_needing_transfer: dict[GroundUnitType, int] = {}
|
||||
for unit_type, count in self.units.items():
|
||||
allegiance = "Ally" if self.destination.captured else "Enemy"
|
||||
allegiance = "Ally" if self.destination.captured.is_blue else "Enemy"
|
||||
d: dict[GroundUnitType, int]
|
||||
if self.destination != ground_unit_source:
|
||||
source = ground_unit_source
|
||||
|
||||
@@ -4,6 +4,7 @@ from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from game.config import REWARDS
|
||||
from game.theater.player import Player
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@@ -22,8 +23,8 @@ class BuildingIncome:
|
||||
|
||||
|
||||
class Income:
|
||||
def __init__(self, game: Game, player: bool) -> None:
|
||||
if player:
|
||||
def __init__(self, game: Game, player: Player) -> None:
|
||||
if player.is_blue:
|
||||
self.multiplier = game.settings.player_income_multiplier
|
||||
else:
|
||||
self.multiplier = game.settings.enemy_income_multiplier
|
||||
|
||||
@@ -104,6 +104,23 @@ class AircraftGenerator:
|
||||
for parking_slot in cp.parking_slots:
|
||||
parking_slot.unit_id = None
|
||||
|
||||
def _prioritized_packages(self, ato: AirTaskingOrder) -> List[Package]:
|
||||
"""Returns the packages in the order they should be generated."""
|
||||
return sorted(
|
||||
ato.packages,
|
||||
key=lambda p: (
|
||||
(
|
||||
1
|
||||
if any(
|
||||
f.flight_type in [FlightType.AEWC, FlightType.REFUELING]
|
||||
for f in p.flights
|
||||
)
|
||||
else 0
|
||||
),
|
||||
p.time_over_target,
|
||||
),
|
||||
)
|
||||
|
||||
def generate_flights(
|
||||
self,
|
||||
country: Country,
|
||||
@@ -124,7 +141,7 @@ class AircraftGenerator:
|
||||
self._reserve_frequencies_and_tacan(ato)
|
||||
self.mission_data.packages.clear()
|
||||
|
||||
for package in reversed(sorted(ato.packages, key=lambda x: x.time_over_target)):
|
||||
for package in reversed(self._prioritized_packages(ato)):
|
||||
logging.info(f"Generating package for target: {package.target.name}")
|
||||
if not package.flights:
|
||||
continue
|
||||
@@ -203,7 +220,7 @@ class AircraftGenerator:
|
||||
):
|
||||
continue
|
||||
|
||||
if control_point.captured:
|
||||
if control_point.captured.is_blue:
|
||||
country = player_country
|
||||
else:
|
||||
country = enemy_country
|
||||
@@ -220,12 +237,12 @@ class AircraftGenerator:
|
||||
squadron.location, Fob
|
||||
)
|
||||
if (
|
||||
squadron.coalition.player
|
||||
squadron.coalition.player.is_blue
|
||||
and self.game.settings.perf_disable_untasked_blufor_aircraft
|
||||
):
|
||||
return
|
||||
elif (
|
||||
not squadron.coalition.player
|
||||
squadron.coalition.player.is_red
|
||||
and self.game.settings.perf_disable_untasked_opfor_aircraft
|
||||
):
|
||||
return
|
||||
@@ -257,7 +274,7 @@ class AircraftGenerator:
|
||||
).create_idle_aircraft()
|
||||
if group:
|
||||
if (
|
||||
not squadron.coalition.player
|
||||
squadron.coalition.player.is_red
|
||||
and squadron.aircraft.flyable
|
||||
and (
|
||||
self.game.settings.enable_squadron_pilot_limits
|
||||
@@ -366,7 +383,9 @@ class AircraftGenerator:
|
||||
and (
|
||||
not self.need_ecm
|
||||
or flight.any_member_has_weapon_of_type(WeaponType.JAMMER)
|
||||
or flight.any_member_has_weapon_of_type(WeaponType.OFFENSIVE_JAMMER)
|
||||
or flight.squadron.aircraft.has_built_in_ecm
|
||||
or flight.squadron.aircraft.has_built_in_jamming
|
||||
)
|
||||
):
|
||||
self.ewrj_package_dict[id(flight.package)].append(group)
|
||||
|
||||
@@ -14,6 +14,7 @@ if TYPE_CHECKING:
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.radio.radios import RadioFrequency
|
||||
from game.runways import RunwayData
|
||||
from game.theater.player import Player
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -42,7 +43,7 @@ class FlightData:
|
||||
size: int
|
||||
|
||||
#: True if this flight belongs to the player's coalition.
|
||||
friendly: bool
|
||||
friendly: Player
|
||||
|
||||
#: Number of seconds after mission start the flight is set to depart.
|
||||
departure_delay: timedelta
|
||||
|
||||
@@ -189,8 +189,17 @@ class FlightGroupConfigurator:
|
||||
return
|
||||
# Check if ecm_required option is enabled
|
||||
jammer_required = settings.plugin_option("ewrj.ecm_required")
|
||||
has_jammer = member.loadout.has_weapon_of_type(WeaponType.JAMMER)
|
||||
if jammer_required and not has_jammer:
|
||||
offensive_jammer = member.loadout.has_weapon_of_type(
|
||||
WeaponType.OFFENSIVE_JAMMER
|
||||
)
|
||||
offensive_inbuilt = self.flight.squadron.aircraft.has_built_in_jamming
|
||||
has_jammer = (
|
||||
member.loadout.has_weapon_of_type(WeaponType.JAMMER) or offensive_jammer
|
||||
)
|
||||
built_in_jammer = (
|
||||
self.flight.squadron.aircraft.has_built_in_ecm or offensive_inbuilt
|
||||
)
|
||||
if jammer_required and not (has_jammer or built_in_jammer):
|
||||
return
|
||||
# Create the original ewrj_menu_trigger for player flight members
|
||||
ewrj_menu_trigger = TriggerStart(comment=f"EWRJ-{unit.name}")
|
||||
@@ -199,6 +208,20 @@ class FlightGroupConfigurator:
|
||||
self.group.points[0].tasks[0] = OptReactOnThreat(
|
||||
OptReactOnThreat.Values.PassiveDefense
|
||||
)
|
||||
# Create LUA Flags for Offensive Jamming in EW Script for Player Flights
|
||||
if not (offensive_jammer or offensive_inbuilt):
|
||||
return
|
||||
ewrj_offensive_trigger = TriggerStart(
|
||||
comment=f"Offensive Jammer Flag {unit.name}"
|
||||
)
|
||||
ewrj_offensive_trigger.add_action(
|
||||
DoScript(
|
||||
String(
|
||||
f'trigger.action.setUserFlag("offensive_jamming_{unit.name}", 1)'
|
||||
)
|
||||
)
|
||||
)
|
||||
self.mission.triggerrules.triggers.append(ewrj_offensive_trigger)
|
||||
|
||||
def setup_radios(self) -> RadioFrequency:
|
||||
freq = self.flight.frequency
|
||||
@@ -276,7 +299,7 @@ class FlightGroupConfigurator:
|
||||
unit.set_player()
|
||||
|
||||
def skill_level_for(self, unit: FlyingUnit, pilot: Optional[Pilot]) -> Skill:
|
||||
if self.flight.squadron.player:
|
||||
if self.flight.squadron.player.is_blue:
|
||||
base_skill = Skill(self.game.settings.player_skill)
|
||||
else:
|
||||
base_skill = Skill(self.game.settings.enemy_skill)
|
||||
|
||||
@@ -60,6 +60,7 @@ class JoinPointBuilder(PydcsWaypointBuilder):
|
||||
FlightType.SEAD_SWEEP,
|
||||
FlightType.SEAD,
|
||||
FlightType.SEAD_ESCORT,
|
||||
FlightType.DEAD,
|
||||
]:
|
||||
settings = self.flight.coalition.game.settings
|
||||
ai_jammer = settings.plugin_option("ewrj.ai_jammer_enabled")
|
||||
|
||||
@@ -164,12 +164,17 @@ class PydcsWaypointBuilder:
|
||||
settings = self.flight.coalition.game.settings
|
||||
ecm_required = settings.plugin_option("ewrj.ecm_required")
|
||||
for unit, member in zip(self.group.units, self.flight.iter_members()):
|
||||
has_jammer = member.loadout.has_weapon_of_type(WeaponType.JAMMER)
|
||||
built_in_jammer = self.flight.squadron.aircraft.has_built_in_ecm
|
||||
has_jammer = member.loadout.has_weapon_of_type(
|
||||
WeaponType.JAMMER
|
||||
) or member.loadout.has_weapon_of_type(WeaponType.OFFENSIVE_JAMMER)
|
||||
built_in_jammer = (
|
||||
self.flight.squadron.aircraft.has_built_in_ecm
|
||||
or self.flight.squadron.aircraft.has_built_in_jamming
|
||||
)
|
||||
if ecm_required and not (has_jammer or built_in_jammer):
|
||||
continue
|
||||
if not member.is_player:
|
||||
script_content = f'{action}Djamming("{unit.name}")'
|
||||
script_content = f'{action}IAdefjamming("{unit.name}")'
|
||||
jamming_script = RunScript(script_content)
|
||||
waypoint.tasks.append(jamming_script)
|
||||
|
||||
@@ -178,8 +183,8 @@ class PydcsWaypointBuilder:
|
||||
settings = self.flight.coalition.game.settings
|
||||
ecm_required = settings.plugin_option("ewrj.ecm_required")
|
||||
for unit, member in zip(self.group.units, self.flight.iter_members()):
|
||||
has_jammer = member.loadout.has_weapon_of_type(WeaponType.JAMMER)
|
||||
built_in_jammer = self.flight.squadron.aircraft.has_built_in_ecm
|
||||
has_jammer = member.loadout.has_weapon_of_type(WeaponType.OFFENSIVE_JAMMER)
|
||||
built_in_jammer = self.flight.squadron.aircraft.has_built_in_jamming
|
||||
if ecm_required and not (has_jammer or built_in_jammer):
|
||||
continue
|
||||
if not member.is_player:
|
||||
|
||||
@@ -43,6 +43,7 @@ class RaceTrackBuilder(PydcsWaypointBuilder):
|
||||
ai_jammer = settings.plugin_option("ewrj.ai_jammer_enabled")
|
||||
if settings.plugins.get("ewrj") and ai_jammer:
|
||||
self.defensive_jamming(waypoint, "start")
|
||||
self.offensive_jamming(waypoint, "start")
|
||||
|
||||
# NB: It's important that the engage task comes before the orbit task.
|
||||
# Though they're on the same waypoint, if the orbit task comes first it
|
||||
|
||||
@@ -23,6 +23,7 @@ class RaceTrackEndBuilder(PydcsWaypointBuilder):
|
||||
ai_jammer = settings.plugin_option("ewrj.ai_jammer_enabled")
|
||||
if settings.plugins.get("ewrj") and ai_jammer:
|
||||
self.defensive_jamming(waypoint, "stop")
|
||||
self.offensive_jamming(waypoint, "stop")
|
||||
|
||||
def build(self) -> MovingPoint:
|
||||
waypoint = super().build()
|
||||
|
||||
@@ -62,6 +62,7 @@ class SeadIngressBuilder(PydcsWaypointBuilder):
|
||||
# into the SAM instead of waiting for it to come alive
|
||||
engage_task = EngageGroup(miz_group.id)
|
||||
engage_task.params["weaponType"] = DcsWeaponType.ARM.value
|
||||
engage_task.params["expend"] = Expend.All.value
|
||||
waypoint.tasks.append(engage_task)
|
||||
|
||||
# Use other Air-to-Surface Missiles at last
|
||||
|
||||
@@ -47,6 +47,7 @@ class SplitPointBuilder(PydcsWaypointBuilder):
|
||||
FlightType.SEAD_SWEEP,
|
||||
FlightType.SEAD,
|
||||
FlightType.SEAD_ESCORT,
|
||||
FlightType.DEAD,
|
||||
]:
|
||||
if self.flight.flight_type == FlightType.SEAD_ESCORT:
|
||||
# Moved previous escort split tasks
|
||||
|
||||
@@ -17,8 +17,8 @@ from game.radio.radios import RadioFrequency
|
||||
from game.runways import RunwayData
|
||||
from game.theater import ControlPoint, FrontLine
|
||||
from .aircraft.flightdata import FlightData
|
||||
from .missiondata import AwacsInfo, TankerInfo
|
||||
from .flotgenerator import JtacInfo
|
||||
from .missiondata import AwacsInfo, TankerInfo
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@@ -182,7 +182,7 @@ class BriefingGenerator(MissionInfoGenerator):
|
||||
def generate_allied_flights_by_departure(self) -> None:
|
||||
"""Create iterable to display allied flights grouped by departure airfield."""
|
||||
for flight in self.flights:
|
||||
if not flight.client_units and flight.friendly:
|
||||
if not flight.client_units and flight.friendly.is_blue:
|
||||
name = flight.departure.airfield_name
|
||||
if (
|
||||
name in self.allied_flights_by_departure
|
||||
|
||||
@@ -18,6 +18,7 @@ from game.utils import kph
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.theater.player import Player
|
||||
|
||||
|
||||
class ConvoyGenerator:
|
||||
@@ -94,7 +95,7 @@ class ConvoyGenerator:
|
||||
name: str,
|
||||
position: Point,
|
||||
units: dict[GroundUnitType, int],
|
||||
for_player: bool,
|
||||
for_player: Player,
|
||||
) -> VehicleGroup:
|
||||
unit_types = list(units.items())
|
||||
main_unit_type, main_unit_count = unit_types[0]
|
||||
|
||||
@@ -15,6 +15,7 @@ FRONTLINE_COLORS = Rgba(255, 0, 0, 255)
|
||||
WHITE = Rgba(255, 255, 255, 255)
|
||||
CP_RED = Rgba(255, 0, 0, 80)
|
||||
CP_BLUE = Rgba(0, 0, 255, 80)
|
||||
CP_NEUTRAL = Rgba(128, 128, 128, 80)
|
||||
BLUE_PATH_COLOR = Rgba(0, 0, 255, 100)
|
||||
RED_PATH_COLOR = Rgba(255, 0, 0, 100)
|
||||
ACTIVE_PATH_COLOR = Rgba(255, 80, 80, 100)
|
||||
@@ -35,10 +36,12 @@ class DrawingsGenerator:
|
||||
Generate cps as circles
|
||||
"""
|
||||
for cp in self.game.theater.controlpoints:
|
||||
if cp.captured:
|
||||
if cp.captured.is_blue:
|
||||
color = CP_BLUE
|
||||
else:
|
||||
elif cp.captured.is_red:
|
||||
color = CP_RED
|
||||
else:
|
||||
color = CP_NEUTRAL
|
||||
shape = self.player_layer.add_circle(
|
||||
cp.position,
|
||||
TRIGGER_RADIUS_CAPTURE,
|
||||
@@ -61,9 +64,9 @@ class DrawingsGenerator:
|
||||
continue
|
||||
else:
|
||||
# Determine path color
|
||||
if cp.captured and destination.captured:
|
||||
if cp.captured.is_blue and destination.captured.is_blue:
|
||||
color = BLUE_PATH_COLOR
|
||||
elif not cp.captured and not destination.captured:
|
||||
elif cp.captured.is_red and destination.captured.is_red:
|
||||
color = RED_PATH_COLOR
|
||||
else:
|
||||
color = ACTIVE_PATH_COLOR
|
||||
|
||||
@@ -40,7 +40,7 @@ from game.ground_forces.ai_ground_planner import (
|
||||
from game.ground_forces.combat_stance import CombatStance
|
||||
from game.naming import namegen
|
||||
from game.radio.radios import RadioRegistry
|
||||
from game.theater.controlpoint import ControlPoint
|
||||
from game.theater.controlpoint import ControlPoint, Player
|
||||
from game.unitmap import UnitMap
|
||||
from game.utils import Heading
|
||||
from .frontlineconflictdescription import FrontLineConflictDescription
|
||||
@@ -101,12 +101,12 @@ class FlotGenerator:
|
||||
|
||||
# Create player groups at random position
|
||||
player_groups = self._generate_groups(
|
||||
self.player_planned_combat_groups, is_player=True
|
||||
self.player_planned_combat_groups, is_player=Player.BLUE
|
||||
)
|
||||
|
||||
# Create enemy groups at random position
|
||||
enemy_groups = self._generate_groups(
|
||||
self.enemy_planned_combat_groups, is_player=False
|
||||
self.enemy_planned_combat_groups, is_player=Player.RED
|
||||
)
|
||||
|
||||
# TODO: Differentiate AirConflict and GroundConflict classes.
|
||||
@@ -193,7 +193,7 @@ class FlotGenerator:
|
||||
callsign=callsign,
|
||||
region=frontline,
|
||||
code=str(code),
|
||||
blue=True,
|
||||
blue=Player.BLUE,
|
||||
freq=freq,
|
||||
)
|
||||
)
|
||||
@@ -215,7 +215,7 @@ class FlotGenerator:
|
||||
def gen_infantry_group_for_group(
|
||||
self,
|
||||
group: VehicleGroup,
|
||||
is_player: bool,
|
||||
is_player: Player,
|
||||
side: Country,
|
||||
forward_heading: Heading,
|
||||
) -> None:
|
||||
@@ -294,7 +294,7 @@ class FlotGenerator:
|
||||
GroundForcePainter(faction, vehicle).apply_livery()
|
||||
vg.hidden_on_mfd = True
|
||||
|
||||
def _earliest_tot_on_flot(self, player: bool) -> timedelta:
|
||||
def _earliest_tot_on_flot(self, player: Player) -> timedelta:
|
||||
tots = [
|
||||
x.time_over_target
|
||||
for x in self.game.ato_for(player).packages
|
||||
@@ -413,7 +413,7 @@ class FlotGenerator:
|
||||
"""
|
||||
duration = timedelta()
|
||||
if stance in [CombatStance.DEFENSIVE, CombatStance.AGGRESSIVE]:
|
||||
duration = self._earliest_tot_on_flot(not to_cp.coalition.player)
|
||||
duration = self._earliest_tot_on_flot(to_cp.coalition.player.opponent)
|
||||
self._set_reform_waypoint(dcs_group, forward_heading, duration)
|
||||
if stance == CombatStance.AGGRESSIVE:
|
||||
# Attack nearest enemy if any
|
||||
@@ -503,7 +503,7 @@ class FlotGenerator:
|
||||
"""
|
||||
duration = timedelta()
|
||||
if stance in [CombatStance.DEFENSIVE, CombatStance.AGGRESSIVE]:
|
||||
duration = self._earliest_tot_on_flot(not to_cp.coalition.player)
|
||||
duration = self._earliest_tot_on_flot(to_cp.coalition.player.opponent)
|
||||
self._set_reform_waypoint(dcs_group, forward_heading, duration)
|
||||
if stance in [
|
||||
CombatStance.AGGRESSIVE,
|
||||
@@ -762,13 +762,15 @@ class FlotGenerator:
|
||||
)
|
||||
|
||||
def _generate_groups(
|
||||
self, groups: list[CombatGroup], is_player: bool
|
||||
self, groups: list[CombatGroup], is_player: Player
|
||||
) -> List[Tuple[VehicleGroup, CombatGroup]]:
|
||||
"""Finds valid positions for planned groups and generates a pydcs group for them"""
|
||||
positioned_groups = []
|
||||
assert self.conflict.heading is not None
|
||||
spawn_heading = (
|
||||
self.conflict.heading.left if is_player else self.conflict.heading.right
|
||||
self.conflict.heading.left
|
||||
if is_player.is_blue
|
||||
else self.conflict.heading.right
|
||||
)
|
||||
country = self.game.coalition_for(is_player).faction.country
|
||||
country = self.mission.country(country.name)
|
||||
@@ -795,7 +797,7 @@ class FlotGenerator:
|
||||
final_position,
|
||||
heading=spawn_heading.opposite,
|
||||
)
|
||||
if is_player:
|
||||
if is_player == Player.BLUE:
|
||||
g.set_skill(Skill(self.game.settings.player_skill))
|
||||
else:
|
||||
g.set_skill(Skill(self.game.settings.enemy_vehicle_skill))
|
||||
@@ -813,7 +815,7 @@ class FlotGenerator:
|
||||
|
||||
def _generate_group(
|
||||
self,
|
||||
player: bool,
|
||||
player: Player,
|
||||
side: Country,
|
||||
unit_type: GroundUnitType,
|
||||
count: int,
|
||||
|
||||
@@ -10,15 +10,14 @@ from dcs import Mission
|
||||
from dcs.action import DoScript, DoScriptFile
|
||||
from dcs.translation import String
|
||||
from dcs.triggers import TriggerStart
|
||||
from dcs.unit import Skill
|
||||
|
||||
from game.ato import FlightType
|
||||
from game.data.units import UnitClass
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.plugins import LuaPluginManager
|
||||
from game.theater import TheaterGroundObject
|
||||
from game.theater.iadsnetwork.iadsrole import IadsRole
|
||||
from game.utils import escape_string_for_lua
|
||||
from game.data.units import UnitClass
|
||||
from .missiondata import MissionData
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -102,13 +101,15 @@ class LuaGenerator:
|
||||
for logistic_info in self.mission_data.logistics:
|
||||
if logistic_info.transport not in transports:
|
||||
transports.append(logistic_info.transport)
|
||||
coalition_color = "blue" if logistic_info.blue else "red"
|
||||
coalition_color = "blue" if logistic_info.blue.is_blue else "red"
|
||||
logistics_item = logistics_flights.add_item()
|
||||
logistics_item.add_data_array("pilot_names", logistic_info.pilot_names)
|
||||
logistics_item.add_key_value("pickup_zone", logistic_info.pickup_zone)
|
||||
logistics_item.add_key_value("drop_off_zone", logistic_info.drop_off_zone)
|
||||
logistics_item.add_key_value("target_zone", logistic_info.target_zone)
|
||||
logistics_item.add_key_value("side", str(2 if logistic_info.blue else 1))
|
||||
logistics_item.add_key_value(
|
||||
"side", str(2 if logistic_info.blue.is_blue else 1)
|
||||
)
|
||||
logistics_item.add_key_value("logistic_unit", logistic_info.logistic_unit)
|
||||
logistics_item.add_key_value(
|
||||
"aircraft_type", logistic_info.transport.dcs_id
|
||||
@@ -144,7 +145,7 @@ class LuaGenerator:
|
||||
|
||||
target_points = lua_data.add_item("TargetPoints")
|
||||
for flight in self.mission_data.flights:
|
||||
if flight.friendly and flight.flight_type in [
|
||||
if flight.friendly.is_blue and flight.flight_type in [
|
||||
FlightType.ANTISHIP,
|
||||
FlightType.DEAD,
|
||||
FlightType.SEAD,
|
||||
@@ -178,7 +179,7 @@ class LuaGenerator:
|
||||
for cp in self.game.theater.controlpoints:
|
||||
coalition_object = (
|
||||
lua_data.get_or_create_item("BlueAA")
|
||||
if cp.captured
|
||||
if cp.captured.is_blue
|
||||
else lua_data.get_or_create_item("RedAA")
|
||||
)
|
||||
for ground_object in cp.ground_objects:
|
||||
@@ -202,7 +203,9 @@ class LuaGenerator:
|
||||
# Should probably do the same with all the roles... but the script is already
|
||||
# tolerant of those being empty.
|
||||
for node in self.game.theater.iads_network.skynet_nodes(self.game):
|
||||
coalition = iads_object.get_or_create_item("BLUE" if node.player else "RED")
|
||||
coalition = iads_object.get_or_create_item(
|
||||
"BLUE" if node.player.is_blue else "RED"
|
||||
)
|
||||
iads_type = coalition.get_or_create_item(node.iads_role.value)
|
||||
iads_element = iads_type.add_item()
|
||||
iads_element.add_key_value("dcsGroupName", node.dcs_name)
|
||||
|
||||
@@ -15,6 +15,7 @@ from game.runways import RunwayData
|
||||
if TYPE_CHECKING:
|
||||
from game.radio.radios import RadioFrequency
|
||||
from game.radio.tacan import TacanChannel
|
||||
from game.theater.player import Player
|
||||
from game.utils import Distance
|
||||
from uuid import UUID
|
||||
|
||||
@@ -24,7 +25,7 @@ class GroupInfo:
|
||||
group_name: str
|
||||
callsign: str
|
||||
freq: RadioFrequency
|
||||
blue: bool
|
||||
blue: Player
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -85,7 +86,7 @@ class LogisticsInfo:
|
||||
|
||||
pilot_names: list[str]
|
||||
transport: AircraftType
|
||||
blue: bool
|
||||
blue: Player
|
||||
|
||||
logistic_unit: str = field(default_factory=str)
|
||||
pickup_zone: str = field(default_factory=str)
|
||||
|
||||
@@ -391,9 +391,12 @@ class MissionGenerator:
|
||||
tmu.theater_unit.position,
|
||||
self.mission.terrain,
|
||||
).dict()
|
||||
warehouse["coalition"] = (
|
||||
"blue" if tmu.theater_unit.ground_object.coalition.player else "red"
|
||||
)
|
||||
if tmu.theater_unit.ground_object.coalition.player.is_neutral:
|
||||
warehouse["coalition"] = "neutral"
|
||||
elif tmu.theater_unit.ground_object.coalition.player.is_blue:
|
||||
warehouse["coalition"] = "blue"
|
||||
else:
|
||||
warehouse["coalition"] = "red"
|
||||
warehouse["dynamicCargo"] = settings.dynamic_cargo
|
||||
if tmu.theater_unit.is_ship or tmu.dcs_unit.category == "Heliports": # type: ignore
|
||||
warehouse["dynamicSpawn"] = settings.dynamic_slots
|
||||
|
||||
@@ -13,6 +13,7 @@ from dcs.vehicles import vehicle_map
|
||||
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.naming import namegen
|
||||
from game.theater import Player
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@@ -25,12 +26,12 @@ class RebellionGenerator:
|
||||
|
||||
def generate(self) -> None:
|
||||
ownfor_country = self.mission.country(
|
||||
self.game.coalition_for(player=True).faction.country.name
|
||||
self.game.coalition_for(player=Player.BLUE).faction.country.name
|
||||
)
|
||||
for rz in self.game.theater.ownfor_rebel_zones:
|
||||
self._generate_rebel_zone(ownfor_country, rz)
|
||||
opfor_country = self.mission.country(
|
||||
self.game.coalition_for(player=False).faction.country.name
|
||||
self.game.coalition_for(player=Player.RED).faction.country.name
|
||||
)
|
||||
for rz in self.game.theater.opfor_rebel_zones:
|
||||
self._generate_rebel_zone(opfor_country, rz)
|
||||
|
||||
@@ -67,6 +67,7 @@ from game.radio.tacan import TacanBand, TacanChannel, TacanRegistry, TacanUsage
|
||||
from game.runways import RunwayData
|
||||
from game.theater import (
|
||||
ControlPoint,
|
||||
Player,
|
||||
TheaterGroundObject,
|
||||
TheaterUnit,
|
||||
NavalControlPoint,
|
||||
@@ -408,7 +409,7 @@ class GroundObjectGenerator:
|
||||
# Align the trigger zones to the faction color on the DCS briefing/F10 map.
|
||||
color = (
|
||||
{1: 0.2, 2: 0.7, 3: 1, 4: 0.15}
|
||||
if scenery.ground_object.is_friendly(to_player=True)
|
||||
if scenery.ground_object.is_friendly(to_player=Player.BLUE)
|
||||
else {1: 1, 2: 0.2, 3: 0.2, 4: 0.15}
|
||||
)
|
||||
|
||||
@@ -809,9 +810,12 @@ class HelipadGenerator:
|
||||
# capture triggers
|
||||
pad: BaseFARP
|
||||
neutral_country = self.m.country(self.game.neutral_country.name)
|
||||
country = self.m.country(
|
||||
self.game.coalition_for(self.cp.captured).faction.country.name
|
||||
)
|
||||
if self.cp.captured is Player.NEUTRAL:
|
||||
country = neutral_country
|
||||
else:
|
||||
country = self.m.country(
|
||||
self.game.coalition_for(self.cp.captured).faction.country.name
|
||||
)
|
||||
|
||||
name = f"{self.cp.name} {helipad_type} {i}"
|
||||
logging.info("Generating helipad static : " + name)
|
||||
@@ -862,7 +866,7 @@ class HelipadGenerator:
|
||||
|
||||
if self.game.position_culled(helipad):
|
||||
cull_farp_statics = True
|
||||
if self.cp.coalition.player:
|
||||
if self.cp.coalition.player.is_blue:
|
||||
for package in self.cp.coalition.ato.packages:
|
||||
for flight in package.flights:
|
||||
if flight.squadron.location == self.cp:
|
||||
@@ -878,7 +882,12 @@ class HelipadGenerator:
|
||||
pad.position,
|
||||
self.m.terrain,
|
||||
).dict()
|
||||
warehouse["coalition"] = "blue" if self.cp.coalition.player else "red"
|
||||
if self.cp.coalition.player.is_neutral:
|
||||
warehouse["coalition"] = "neutral"
|
||||
elif self.cp.coalition.player.is_blue:
|
||||
warehouse["coalition"] = "blue"
|
||||
else:
|
||||
warehouse["coalition"] = "red"
|
||||
# configure dynamic spawn + hot start of DS, plus dynamic cargo?
|
||||
self.m.warehouses.warehouses[pad.id] = warehouse
|
||||
|
||||
@@ -989,7 +998,7 @@ class GroundSpawnRoadbaseGenerator:
|
||||
cull_farp_statics = True
|
||||
elif self.game.position_culled(ground_spawn[0]):
|
||||
cull_farp_statics = True
|
||||
if self.cp.coalition.player:
|
||||
if self.cp.coalition.player.is_blue:
|
||||
for package in self.cp.coalition.ato.packages:
|
||||
for flight in package.flights:
|
||||
if flight.squadron.location == self.cp:
|
||||
@@ -1005,7 +1014,12 @@ class GroundSpawnRoadbaseGenerator:
|
||||
pad.position,
|
||||
self.m.terrain,
|
||||
).dict()
|
||||
warehouse["coalition"] = "blue" if self.cp.coalition.player else "red"
|
||||
if self.cp.coalition.player.is_neutral:
|
||||
warehouse["coalition"] = "neutral"
|
||||
elif self.cp.coalition.player.is_blue:
|
||||
warehouse["coalition"] = "blue"
|
||||
else:
|
||||
warehouse["coalition"] = "red"
|
||||
# configure dynamic spawn + hot start of DS, plus dynamic cargo?
|
||||
self.m.warehouses.warehouses[pad.id] = warehouse
|
||||
|
||||
@@ -1131,7 +1145,12 @@ class GroundSpawnLargeGenerator:
|
||||
pad.position,
|
||||
self.m.terrain,
|
||||
).dict()
|
||||
warehouse["coalition"] = "blue" if self.cp.coalition.player else "red"
|
||||
if self.cp.coalition.player.is_neutral:
|
||||
warehouse["coalition"] = "neutral"
|
||||
elif self.cp.coalition.player.is_blue:
|
||||
warehouse["coalition"] = "blue"
|
||||
else:
|
||||
warehouse["coalition"] = "red"
|
||||
# configure dynamic spawn + hot start of DS, plus dynamic cargo?
|
||||
self.m.warehouses.warehouses[pad.id] = warehouse
|
||||
|
||||
@@ -1258,7 +1277,7 @@ class GroundSpawnGenerator:
|
||||
cull_farp_statics = True
|
||||
elif self.game.position_culled(vtol_pad[0]):
|
||||
cull_farp_statics = True
|
||||
if self.cp.coalition.player:
|
||||
if self.cp.coalition.player.is_blue:
|
||||
for package in self.cp.coalition.ato.packages:
|
||||
for flight in package.flights:
|
||||
if flight.squadron.location == self.cp:
|
||||
@@ -1275,7 +1294,12 @@ class GroundSpawnGenerator:
|
||||
pad.position,
|
||||
self.m.terrain,
|
||||
).dict()
|
||||
warehouse["coalition"] = "blue" if self.cp.coalition.player else "red"
|
||||
if self.cp.coalition.player.is_neutral:
|
||||
warehouse["coalition"] = "neutral"
|
||||
elif self.cp.coalition.player.is_blue:
|
||||
warehouse["coalition"] = "blue"
|
||||
else:
|
||||
warehouse["coalition"] = "red"
|
||||
# configure dynamic spawn + hot start of DS, plus dynamic cargo?
|
||||
self.m.warehouses.warehouses[pad.id] = warehouse
|
||||
|
||||
@@ -1382,7 +1406,11 @@ class TgoGenerator:
|
||||
|
||||
def generate(self) -> None:
|
||||
for cp in self.game.theater.controlpoints:
|
||||
country = self.m.country(cp.coalition.faction.country.name)
|
||||
# Use neutral country for neutral control points
|
||||
if cp.captured is Player.NEUTRAL:
|
||||
country = self.m.country(self.game.neutral_country.name)
|
||||
else:
|
||||
country = self.m.country(cp.coalition.faction.country.name)
|
||||
|
||||
# Generate helipads
|
||||
helipad_gen = HelipadGenerator(
|
||||
|
||||
@@ -12,7 +12,6 @@ from dcs.action import (
|
||||
RemoveSceneObjects,
|
||||
RemoveSceneObjectsMask,
|
||||
SceneryDestructionZone,
|
||||
Smoke,
|
||||
)
|
||||
from dcs.condition import (
|
||||
AllOfCoalitionOutsideZone,
|
||||
@@ -33,6 +32,7 @@ from game.theater.controlpoint import Fob, TRIGGER_RADIUS_CAPTURE
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.game import Game
|
||||
from game.theater.controlpoint import ControlPoint
|
||||
|
||||
PUSH_TRIGGER_SIZE = 3000
|
||||
PUSH_TRIGGER_ACTIVATION_AGL = 25
|
||||
@@ -99,9 +99,12 @@ class TriggerGenerator:
|
||||
raise RuntimeError(
|
||||
f"Could not find {airfield.airport.name} in the mission"
|
||||
)
|
||||
cp_airport.set_coalition(
|
||||
airfield.captured and player_coalition or enemy_coalition
|
||||
)
|
||||
if airfield.captured.is_neutral:
|
||||
cp_airport.set_coalition("neutral")
|
||||
elif airfield.captured.is_blue:
|
||||
cp_airport.set_coalition(player_coalition)
|
||||
elif airfield.captured.is_red:
|
||||
cp_airport.set_coalition(enemy_coalition)
|
||||
|
||||
def _set_skill(self, player_coalition: str, enemy_coalition: str) -> None:
|
||||
"""
|
||||
@@ -138,7 +141,7 @@ class TriggerGenerator:
|
||||
zone = self.mission.triggers.add_triggerzone(
|
||||
location, radius=10, hidden=True, name="MARK"
|
||||
)
|
||||
if cp.captured:
|
||||
if cp.captured.is_blue:
|
||||
name = ground_object.obj_name + " [ALLY]"
|
||||
else:
|
||||
name = ground_object.obj_name + " [ENEMY]"
|
||||
@@ -177,26 +180,57 @@ class TriggerGenerator:
|
||||
# clear_trigger.add_action(MessageToAll(text=String("Enable clear trigger"),))
|
||||
self.mission.triggerrules.triggers.append(enable_clear_trigger)
|
||||
|
||||
def _generate_capture_triggers(
|
||||
self, player_coalition: str, enemy_coalition: str
|
||||
) -> None:
|
||||
def _create_capture_trigger(
|
||||
self,
|
||||
trigger_zone_id: int,
|
||||
flag: int,
|
||||
capturing_coalition: str,
|
||||
losing_coalition: str,
|
||||
capturing_coalition_int: int,
|
||||
cp: ControlPoint,
|
||||
flag_condition_true: bool = False,
|
||||
) -> TriggerCondition:
|
||||
"""Helper method to create a single capture trigger with the given parameters."""
|
||||
trigger = TriggerCondition(Event.NoEvent, "Capture Trigger")
|
||||
trigger.add_condition(
|
||||
AllOfCoalitionOutsideZone(
|
||||
losing_coalition, trigger_zone_id, unit_type="GROUND"
|
||||
)
|
||||
)
|
||||
trigger.add_condition(
|
||||
PartOfCoalitionInZone(
|
||||
capturing_coalition, trigger_zone_id, unit_type="GROUND"
|
||||
)
|
||||
)
|
||||
|
||||
if flag_condition_true:
|
||||
trigger.add_condition(FlagIsTrue(flag=flag))
|
||||
trigger.add_action(ClearFlag(flag=flag))
|
||||
else:
|
||||
trigger.add_condition(FlagIsFalse(flag=flag))
|
||||
trigger.add_action(SetFlag(flag=flag))
|
||||
|
||||
script_string = String(
|
||||
f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{capturing_coalition_int}||{cp.full_name}"'
|
||||
)
|
||||
trigger.add_action(DoScript(script_string))
|
||||
return trigger
|
||||
|
||||
def _generate_capture_triggers(self) -> None:
|
||||
"""Creates a pair of triggers for each control point of `cls.capture_zone_types`.
|
||||
One for the initial capture of a control point, and one if it is recaptured.
|
||||
Directly appends to the global `base_capture_events` var declared by `dcs_libaration.lua`
|
||||
"""
|
||||
for cp in self.game.theater.controlpoints:
|
||||
attacking_coalition = str.lower(cp.captured.opponent.name)
|
||||
defending_coalition = str.lower(cp.captured.opponent.opponent.name)
|
||||
if attacking_coalition == "red":
|
||||
attack_coalition_int = 1 # 1 is the Event int for Red
|
||||
defend_coalition_int = 2 # 2 is the Event int for Blue
|
||||
else:
|
||||
attack_coalition_int = 2
|
||||
defend_coalition_int = 1
|
||||
if isinstance(cp, self.capture_zone_types) and not cp.is_carrier:
|
||||
if cp.captured:
|
||||
attacking_coalition = enemy_coalition
|
||||
attack_coalition_int = 1 # 1 is the Event int for Red
|
||||
defending_coalition = player_coalition
|
||||
defend_coalition_int = 2 # 2 is the Event int for Blue
|
||||
else:
|
||||
attacking_coalition = player_coalition
|
||||
attack_coalition_int = 2
|
||||
defending_coalition = enemy_coalition
|
||||
defend_coalition_int = 1
|
||||
|
||||
trigger_zone = self.mission.triggers.add_triggerzone(
|
||||
cp.position,
|
||||
radius=TRIGGER_RADIUS_CAPTURE,
|
||||
@@ -204,43 +238,48 @@ class TriggerGenerator:
|
||||
name="CAPTURE",
|
||||
)
|
||||
flag = self.get_capture_zone_flag()
|
||||
capture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger")
|
||||
capture_trigger.add_condition(
|
||||
AllOfCoalitionOutsideZone(
|
||||
defending_coalition, trigger_zone.id, unit_type="GROUND"
|
||||
)
|
||||
capture = self._create_capture_trigger(
|
||||
trigger_zone.id,
|
||||
flag,
|
||||
attacking_coalition,
|
||||
defending_coalition,
|
||||
attack_coalition_int,
|
||||
cp,
|
||||
)
|
||||
capture_trigger.add_condition(
|
||||
PartOfCoalitionInZone(
|
||||
attacking_coalition, trigger_zone.id, unit_type="GROUND"
|
||||
)
|
||||
recapture = self._create_capture_trigger(
|
||||
trigger_zone.id,
|
||||
flag,
|
||||
defending_coalition,
|
||||
attacking_coalition,
|
||||
defend_coalition_int,
|
||||
cp,
|
||||
flag_condition_true=True,
|
||||
)
|
||||
capture_trigger.add_condition(FlagIsFalse(flag=flag))
|
||||
script_string = String(
|
||||
f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{attack_coalition_int}||{cp.full_name}"'
|
||||
)
|
||||
capture_trigger.add_action(DoScript(script_string))
|
||||
capture_trigger.add_action(SetFlag(flag=flag))
|
||||
self.mission.triggerrules.triggers.append(capture_trigger)
|
||||
self.mission.triggerrules.triggers.extend([capture, recapture])
|
||||
|
||||
recapture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger")
|
||||
recapture_trigger.add_condition(
|
||||
AllOfCoalitionOutsideZone(
|
||||
attacking_coalition, trigger_zone.id, unit_type="GROUND"
|
||||
if cp.captured.is_neutral:
|
||||
# In this case attacking_coalition is blue and defending_coalition is red because
|
||||
# neutral control points always have blue set as the opponent
|
||||
red_capture = self._create_capture_trigger(
|
||||
trigger_zone.id,
|
||||
flag,
|
||||
defending_coalition,
|
||||
attacking_coalition,
|
||||
defend_coalition_int,
|
||||
cp,
|
||||
)
|
||||
)
|
||||
recapture_trigger.add_condition(
|
||||
PartOfCoalitionInZone(
|
||||
defending_coalition, trigger_zone.id, unit_type="GROUND"
|
||||
red_recapture = self._create_capture_trigger(
|
||||
trigger_zone.id,
|
||||
flag,
|
||||
defending_coalition,
|
||||
attacking_coalition,
|
||||
defend_coalition_int,
|
||||
cp,
|
||||
flag_condition_true=True,
|
||||
)
|
||||
self.mission.triggerrules.triggers.extend(
|
||||
[red_capture, red_recapture]
|
||||
)
|
||||
)
|
||||
recapture_trigger.add_condition(FlagIsTrue(flag=flag))
|
||||
script_string = String(
|
||||
f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{defend_coalition_int}||{cp.full_name}"'
|
||||
)
|
||||
recapture_trigger.add_action(DoScript(script_string))
|
||||
recapture_trigger.add_action(ClearFlag(flag=flag))
|
||||
self.mission.triggerrules.triggers.append(recapture_trigger)
|
||||
|
||||
def generate(self) -> None:
|
||||
player_coalition = "blue"
|
||||
@@ -249,7 +288,7 @@ class TriggerGenerator:
|
||||
self._set_skill(player_coalition, enemy_coalition)
|
||||
self._set_allegiances(player_coalition, enemy_coalition)
|
||||
self._gen_markers()
|
||||
self._generate_capture_triggers(player_coalition, enemy_coalition)
|
||||
self._generate_capture_triggers()
|
||||
if self.game.settings.ground_start_scenery_remove_triggers:
|
||||
try:
|
||||
self._generate_clear_statics_trigger(self.game.scenery_clear_zones)
|
||||
|
||||
@@ -55,7 +55,7 @@ class GameStats:
|
||||
turn_data = GameTurnMetadata()
|
||||
|
||||
for cp in game.theater.controlpoints:
|
||||
if cp.captured:
|
||||
if cp.captured.is_blue:
|
||||
for squadron in cp.squadrons:
|
||||
turn_data.allied_units.aircraft_count += squadron.owned_aircraft
|
||||
turn_data.allied_units.vehicles_count += sum(cp.base.armor.values())
|
||||
|
||||
@@ -36,6 +36,18 @@ class DummyObject:
|
||||
class MigrationUnpickler(pickle.Unpickler):
|
||||
"""Custom unpickler to migrate campaign save-files for when components have been moved"""
|
||||
def find_class(self, module: Any, name: str) -> Any:
|
||||
if name == "Su_30MKA_AG":
|
||||
from pydcs_extensions.su30 import Su_30MKA
|
||||
return Su_30MKA
|
||||
if name == "Su_30MKI_AG":
|
||||
from pydcs_extensions.su30 import Su_30MKI
|
||||
return Su_30MKI
|
||||
if name == "Su_30SM_AG":
|
||||
from pydcs_extensions.su30 import Su_30SM
|
||||
return Su_30SM
|
||||
if name == "Su_30MKM_AG":
|
||||
from pydcs_extensions.su30 import Su_30MKM
|
||||
return Su_30MKM
|
||||
if name == "NightMissions":
|
||||
from game.settings import NightMissions
|
||||
return NightMissions
|
||||
@@ -129,6 +141,10 @@ class MigrationUnpickler(pickle.Unpickler):
|
||||
"Helipad_218"
|
||||
]:
|
||||
return dcs.terrain.Airport # use base-class if airport was removed
|
||||
if module == "dcs.terrain.afghanistan.airports":
|
||||
if name == "Khost_Heliport":
|
||||
from dcs.terrain.afghanistan.airports import FOB_Salerno
|
||||
return FOB_Salerno
|
||||
if module == "dcs.terrain.falklands.airports":
|
||||
if name == "Aerodromo_De_Tolhuin":
|
||||
from dcs.terrain.falklands.airports import Tolhuin
|
||||
|
||||
@@ -35,6 +35,7 @@ from game.runways import RunwayData
|
||||
from game.settings import Settings
|
||||
from game.squadrons import AirWing
|
||||
from game.squadrons import Squadron
|
||||
from game.theater.player import Player
|
||||
from game.theater.controlpoint import (
|
||||
ControlPoint,
|
||||
OffMapSpawn,
|
||||
@@ -833,7 +834,7 @@ class PretenseAircraftGenerator:
|
||||
"""
|
||||
self.initialize_pretense_data_structures(cp)
|
||||
|
||||
is_player = True
|
||||
is_player = Player.BLUE
|
||||
if country == cp.coalition.faction.country:
|
||||
offmap_transport_cp = self.find_pretense_cargo_plane_cp(cp)
|
||||
|
||||
@@ -868,7 +869,7 @@ class PretenseAircraftGenerator:
|
||||
coalition = (
|
||||
self.game.coalition_for(is_player)
|
||||
if country == self.game.coalition_for(is_player).faction.country
|
||||
else self.game.coalition_for(False)
|
||||
else self.game.coalition_for(Player.RED)
|
||||
)
|
||||
self.generate_pretense_aircraft_for_other_side(cp, coalition, ato)
|
||||
|
||||
@@ -1057,6 +1058,7 @@ class PretenseAircraftGenerator:
|
||||
and (
|
||||
not self.need_ecm
|
||||
or flight.any_member_has_weapon_of_type(WeaponType.JAMMER)
|
||||
or flight.any_member_has_weapon_of_type(WeaponType.OFFENSIVE_JAMMER)
|
||||
)
|
||||
):
|
||||
self.ewrj_package_dict[id(flight.package)].append(group)
|
||||
|
||||
@@ -25,7 +25,7 @@ from game.missiongenerator.aircraft.flightgroupspawner import (
|
||||
)
|
||||
from game.missiongenerator.missiondata import MissionData
|
||||
from game.naming import NameGenerator
|
||||
from game.theater import Airfield, ControlPoint, Fob, NavalControlPoint
|
||||
from game.theater import Airfield, ControlPoint, Fob, NavalControlPoint, Player
|
||||
|
||||
|
||||
class PretenseNameGenerator(NameGenerator):
|
||||
@@ -87,7 +87,7 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner):
|
||||
|
||||
def insert_into_pretense(self, name: str) -> None:
|
||||
cp = self.flight.departure
|
||||
is_player = True
|
||||
is_player = Player.BLUE
|
||||
cp_side = (
|
||||
2
|
||||
if self.flight.coalition
|
||||
|
||||
@@ -1495,13 +1495,13 @@ class PretenseLuaGenerator(LuaGenerator):
|
||||
cp_name.replace("ä", "a")
|
||||
cp_name.replace("ö", "o")
|
||||
cp_name.replace("ø", "o")
|
||||
cp_side = 2 if cp.captured else 1
|
||||
cp_side = 2 if cp.captured.is_blue else 1
|
||||
|
||||
if isinstance(cp, OffMapSpawn):
|
||||
continue
|
||||
elif (
|
||||
cp.is_fleet
|
||||
and cp.captured
|
||||
and cp.captured.is_blue
|
||||
and self.game.settings.pretense_controllable_carrier
|
||||
):
|
||||
# Friendly carrier, generate carrier parameters
|
||||
@@ -1591,7 +1591,7 @@ class PretenseLuaGenerator(LuaGenerator):
|
||||
# Also connect carrier and LHA control points to adjacent friendly points
|
||||
if cp.is_fleet and (
|
||||
not self.game.settings.pretense_controllable_carrier
|
||||
or not cp.captured
|
||||
or cp.captured.is_red
|
||||
):
|
||||
num_of_carrier_connections = 0
|
||||
for (
|
||||
@@ -1616,13 +1616,13 @@ class PretenseLuaGenerator(LuaGenerator):
|
||||
try:
|
||||
if (
|
||||
cp.is_fleet
|
||||
and cp.captured
|
||||
and cp.captured.is_blue
|
||||
and self.game.settings.pretense_controllable_carrier
|
||||
):
|
||||
break
|
||||
elif (
|
||||
closest_cps[extra_connection].is_fleet
|
||||
and closest_cps[extra_connection].captured
|
||||
and closest_cps[extra_connection].captured.is_blue
|
||||
and self.game.settings.pretense_controllable_carrier
|
||||
):
|
||||
break
|
||||
@@ -1647,7 +1647,7 @@ class PretenseLuaGenerator(LuaGenerator):
|
||||
if isinstance(cp, OffMapSpawn):
|
||||
continue
|
||||
cp_side_captured = cp_side == 2
|
||||
if cp_side_captured != cp.captured:
|
||||
if cp_side_captured != cp.captured.is_blue:
|
||||
continue
|
||||
cp_name_trimmed = PretenseNameGenerator.pretense_trimmed_cp_name(
|
||||
cp.name
|
||||
@@ -1723,6 +1723,13 @@ class PretenseLuaGenerator(LuaGenerator):
|
||||
def inject_plugin_script(
|
||||
self, plugin_mnemonic: str, script: str, script_mnemonic: str
|
||||
) -> None:
|
||||
# Hard block MOOSE injection for Pretense missions
|
||||
if script_mnemonic.lower() == "moose" or "moose" in script.lower():
|
||||
logging.info(
|
||||
"PretenseLuaGenerator: Skipping hard-blocked Moose.lua injection"
|
||||
)
|
||||
return
|
||||
|
||||
if script_mnemonic in self.plugin_scripts:
|
||||
logging.debug(f"Skipping already loaded {script} for {plugin_mnemonic}")
|
||||
return
|
||||
@@ -1730,7 +1737,6 @@ class PretenseLuaGenerator(LuaGenerator):
|
||||
self.plugin_scripts.append(script_mnemonic)
|
||||
|
||||
plugin_path = Path("./resources/plugins", plugin_mnemonic)
|
||||
|
||||
script_path = Path(plugin_path, script)
|
||||
if not script_path.exists():
|
||||
logging.error(f"Cannot find {script_path} for plugin {plugin_mnemonic}")
|
||||
|
||||
@@ -28,6 +28,7 @@ from game.missiongenerator.visualsgenerator import VisualsGenerator
|
||||
from game.naming import namegen
|
||||
from game.persistency import pre_pretense_backups_dir
|
||||
from game.pretense.pretenseaircraftgenerator import PretenseAircraftGenerator
|
||||
from game.theater import Player
|
||||
from game.theater.bullseye import Bullseye
|
||||
from game.unitmap import UnitMap
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
@@ -233,7 +234,7 @@ class PretenseMissionGenerator(MissionGenerator):
|
||||
callsign=callsign,
|
||||
region=frontline,
|
||||
code=str(code),
|
||||
blue=True,
|
||||
blue=Player.BLUE,
|
||||
freq=freq,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -49,6 +49,7 @@ from game.theater import (
|
||||
TheaterUnit,
|
||||
NavalControlPoint,
|
||||
PresetLocation,
|
||||
Player,
|
||||
)
|
||||
from game.theater.theatergroundobject import (
|
||||
CarrierGroundObject,
|
||||
@@ -248,7 +249,7 @@ class PretenseGroundObjectGenerator(GroundObjectGenerator):
|
||||
"""
|
||||
unit_type = None
|
||||
faction = self.coalition.faction
|
||||
is_player = True
|
||||
is_player = Player.BLUE
|
||||
side = (
|
||||
2
|
||||
if self.country == self.game.coalition_for(is_player).faction.country
|
||||
@@ -458,7 +459,7 @@ class PretenseGroundObjectGenerator(GroundObjectGenerator):
|
||||
cp_name_trimmed = PretenseNameGenerator.pretense_trimmed_cp_name(
|
||||
control_point.name
|
||||
)
|
||||
is_player = True
|
||||
is_player = Player.BLUE
|
||||
side = (
|
||||
2
|
||||
if self.country
|
||||
@@ -567,7 +568,7 @@ class PretenseGroundObjectGenerator(GroundObjectGenerator):
|
||||
cp_name_trimmed = PretenseNameGenerator.pretense_trimmed_cp_name(
|
||||
control_point.name
|
||||
)
|
||||
is_player = True
|
||||
is_player = Player.BLUE
|
||||
side = (
|
||||
2
|
||||
if self.country == self.game.coalition_for(is_player).faction.country
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
import random
|
||||
from typing import TYPE_CHECKING, List
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from dcs import Point
|
||||
from dcs.action import (
|
||||
@@ -11,10 +9,6 @@ from dcs.action import (
|
||||
DoScript,
|
||||
MarkToAll,
|
||||
SetFlag,
|
||||
RemoveSceneObjects,
|
||||
RemoveSceneObjectsMask,
|
||||
SceneryDestructionZone,
|
||||
Smoke,
|
||||
)
|
||||
from dcs.condition import (
|
||||
AllOfCoalitionOutsideZone,
|
||||
@@ -22,7 +16,6 @@ from dcs.condition import (
|
||||
FlagIsTrue,
|
||||
PartOfCoalitionInZone,
|
||||
TimeAfter,
|
||||
TimeSinceFlag,
|
||||
)
|
||||
from dcs.mission import Mission
|
||||
from dcs.task import Option
|
||||
@@ -31,12 +24,11 @@ from dcs.terrain.syria.airports import Damascus, Khalkhalah
|
||||
from dcs.translation import String
|
||||
from dcs.triggers import Event, TriggerCondition, TriggerOnce
|
||||
from dcs.unit import Skill
|
||||
from numpy import cross, einsum, arctan2
|
||||
from shapely import MultiPolygon, Point as ShapelyPoint
|
||||
|
||||
from game.naming import ALPHA_MILITARY
|
||||
from game.pretense.pretenseflightgroupspawner import PretenseNameGenerator
|
||||
from game.theater import Airfield
|
||||
from game.theater import Airfield, Player
|
||||
from game.theater.controlpoint import Fob, TRIGGER_RADIUS_CAPTURE, OffMapSpawn
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -119,7 +111,7 @@ class PretenseTriggerGenerator:
|
||||
f"Could not find {airfield.airport.name} in the mission"
|
||||
)
|
||||
cp_airport.set_coalition(
|
||||
airfield.captured and player_coalition or enemy_coalition
|
||||
airfield.captured.is_blue and player_coalition or enemy_coalition
|
||||
)
|
||||
|
||||
def _set_skill(self, player_coalition: str, enemy_coalition: str) -> None:
|
||||
@@ -157,7 +149,7 @@ class PretenseTriggerGenerator:
|
||||
zone = self.mission.triggers.add_triggerzone(
|
||||
location, radius=10, hidden=True, name="MARK"
|
||||
)
|
||||
if cp.captured:
|
||||
if cp.captured.is_blue:
|
||||
name = ground_object.obj_name + " [ALLY]"
|
||||
else:
|
||||
name = ground_object.obj_name + " [ENEMY]"
|
||||
@@ -174,7 +166,7 @@ class PretenseTriggerGenerator:
|
||||
"""
|
||||
for cp in self.game.theater.controlpoints:
|
||||
if isinstance(cp, self.capture_zone_types) and not cp.is_carrier:
|
||||
if cp.captured:
|
||||
if cp.captured.is_blue:
|
||||
attacking_coalition = enemy_coalition
|
||||
attack_coalition_int = 1 # 1 is the Event int for Red
|
||||
defending_coalition = player_coalition
|
||||
@@ -243,7 +235,7 @@ class PretenseTriggerGenerator:
|
||||
self.game.settings.pretense_carrier_zones_navmesh == "Blue navmesh"
|
||||
)
|
||||
sea_zones_landmap = self.game.coalition_for(
|
||||
player=False
|
||||
player=Player.RED
|
||||
).nav_mesh.theater.landmap
|
||||
if (
|
||||
self.game.settings.pretense_controllable_carrier
|
||||
@@ -251,7 +243,7 @@ class PretenseTriggerGenerator:
|
||||
):
|
||||
navmesh_number = 0
|
||||
for navmesh_poly in self.game.coalition_for(
|
||||
player=use_blue_navmesh
|
||||
player=Player.BLUE if use_blue_navmesh else Player.RED
|
||||
).nav_mesh.polys:
|
||||
navmesh_number += 1
|
||||
if sea_zones_landmap.sea_zones.intersects(navmesh_poly.poly):
|
||||
@@ -325,7 +317,7 @@ class PretenseTriggerGenerator:
|
||||
if (
|
||||
cp.is_fleet
|
||||
and self.game.settings.pretense_controllable_carrier
|
||||
and cp.captured
|
||||
and cp.captured.is_blue
|
||||
):
|
||||
# Friendly carrier zones are generated above
|
||||
continue
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import Iterator, List, Optional, TYPE_CHECKING, Tuple
|
||||
from game.config import RUNWAY_REPAIR_COST
|
||||
from game.data.units import UnitClass
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.theater import ControlPoint, MissionTarget, ParkingType
|
||||
from game.theater import ControlPoint, MissionTarget, ParkingType, Player
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@@ -34,20 +34,20 @@ class ProcurementAi:
|
||||
def __init__(
|
||||
self,
|
||||
game: Game,
|
||||
for_player: bool,
|
||||
owner: Player,
|
||||
faction: Faction,
|
||||
manage_runways: bool,
|
||||
manage_front_line: bool,
|
||||
manage_aircraft: bool,
|
||||
) -> None:
|
||||
self.game = game
|
||||
self.is_player = for_player
|
||||
self.air_wing = game.air_wing_for(for_player)
|
||||
self.is_player = owner
|
||||
self.air_wing = game.air_wing_for(owner)
|
||||
self.faction = faction
|
||||
self.manage_runways = manage_runways
|
||||
self.manage_front_line = manage_front_line
|
||||
self.manage_aircraft = manage_aircraft
|
||||
self.threat_zones = self.game.threat_zone_for(not self.is_player)
|
||||
self.threat_zones = self.game.threat_zone_for(self.is_player.opponent)
|
||||
|
||||
def calculate_ground_unit_budget_share(self) -> float:
|
||||
armor_investment = 0
|
||||
@@ -78,7 +78,7 @@ class ProcurementAi:
|
||||
|
||||
balance = (
|
||||
self.game.settings.auto_procurement_balance
|
||||
if self.is_player
|
||||
if self.is_player.is_blue
|
||||
else self.game.settings.auto_procurement_balance_red
|
||||
)
|
||||
air = balance / 100.0
|
||||
@@ -114,7 +114,7 @@ class ProcurementAi:
|
||||
if control_point.runway_can_be_repaired:
|
||||
control_point.begin_runway_repair()
|
||||
budget -= RUNWAY_REPAIR_COST
|
||||
if self.is_player:
|
||||
if self.is_player.is_blue:
|
||||
self.game.message(
|
||||
"We have begun repairing the runway at " f"{control_point}"
|
||||
)
|
||||
@@ -223,7 +223,7 @@ class ProcurementAi:
|
||||
|
||||
@property
|
||||
def owned_points(self) -> List[ControlPoint]:
|
||||
if self.is_player:
|
||||
if self.is_player.is_blue:
|
||||
return self.game.theater.player_points()
|
||||
else:
|
||||
return self.game.theater.enemy_points()
|
||||
@@ -269,7 +269,7 @@ class ProcurementAi:
|
||||
|
||||
reserves_factor = (
|
||||
self.game.settings.frontline_reserves_factor
|
||||
if self.is_player
|
||||
if self.is_player.is_blue
|
||||
else self.game.settings.frontline_reserves_factor_red
|
||||
)
|
||||
fr_factor = reserves_factor / 100.0
|
||||
@@ -308,7 +308,7 @@ class ProcurementAi:
|
||||
)
|
||||
target = (
|
||||
self.game.settings.reserves_procurement_target
|
||||
if self.is_player
|
||||
if self.is_player.is_blue
|
||||
else self.game.settings.reserves_procurement_target_red
|
||||
)
|
||||
if allocated.total >= target:
|
||||
|
||||
@@ -472,3 +472,15 @@ class KiowaChannelNamer(ChannelNamer):
|
||||
@classmethod
|
||||
def name(cls) -> str:
|
||||
return "kiowa"
|
||||
|
||||
|
||||
class FulcrumChannelNamer(ChannelNamer):
|
||||
"""Channel namer for the MiG-29 Fulcrum A"""
|
||||
|
||||
@staticmethod
|
||||
def channel_name(radio_id: int, channel_id: int) -> str:
|
||||
return f"Ch {channel_id -1}"
|
||||
|
||||
@classmethod
|
||||
def name(cls) -> str:
|
||||
return "fulcrum"
|
||||
|
||||
@@ -84,6 +84,10 @@ def kHz(
|
||||
return RadioFrequency(num * 1000 + hz, modulation)
|
||||
|
||||
|
||||
def Hz(num: int, hz: int = 0, modulation: Modulation = Modulation.AM) -> RadioFrequency:
|
||||
return RadioFrequency(num + hz, modulation)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RadioRange:
|
||||
"""Defines the minimum (inclusive) and maximum (exclusive) range of the radio."""
|
||||
@@ -352,6 +356,20 @@ RADIOS: List[Radio] = [
|
||||
"AN/ARC-27",
|
||||
(RadioRange(MHz(225), MHz(400), kHz(100), Modulation.AM),),
|
||||
),
|
||||
# MiG-29 Fulcrum A
|
||||
Radio(
|
||||
"R-862",
|
||||
(
|
||||
RadioRange(MHz(220), MHz(400), kHz(25), Modulation.AM),
|
||||
RadioRange(MHz(100), MHz(150), kHz(25), Modulation.AM),
|
||||
RadioRange(MHz(220), MHz(400), kHz(25), Modulation.FM),
|
||||
RadioRange(MHz(100), MHz(150), kHz(25), Modulation.FM),
|
||||
),
|
||||
),
|
||||
Radio(
|
||||
"ARK-19",
|
||||
(RadioRange(kHz(150), kHz(1300), Hz(500), Modulation.AM),),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -29,12 +29,16 @@ class ControlPointJs(BaseModel):
|
||||
destination = None
|
||||
if control_point.target_position is not None:
|
||||
destination = control_point.target_position.latlng()
|
||||
if control_point.captured.is_blue:
|
||||
blue = True
|
||||
else:
|
||||
blue = False
|
||||
return ControlPointJs(
|
||||
id=control_point.id,
|
||||
name=control_point.name,
|
||||
blue=control_point.captured,
|
||||
blue=blue,
|
||||
position=control_point.position.latlng(),
|
||||
mobile=control_point.moveable and control_point.captured,
|
||||
mobile=control_point.moveable and control_point.captured.is_blue,
|
||||
destination=destination,
|
||||
sidc=str(control_point.sidc()),
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ from fastapi import APIRouter, Body, Depends, HTTPException, status
|
||||
from starlette.responses import Response
|
||||
|
||||
from game import Game
|
||||
from game.theater.player import Player
|
||||
from .models import ControlPointJs
|
||||
from ..dependencies import GameContext
|
||||
from ..leaflet import LeafletPoint
|
||||
@@ -75,7 +76,7 @@ def set_destination(
|
||||
)
|
||||
if not cp.moveable:
|
||||
raise HTTPException(status.HTTP_403_FORBIDDEN, detail=f"{cp} is not mobile")
|
||||
if not cp.captured:
|
||||
if not cp.captured.is_blue:
|
||||
raise HTTPException(
|
||||
status.HTTP_403_FORBIDDEN, detail=f"{cp} is not owned by the player"
|
||||
)
|
||||
@@ -120,7 +121,7 @@ def cancel_travel(cp_id: UUID, game: Game = Depends(GameContext.require)) -> Non
|
||||
)
|
||||
if not cp.moveable:
|
||||
raise HTTPException(status.HTTP_403_FORBIDDEN, detail=f"{cp} is not mobile")
|
||||
if not cp.captured:
|
||||
if not cp.captured.is_blue:
|
||||
raise HTTPException(
|
||||
status.HTTP_403_FORBIDDEN, detail=f"{cp} is not owned by the player"
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@ from game.server.mapzones.models import ThreatZonesJs, UnculledZoneJs
|
||||
from game.server.navmesh.models import NavMeshJs
|
||||
from game.server.supplyroutes.models import SupplyRouteJs
|
||||
from game.server.tgos.models import TgoJs
|
||||
from game.theater import Player
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@@ -26,9 +27,9 @@ class GameUpdateEventsJs(BaseModel):
|
||||
new_combats: list[FrozenCombatJs]
|
||||
updated_combats: list[FrozenCombatJs]
|
||||
ended_combats: list[UUID]
|
||||
navmesh_updates: dict[bool, NavMeshJs]
|
||||
navmesh_updates: dict[Player, NavMeshJs]
|
||||
updated_unculled_zones: list[UnculledZoneJs]
|
||||
threat_zones_updated: dict[bool, ThreatZonesJs]
|
||||
threat_zones_updated: dict[Player, ThreatZonesJs]
|
||||
new_flights: list[FlightJs]
|
||||
updated_flights: list[FlightJs]
|
||||
deleted_flights: set[UUID]
|
||||
|
||||
@@ -41,9 +41,13 @@ class FlightJs(BaseModel):
|
||||
waypoints = None
|
||||
if with_waypoints:
|
||||
waypoints = waypoints_for_flight(flight)
|
||||
if flight.blue.is_blue:
|
||||
blue = True
|
||||
else:
|
||||
blue = False
|
||||
return FlightJs(
|
||||
id=flight.id,
|
||||
blue=flight.blue,
|
||||
blue=blue,
|
||||
position=position,
|
||||
sidc=str(flight.sidc()),
|
||||
waypoints=waypoints,
|
||||
|
||||
@@ -5,6 +5,7 @@ from uuid import UUID
|
||||
from pydantic import BaseModel
|
||||
|
||||
from game.server.leaflet import LeafletPoint
|
||||
from game.theater.player import Player
|
||||
from game.theater.iadsnetwork.iadsnetwork import IadsNetworkNode, IadsNetwork
|
||||
|
||||
|
||||
@@ -34,8 +35,16 @@ class IadsConnectionJs(BaseModel):
|
||||
iads_connections = []
|
||||
tgo = network_node.group.ground_object
|
||||
for id, connection in network_node.connections.items():
|
||||
if connection.ground_object.is_friendly(True) != tgo.is_friendly(True):
|
||||
if connection.ground_object.is_friendly(Player.BLUE) != tgo.is_friendly(
|
||||
Player.BLUE
|
||||
):
|
||||
continue # Skip connections which are not from same coalition
|
||||
if tgo.is_friendly(Player.BLUE):
|
||||
blue = True
|
||||
elif tgo.is_friendly(Player.RED):
|
||||
blue = False
|
||||
else:
|
||||
continue # Skip neutral
|
||||
iads_connections.append(
|
||||
IadsConnectionJs(
|
||||
id=id,
|
||||
@@ -49,7 +58,7 @@ class IadsConnectionJs(BaseModel):
|
||||
network_node.group.alive_units > 0
|
||||
and connection.alive_units > 0
|
||||
),
|
||||
blue=tgo.is_friendly(True),
|
||||
blue=blue,
|
||||
is_power="power"
|
||||
in [tgo.category, connection.ground_object.category],
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
|
||||
from pydantic import BaseModel
|
||||
|
||||
from game.server.leaflet import LeafletPoint, LeafletPoly, ShapelyUtil
|
||||
from game.theater import ConflictTheater
|
||||
from game.theater import ConflictTheater, Player
|
||||
from game.threatzones import ThreatZones
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -85,9 +85,9 @@ class ThreatZoneContainerJs(BaseModel):
|
||||
def for_game(game: Game) -> ThreatZoneContainerJs:
|
||||
return ThreatZoneContainerJs(
|
||||
blue=ThreatZonesJs.from_zones(
|
||||
game.threat_zone_for(player=True), game.theater
|
||||
game.threat_zone_for(player=Player.BLUE), game.theater
|
||||
),
|
||||
red=ThreatZonesJs.from_zones(
|
||||
game.threat_zone_for(player=False), game.theater
|
||||
game.threat_zone_for(player=Player.RED), game.theater
|
||||
),
|
||||
)
|
||||
|
||||
@@ -2,12 +2,13 @@ from fastapi import APIRouter, Depends
|
||||
|
||||
from game import Game
|
||||
from game.server import GameContext
|
||||
from game.theater.player import Player
|
||||
from .models import NavMeshJs
|
||||
|
||||
router: APIRouter = APIRouter(prefix="/navmesh")
|
||||
|
||||
|
||||
@router.get("/", operation_id="get_navmesh", response_model=NavMeshJs)
|
||||
def get(for_player: bool, game: Game = Depends(GameContext.require)) -> NavMeshJs:
|
||||
def get(for_player: Player, game: Game = Depends(GameContext.require)) -> NavMeshJs:
|
||||
mesh = game.coalition_for(for_player).nav_mesh
|
||||
return NavMeshJs.from_navmesh(mesh, game)
|
||||
|
||||
@@ -76,6 +76,10 @@ class SupplyRouteJs(BaseModel):
|
||||
def for_link(
|
||||
game: Game, a: ControlPoint, b: ControlPoint, points: list[Point], sea: bool
|
||||
) -> SupplyRouteJs:
|
||||
if a.captured.is_blue:
|
||||
blue = True
|
||||
else:
|
||||
blue = False
|
||||
return SupplyRouteJs(
|
||||
# Although these are not persistent objects in the backend, the frontend
|
||||
# needs unique IDs for anything that it will use in a list. That means that
|
||||
@@ -93,7 +97,7 @@ class SupplyRouteJs(BaseModel):
|
||||
points=[p.latlng() for p in points],
|
||||
front_active=not sea and a.front_is_active(b),
|
||||
is_sea=sea,
|
||||
blue=a.captured,
|
||||
blue=blue,
|
||||
active_transports=TransportFinder(game, a, b).describe_active_transports(
|
||||
sea
|
||||
),
|
||||
|
||||
@@ -34,12 +34,16 @@ class TgoJs(BaseModel):
|
||||
def for_tgo(tgo: TheaterGroundObject) -> TgoJs:
|
||||
threat_ranges = [group.max_threat_range().meters for group in tgo.groups]
|
||||
detection_ranges = [group.max_detection_range().meters for group in tgo.groups]
|
||||
if tgo.control_point.captured.is_blue:
|
||||
blue = True
|
||||
else:
|
||||
blue = False
|
||||
return TgoJs(
|
||||
id=tgo.id,
|
||||
name=tgo.name,
|
||||
control_point_name=tgo.control_point.name,
|
||||
category=tgo.category,
|
||||
blue=tgo.control_point.captured,
|
||||
blue=blue,
|
||||
position=tgo.position.latlng(),
|
||||
units=[unit.display_name for unit in tgo.units],
|
||||
threat_ranges=threat_ranges,
|
||||
|
||||
@@ -46,7 +46,7 @@ class AirCombat(JoinableCombat):
|
||||
blue_flights = []
|
||||
red_flights = []
|
||||
for flight in self.flights:
|
||||
if flight.squadron.player:
|
||||
if flight.squadron.player.is_blue:
|
||||
blue_flights.append(str(flight))
|
||||
else:
|
||||
red_flights.append(str(flight))
|
||||
@@ -71,7 +71,7 @@ class AirCombat(JoinableCombat):
|
||||
blue = []
|
||||
red = []
|
||||
for flight in self.flights:
|
||||
if flight.squadron.player:
|
||||
if flight.squadron.player.is_blue:
|
||||
blue.append(flight)
|
||||
else:
|
||||
red.append(flight)
|
||||
|
||||
@@ -6,6 +6,7 @@ from collections.abc import Iterator
|
||||
from datetime import timedelta
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from game.theater.player import Player
|
||||
from .aircombat import AirCombat
|
||||
from .aircraftengagementzones import AircraftEngagementZones
|
||||
from .atip import AtIp
|
||||
@@ -31,8 +32,10 @@ class CombatInitiator:
|
||||
def update_active_combats(self) -> None:
|
||||
blue_a2a = AircraftEngagementZones.from_ato(self.game.blue.ato)
|
||||
red_a2a = AircraftEngagementZones.from_ato(self.game.red.ato)
|
||||
blue_sam = SamEngagementZones.from_theater(self.game.theater, player=True)
|
||||
red_sam = SamEngagementZones.from_theater(self.game.theater, player=False)
|
||||
blue_sam = SamEngagementZones.from_theater(
|
||||
self.game.theater, player=Player.BLUE
|
||||
)
|
||||
red_sam = SamEngagementZones.from_theater(self.game.theater, player=Player.RED)
|
||||
|
||||
# Check each vulnerable flight to see if it has initiated combat. If any flight
|
||||
# initiates combat, a single FrozenCombat will be created for all involved
|
||||
@@ -46,7 +49,7 @@ class CombatInitiator:
|
||||
if flight.state.in_combat:
|
||||
return
|
||||
|
||||
if flight.squadron.player:
|
||||
if flight.squadron.player.is_blue:
|
||||
a2a = red_a2a
|
||||
own_a2a = blue_a2a
|
||||
sam = red_sam
|
||||
|
||||
@@ -9,7 +9,7 @@ from shapely.ops import unary_union
|
||||
from game.utils import dcs_to_shapely_point
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.theater import ConflictTheater, TheaterGroundObject
|
||||
from game.theater import ConflictTheater, TheaterGroundObject, Player
|
||||
from game.threatzones import ThreatPoly
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ class SamEngagementZones:
|
||||
yield tgo
|
||||
|
||||
@classmethod
|
||||
def from_theater(cls, theater: ConflictTheater, player: bool) -> SamEngagementZones:
|
||||
def from_theater(
|
||||
cls, theater: ConflictTheater, player: Player
|
||||
) -> SamEngagementZones:
|
||||
commit_regions = []
|
||||
individual_zones = []
|
||||
for cp in theater.control_points_for(player):
|
||||
|
||||
@@ -12,7 +12,7 @@ if TYPE_CHECKING:
|
||||
from game.ato import Flight, Package
|
||||
from game.navmesh import NavMesh
|
||||
from game.sim.combat import FrozenCombat
|
||||
from game.theater import ControlPoint, FrontLine, TheaterGroundObject
|
||||
from game.theater import ControlPoint, FrontLine, TheaterGroundObject, Player
|
||||
from game.threatzones import ThreatZones
|
||||
from game.theater.iadsnetwork.iadsnetwork import IadsNetworkNode
|
||||
|
||||
@@ -24,9 +24,9 @@ class GameUpdateEvents:
|
||||
updated_combats: list[FrozenCombat] = field(default_factory=list)
|
||||
ended_combats: list[FrozenCombat] = field(default_factory=list)
|
||||
updated_flight_positions: list[tuple[Flight, Point]] = field(default_factory=list)
|
||||
navmesh_updates: dict[bool, NavMesh] = field(default_factory=dict)
|
||||
navmesh_updates: dict[Player, NavMesh] = field(default_factory=dict)
|
||||
unculled_zones_updated: list[Point] = field(default_factory=list)
|
||||
threat_zones_updated: dict[bool, ThreatZones] = field(default_factory=dict)
|
||||
threat_zones_updated: dict[Player, ThreatZones] = field(default_factory=dict)
|
||||
new_flights: set[Flight] = field(default_factory=set)
|
||||
updated_flights: set[Flight] = field(default_factory=set)
|
||||
deleted_flights: set[UUID] = field(default_factory=set)
|
||||
@@ -70,7 +70,7 @@ class GameUpdateEvents:
|
||||
self.updated_flight_positions.append((flight, new_position))
|
||||
return self
|
||||
|
||||
def update_navmesh(self, player: bool, navmesh: NavMesh) -> GameUpdateEvents:
|
||||
def update_navmesh(self, player: Player, navmesh: NavMesh) -> GameUpdateEvents:
|
||||
self.navmesh_updates[player] = navmesh
|
||||
return self
|
||||
|
||||
@@ -78,7 +78,9 @@ class GameUpdateEvents:
|
||||
self.unculled_zones_updated = zones
|
||||
return self
|
||||
|
||||
def update_threat_zones(self, player: bool, zones: ThreatZones) -> GameUpdateEvents:
|
||||
def update_threat_zones(
|
||||
self, player: Player, zones: ThreatZones
|
||||
) -> GameUpdateEvents:
|
||||
self.threat_zones_updated[player] = zones
|
||||
return self
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ class MissionResultsProcessor:
|
||||
def commit_captures(self, debriefing: Debriefing, events: GameUpdateEvents) -> None:
|
||||
for captured in debriefing.base_captures:
|
||||
try:
|
||||
if captured.captured_by_player:
|
||||
if captured.captured_by_player.is_blue:
|
||||
self.game.message(
|
||||
f"{captured.control_point} captured!",
|
||||
f"We took control of {captured.control_point}.",
|
||||
@@ -174,7 +174,7 @@ class MissionResultsProcessor:
|
||||
self, debriefing: Debriefing, events: GameUpdateEvents
|
||||
) -> None:
|
||||
for cp in self.game.theater.player_points():
|
||||
enemy_cps = [e for e in cp.connected_points if not e.captured]
|
||||
enemy_cps = [e for e in cp.connected_points if e.captured.is_red]
|
||||
for enemy_cp in enemy_cps:
|
||||
front_line = cp.front_line_with(enemy_cp)
|
||||
front_line.update_position()
|
||||
@@ -321,7 +321,7 @@ class MissionResultsProcessor:
|
||||
settings = cp.coalition.game.settings
|
||||
factor = (
|
||||
settings.frontline_reserves_factor
|
||||
if cp.captured
|
||||
if cp.captured.is_blue
|
||||
else settings.frontline_reserves_factor_red
|
||||
)
|
||||
|
||||
@@ -345,7 +345,7 @@ class MissionResultsProcessor:
|
||||
1,
|
||||
(
|
||||
settings.reserves_procurement_target
|
||||
if source.captured
|
||||
if source.captured.is_blue
|
||||
else settings.reserves_procurement_target_red
|
||||
),
|
||||
)
|
||||
@@ -367,7 +367,7 @@ class MissionResultsProcessor:
|
||||
source.base.commit_losses(moved_units)
|
||||
|
||||
# Also transfer pending deliveries.
|
||||
for unit_type, count in source.ground_unit_orders.units.items():
|
||||
for unit_type, count in list(source.ground_unit_orders.units.items()):
|
||||
move_count = int(count * move_factor)
|
||||
source.ground_unit_orders.sell({unit_type: move_count})
|
||||
destination.ground_unit_orders.order({unit_type: move_count})
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
from collections import defaultdict
|
||||
from typing import Iterator, Optional, Sequence, TYPE_CHECKING
|
||||
from typing import Iterator, Optional, Sequence, TYPE_CHECKING, Any
|
||||
|
||||
from game.ato.closestairfields import ObjectiveDistanceCache
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
@@ -14,18 +14,31 @@ from ..utils import Distance
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.game import Game
|
||||
from game.theater.player import Player
|
||||
from ..ato.flighttype import FlightType
|
||||
from .squadron import Squadron
|
||||
|
||||
|
||||
class AirWing:
|
||||
def __init__(self, player: bool, game: Game, faction: Faction) -> None:
|
||||
def __init__(self, player: Player, game: Game, faction: Faction) -> None:
|
||||
self.player = player
|
||||
self.squadrons: dict[AircraftType, list[Squadron]] = defaultdict(list)
|
||||
self.squadron_defs = SquadronDefLoader(game, faction).load()
|
||||
self.squadron_def_generator = SquadronDefGenerator(faction)
|
||||
self.settings = game.settings
|
||||
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
# Migration: Convert old boolean player values to Player enum
|
||||
if "player" in state and isinstance(state["player"], bool):
|
||||
from game.theater.player import Player
|
||||
|
||||
if state["player"]:
|
||||
state["player"] = Player.BLUE
|
||||
else:
|
||||
state["player"] = Player.RED
|
||||
|
||||
self.__dict__.update(state)
|
||||
|
||||
def unclaim_squadron_def(self, squadron: Squadron) -> None:
|
||||
if squadron.aircraft in self.squadron_defs:
|
||||
for squadron_def in self.squadron_defs[squadron.aircraft]:
|
||||
|
||||
@@ -15,6 +15,7 @@ from faker import Faker
|
||||
from game.ato import Flight, FlightType, Package
|
||||
from game.settings import AutoAtoBehavior, Settings
|
||||
from game.theater import ParkingType
|
||||
from game.theater.player import Player
|
||||
from .pilot import Pilot, PilotStatus
|
||||
from ..db.database import Database
|
||||
from ..radio.radios import RadioFrequency
|
||||
@@ -96,7 +97,7 @@ class Squadron:
|
||||
self._livery_pool: list[str] = []
|
||||
|
||||
@property
|
||||
def player(self) -> bool:
|
||||
def player(self) -> Player:
|
||||
return self.coalition.player
|
||||
|
||||
def assign_to_base(self, base: ControlPoint) -> None:
|
||||
@@ -134,7 +135,7 @@ class Squadron:
|
||||
return self.claim_new_pilot_if_allowed()
|
||||
|
||||
# For opfor, so player/AI option is irrelevant.
|
||||
if not self.player:
|
||||
if self.player != Player.BLUE:
|
||||
return self.available_pilots.pop()
|
||||
|
||||
preference = self.settings.auto_ato_behavior
|
||||
|
||||
@@ -15,6 +15,7 @@ from .daytimemap import DaytimeMap
|
||||
from .frontline import FrontLine
|
||||
from .iadsnetwork.iadsnetwork import IadsNetwork
|
||||
from .landmap import poly_contains, load_landmap
|
||||
from .player import Player
|
||||
from .seasonalconditions import SeasonalConditions
|
||||
from ..utils import Heading
|
||||
|
||||
@@ -170,10 +171,10 @@ class ConflictTheater:
|
||||
return new_point
|
||||
|
||||
def control_points_for(
|
||||
self, player: bool, state_check: bool = False
|
||||
self, player: Player, state_check: bool = False
|
||||
) -> Iterator[ControlPoint]:
|
||||
for point in self.controlpoints:
|
||||
if point.captured == player:
|
||||
if point.captured is player:
|
||||
if not state_check:
|
||||
yield point
|
||||
elif point.is_carrier and point.runway_is_operational():
|
||||
@@ -182,14 +183,21 @@ class ConflictTheater:
|
||||
yield point
|
||||
|
||||
def player_points(self, state_check: bool = False) -> List[ControlPoint]:
|
||||
return list(self.control_points_for(player=True, state_check=state_check))
|
||||
return list(
|
||||
self.control_points_for(player=Player.BLUE, state_check=state_check)
|
||||
)
|
||||
|
||||
def conflicts(self) -> Iterator[FrontLine]:
|
||||
for cp in self.player_points():
|
||||
yield from cp.front_lines.values()
|
||||
|
||||
def enemy_points(self, state_check: bool = False) -> List[ControlPoint]:
|
||||
return list(self.control_points_for(player=False, state_check=state_check))
|
||||
return list(self.control_points_for(player=Player.RED, state_check=state_check))
|
||||
|
||||
def neutral_points(self, state_check: bool = False) -> List[ControlPoint]:
|
||||
return list(
|
||||
self.control_points_for(player=Player.NEUTRAL, state_check=state_check)
|
||||
)
|
||||
|
||||
def closest_control_point(
|
||||
self, point: Point, allow_naval: bool = False
|
||||
@@ -259,10 +267,12 @@ class ConflictTheater:
|
||||
"""
|
||||
closest_cps = list()
|
||||
distances_to_cp = dict()
|
||||
if cp.captured:
|
||||
if cp.captured.is_blue:
|
||||
control_points = self.player_points()
|
||||
else:
|
||||
elif cp.captured.is_red:
|
||||
control_points = self.enemy_points()
|
||||
elif cp.captured.is_neutral:
|
||||
control_points = self.neutral_points()
|
||||
for other_cp in control_points:
|
||||
if cp == other_cp:
|
||||
continue
|
||||
@@ -292,6 +302,12 @@ class ConflictTheater:
|
||||
return cp
|
||||
raise KeyError(f"Cannot find ControlPoint named {name}")
|
||||
|
||||
def control_point_by_full_name(self, full_name: str) -> ControlPoint:
|
||||
for cp in self.controlpoints:
|
||||
if cp.full_name == full_name:
|
||||
return cp
|
||||
raise KeyError(f"Cannot find ControlPoint with full name {full_name}")
|
||||
|
||||
def find_carriers(self) -> List[ControlPoint]:
|
||||
try:
|
||||
carriers = [cp for cp in self.controlpoints if cp.is_carrier]
|
||||
|
||||
@@ -68,6 +68,7 @@ from .base import Base
|
||||
from .frontline import FrontLine
|
||||
from .interfaces.CTLD import CTLD
|
||||
from .missiontarget import MissionTarget
|
||||
from .player import Player
|
||||
from .theatergroundobject import (
|
||||
GenericCarrierGroundObject,
|
||||
TheaterGroundObject,
|
||||
@@ -377,7 +378,7 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
position: Point,
|
||||
at: StartingPosition,
|
||||
theater: ConflictTheater,
|
||||
starts_blue: bool,
|
||||
starting_coalition: Player,
|
||||
cptype: ControlPointType = ControlPointType.AIRBASE,
|
||||
is_invisible: bool = False,
|
||||
) -> None:
|
||||
@@ -386,8 +387,8 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
self.full_name = name
|
||||
self.at = at
|
||||
self.theater = theater
|
||||
self.starts_blue = starts_blue
|
||||
self.is_invisible = is_invisible
|
||||
self.starting_coalition = starting_coalition
|
||||
self.connected_objectives: List[TheaterGroundObject] = []
|
||||
self.preset_locations = PresetLocations()
|
||||
self.helipads: List[PointWithHeading] = []
|
||||
@@ -435,7 +436,7 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
|
||||
def finish_init(self, game: Game) -> None:
|
||||
assert self._coalition is None
|
||||
self._coalition = game.coalition_for(self.starts_blue)
|
||||
self._coalition = game.coalition_for(self.starting_coalition)
|
||||
assert self._front_line_db is None
|
||||
self._front_line_db = game.db.front_lines
|
||||
|
||||
@@ -444,7 +445,8 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
# the entire game state when it comes up.
|
||||
from game.sim import GameUpdateEvents
|
||||
|
||||
self._create_missing_front_lines(laser_code_registry, GameUpdateEvents())
|
||||
if self.captured != Player.NEUTRAL:
|
||||
self._create_missing_front_lines(laser_code_registry, GameUpdateEvents())
|
||||
|
||||
@property
|
||||
def front_line_db(self) -> Database[FrontLine]:
|
||||
@@ -455,9 +457,11 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
self, laser_code_registry: LaserCodeRegistry, events: GameUpdateEvents
|
||||
) -> None:
|
||||
for connection in self.convoy_routes.keys():
|
||||
if not connection.front_line_active_with(
|
||||
self
|
||||
) and not connection.is_friendly_to(self):
|
||||
if (
|
||||
not connection.front_line_active_with(self)
|
||||
and not connection.is_friendly_to(self)
|
||||
and connection.captured != Player.NEUTRAL
|
||||
):
|
||||
self._create_front_line_with(laser_code_registry, connection, events)
|
||||
|
||||
def _create_front_line_with(
|
||||
@@ -491,6 +495,8 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
|
||||
@property
|
||||
def has_frontline(self) -> bool:
|
||||
if self.captured.is_neutral:
|
||||
return False
|
||||
return bool(self.front_lines)
|
||||
|
||||
def front_line_active_with(self, other: ControlPoint) -> bool:
|
||||
@@ -500,14 +506,17 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
return self.front_lines[other]
|
||||
|
||||
@property
|
||||
def captured(self) -> bool:
|
||||
def captured(self) -> Player:
|
||||
return self.coalition.player
|
||||
|
||||
@property
|
||||
def standard_identity(self) -> StandardIdentity:
|
||||
return (
|
||||
StandardIdentity.FRIEND if self.captured else StandardIdentity.HOSTILE_FAKER
|
||||
)
|
||||
if self.captured.is_neutral:
|
||||
return StandardIdentity.UNKNOWN
|
||||
elif self.captured.is_blue:
|
||||
return StandardIdentity.FRIEND
|
||||
else:
|
||||
return StandardIdentity.HOSTILE_FAKER
|
||||
|
||||
@property
|
||||
def sidc_status(self) -> Status:
|
||||
@@ -819,7 +828,7 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
found.append(g)
|
||||
return found
|
||||
|
||||
def is_friendly(self, to_player: bool) -> bool:
|
||||
def is_friendly(self, to_player: Player) -> bool:
|
||||
return self.captured == to_player
|
||||
|
||||
def is_friendly_to(self, control_point: ControlPoint) -> bool:
|
||||
@@ -828,7 +837,9 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
def capture_equipment(self, game: Game) -> None:
|
||||
total = self.base.total_armor_value
|
||||
self.base.armor.clear()
|
||||
game.adjust_budget(total, player=not self.captured)
|
||||
game.adjust_budget(
|
||||
total, player=Player.BLUE if self.captured.is_red else Player.RED
|
||||
)
|
||||
game.message(
|
||||
f"{self.name} is not connected to any friendly points. Ground "
|
||||
f"vehicles have been captured and sold for ${total}M."
|
||||
@@ -857,7 +868,9 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
|
||||
def capture_aircraft(self, game: Game, airframe: AircraftType, count: int) -> None:
|
||||
value = airframe.price * count
|
||||
game.adjust_budget(value, player=not self.captured)
|
||||
game.adjust_budget(
|
||||
value, player=Player.BLUE if self.captured.is_red else Player.RED
|
||||
)
|
||||
game.message(
|
||||
f"No valid retreat destination in range of {self.name} for {airframe} "
|
||||
f"{count} aircraft have been captured and sold for ${value}M."
|
||||
@@ -960,7 +973,7 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
pass
|
||||
|
||||
# TODO: Should be Airbase specific.
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None:
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: Player) -> None:
|
||||
new_coalition = game.coalition_for(for_player)
|
||||
self.ground_unit_orders.refund_all(self.coalition)
|
||||
self.retreat_ground_units(game)
|
||||
@@ -1125,6 +1138,8 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
|
||||
@property
|
||||
def has_active_frontline(self) -> bool:
|
||||
if self.captured.is_neutral:
|
||||
return False
|
||||
return any(not c.is_friendly(self.captured) for c in self.connected_points)
|
||||
|
||||
def front_is_active(self, other: ControlPoint) -> bool:
|
||||
@@ -1211,7 +1226,7 @@ class Airfield(ControlPoint, CTLD):
|
||||
self,
|
||||
airport: Airport,
|
||||
theater: ConflictTheater,
|
||||
starts_blue: bool,
|
||||
starting_coalition: Player,
|
||||
ctld_zones: Optional[List[Tuple[Point, float]]] = None,
|
||||
influence_zone: Optional[List[Tuple[Point, float]]] = None,
|
||||
) -> None:
|
||||
@@ -1220,7 +1235,7 @@ class Airfield(ControlPoint, CTLD):
|
||||
airport.position,
|
||||
airport,
|
||||
theater,
|
||||
starts_blue,
|
||||
starting_coalition,
|
||||
cptype=ControlPointType.AIRBASE,
|
||||
)
|
||||
self.airport = airport
|
||||
@@ -1252,7 +1267,7 @@ class Airfield(ControlPoint, CTLD):
|
||||
return True
|
||||
return self.runway_is_operational()
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
@@ -1373,7 +1388,7 @@ class NavalControlPoint(
|
||||
def is_fleet(self) -> bool:
|
||||
return True
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if self.is_friendly(for_player):
|
||||
@@ -1482,7 +1497,7 @@ class NavalControlPoint(
|
||||
|
||||
class Carrier(NavalControlPoint):
|
||||
def __init__(
|
||||
self, name: str, at: Point, theater: ConflictTheater, starts_blue: bool
|
||||
self, name: str, at: Point, theater: ConflictTheater, starts_blue: Player
|
||||
):
|
||||
super().__init__(
|
||||
name,
|
||||
@@ -1497,7 +1512,7 @@ class Carrier(NavalControlPoint):
|
||||
def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]:
|
||||
return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.CARRIER
|
||||
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None:
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: Player) -> None:
|
||||
raise RuntimeError("Carriers cannot be captured")
|
||||
|
||||
@property
|
||||
@@ -1522,7 +1537,7 @@ class EssexCarrier(Carrier):
|
||||
|
||||
class Lha(NavalControlPoint):
|
||||
def __init__(
|
||||
self, name: str, at: Point, theater: ConflictTheater, starts_blue: bool
|
||||
self, name: str, at: Point, theater: ConflictTheater, starts_blue: Player
|
||||
):
|
||||
super().__init__(
|
||||
name, at, at, theater, starts_blue, cptype=ControlPointType.LHA_GROUP
|
||||
@@ -1532,7 +1547,7 @@ class Lha(NavalControlPoint):
|
||||
def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]:
|
||||
return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.AMPHIBIOUS_ASSAULT_SHIP_GENERAL
|
||||
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None:
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: Player) -> None:
|
||||
raise RuntimeError("LHAs cannot be captured")
|
||||
|
||||
@property
|
||||
@@ -1555,7 +1570,7 @@ class OffMapSpawn(ControlPoint):
|
||||
return True
|
||||
|
||||
def __init__(
|
||||
self, name: str, position: Point, theater: ConflictTheater, starts_blue: bool
|
||||
self, name: str, position: Point, theater: ConflictTheater, starts_blue: Player
|
||||
):
|
||||
super().__init__(
|
||||
name,
|
||||
@@ -1570,10 +1585,10 @@ class OffMapSpawn(ControlPoint):
|
||||
def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]:
|
||||
return SymbolSet.LAND_INSTALLATIONS, LandInstallationEntity.AIPORT_AIR_BASE
|
||||
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None:
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: Player) -> None:
|
||||
raise RuntimeError("Off map control points cannot be captured")
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
yield from []
|
||||
|
||||
def total_aircraft_parking(self, parking_type: ParkingType) -> int:
|
||||
@@ -1630,7 +1645,7 @@ class Fob(ControlPoint, RadioFrequencyContainer, CTLD):
|
||||
name: str,
|
||||
at: Point,
|
||||
theater: ConflictTheater,
|
||||
starts_blue: bool,
|
||||
starts_blue: Player,
|
||||
ctld_zones: Optional[List[Tuple[Point, float]]] = None,
|
||||
is_invisible: bool = False,
|
||||
influence_zone: Optional[List[Tuple[Point, float]]] = None,
|
||||
@@ -1667,7 +1682,7 @@ class Fob(ControlPoint, RadioFrequencyContainer, CTLD):
|
||||
def runway_status(self) -> RunwayStatus:
|
||||
return RunwayStatus()
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
|
||||
@@ -8,6 +8,7 @@ from typing import Any, Iterator, List, TYPE_CHECKING, Tuple
|
||||
from dcs.mapping import Point
|
||||
|
||||
from .missiontarget import MissionTarget
|
||||
from .player import Player
|
||||
from ..lasercodes.lasercode import LaserCode
|
||||
from ..utils import Heading, pairwise
|
||||
|
||||
@@ -89,19 +90,22 @@ class FrontLine(MissionTarget):
|
||||
def update_position(self) -> None:
|
||||
self.position = self._compute_position()
|
||||
|
||||
def control_point_friendly_to(self, player: bool) -> ControlPoint:
|
||||
if player:
|
||||
def control_point_friendly_to(self, player: Player) -> ControlPoint:
|
||||
if player.is_blue:
|
||||
return self.blue_cp
|
||||
return self.red_cp
|
||||
|
||||
def control_point_hostile_to(self, player: bool) -> ControlPoint:
|
||||
return self.control_point_friendly_to(not player)
|
||||
def control_point_hostile_to(self, player: Player) -> ControlPoint:
|
||||
if player.is_blue:
|
||||
return self.red_cp
|
||||
else:
|
||||
return self.blue_cp
|
||||
|
||||
def is_friendly(self, to_player: bool) -> bool:
|
||||
def is_friendly(self, to_player: Player) -> bool:
|
||||
"""Returns True if the objective is in friendly territory."""
|
||||
return False
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
yield from [
|
||||
@@ -210,6 +214,6 @@ class FrontLine(MissionTarget):
|
||||
raise ValueError(
|
||||
"Cannot sort control points that are friendly to each other"
|
||||
)
|
||||
if a.captured:
|
||||
if a.captured.is_blue:
|
||||
return a, b
|
||||
return b, a
|
||||
|
||||
@@ -16,6 +16,7 @@ from game.theater.theatergroundobject import (
|
||||
TheaterGroundObject,
|
||||
)
|
||||
from game.theater.theatergroup import IadsGroundGroup
|
||||
from game.theater.player import Player
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.game import Game
|
||||
@@ -31,7 +32,7 @@ class SkynetNode:
|
||||
"""Dataclass for a SkynetNode used in the LUA Data table by the luagenerator"""
|
||||
|
||||
dcs_name: str
|
||||
player: bool
|
||||
player: Player
|
||||
iads_role: IadsRole
|
||||
properties: dict[str, str] = field(default_factory=dict)
|
||||
connections: dict[str, list[str]] = field(default_factory=lambda: defaultdict(list))
|
||||
@@ -62,7 +63,7 @@ class SkynetNode:
|
||||
def from_group(cls, group: IadsGroundGroup) -> SkynetNode:
|
||||
node = cls(
|
||||
cls.dcs_name_for_group(group),
|
||||
group.ground_object.is_friendly(True),
|
||||
group.ground_object.coalition.player,
|
||||
group.iads_role,
|
||||
)
|
||||
unit_type = group.units[0].unit_type
|
||||
@@ -314,8 +315,8 @@ class IadsNetwork:
|
||||
self._make_advanced_connections_by_range(node)
|
||||
|
||||
def _is_friendly(self, node: IadsNetworkNode, tgo: TheaterGroundObject) -> bool:
|
||||
node_friendly = node.group.ground_object.is_friendly(True)
|
||||
tgo_friendly = tgo.is_friendly(True)
|
||||
node_friendly = node.group.ground_object.is_friendly(Player.BLUE)
|
||||
tgo_friendly = tgo.is_friendly(Player.BLUE)
|
||||
return node_friendly == tgo_friendly
|
||||
|
||||
def _update_network(
|
||||
|
||||
@@ -6,7 +6,7 @@ from dcs.mapping import Point
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.theater import TheaterUnit, Coalition
|
||||
from game.theater import TheaterUnit, Coalition, Player
|
||||
|
||||
|
||||
class MissionTarget:
|
||||
@@ -24,11 +24,11 @@ class MissionTarget:
|
||||
"""Computes the distance to the given mission target."""
|
||||
return self.position.distance_to_point(other.position)
|
||||
|
||||
def is_friendly(self, to_player: bool) -> bool:
|
||||
def is_friendly(self, to_player: Player) -> bool:
|
||||
"""Returns True if the objective is in friendly territory."""
|
||||
raise NotImplementedError
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if self.is_friendly(for_player):
|
||||
|
||||
30
game/theater/player.py
Normal file
30
game/theater/player.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class Player(Enum):
|
||||
NEUTRAL = "Neutral"
|
||||
BLUE = "Blue"
|
||||
RED = "Red"
|
||||
|
||||
@property
|
||||
def is_red(self) -> bool:
|
||||
"""Returns True if the player is Red."""
|
||||
return self == Player.RED
|
||||
|
||||
@property
|
||||
def is_blue(self) -> bool:
|
||||
"""Returns True if the player is Blue."""
|
||||
return self == Player.BLUE
|
||||
|
||||
@property
|
||||
def is_neutral(self) -> bool:
|
||||
"""Returns True if the player is Neutral."""
|
||||
return self == Player.NEUTRAL
|
||||
|
||||
@property
|
||||
def opponent(self) -> "Player":
|
||||
"""Returns the opponent player."""
|
||||
if self.is_blue:
|
||||
return Player.RED
|
||||
else:
|
||||
return Player.BLUE
|
||||
@@ -32,6 +32,7 @@ from . import (
|
||||
Fob,
|
||||
OffMapSpawn,
|
||||
)
|
||||
from .player import Player
|
||||
from .theatergroup import (
|
||||
IadsGroundGroup,
|
||||
IadsRole,
|
||||
@@ -95,6 +96,7 @@ class ModSettings:
|
||||
uh_60l: bool = False
|
||||
jas39_gripen: bool = False
|
||||
sk_60: bool = False
|
||||
mam: bool = False
|
||||
mirage_3: bool = False
|
||||
super_etendard: bool = False
|
||||
su15_flagon: bool = False
|
||||
@@ -157,12 +159,12 @@ class GameGenerator:
|
||||
game.settings.version = VERSION
|
||||
return game
|
||||
|
||||
def should_remove_carrier(self, player: bool) -> bool:
|
||||
faction = self.player if player else self.enemy
|
||||
def should_remove_carrier(self, player: Player) -> bool:
|
||||
faction = self.player if player.is_blue else self.enemy
|
||||
return self.generator_settings.no_carrier or not faction.carriers
|
||||
|
||||
def should_remove_lha(self, player: bool) -> bool:
|
||||
faction = self.player if player else self.enemy
|
||||
def should_remove_lha(self, player: Player) -> bool:
|
||||
faction = self.player if player.is_blue else self.enemy
|
||||
return self.generator_settings.no_lha or not [
|
||||
x for x in faction.carriers if x.unit_class == UnitClass.HELICOPTER_CARRIER
|
||||
]
|
||||
@@ -173,11 +175,14 @@ class GameGenerator:
|
||||
# Remove carrier and lha, invert situation if needed
|
||||
for cp in self.theater.controlpoints:
|
||||
if self.generator_settings.inverted:
|
||||
cp.starts_blue = cp.captured_invert
|
||||
if not cp.starting_coalition.is_neutral:
|
||||
cp.starting_coalition = (
|
||||
Player.RED if not cp.captured_invert else Player.BLUE
|
||||
)
|
||||
|
||||
if cp.is_carrier and self.should_remove_carrier(cp.starts_blue):
|
||||
if cp.is_carrier and self.should_remove_carrier(cp.starting_coalition):
|
||||
to_remove.append(cp)
|
||||
elif cp.is_lha and self.should_remove_lha(cp.starts_blue):
|
||||
elif cp.is_lha and self.should_remove_lha(cp.starting_coalition):
|
||||
to_remove.append(cp)
|
||||
|
||||
# do remove
|
||||
@@ -229,11 +234,13 @@ class ControlPointGroundObjectGenerator:
|
||||
self.control_point.connected_objectives.append(ground_object)
|
||||
|
||||
def generate_navy(self) -> None:
|
||||
if self.control_point.captured.is_neutral:
|
||||
return
|
||||
skip_player_navy = self.generator_settings.no_player_navy
|
||||
if self.control_point.captured and skip_player_navy:
|
||||
if self.control_point.captured.is_blue and skip_player_navy:
|
||||
return
|
||||
skip_enemy_navy = self.generator_settings.no_enemy_navy
|
||||
if not self.control_point.captured and skip_enemy_navy:
|
||||
if self.control_point.captured.is_red and skip_enemy_navy:
|
||||
return
|
||||
for position in self.control_point.preset_locations.ships:
|
||||
unit_group = self.armed_forces.random_group_for_task(GroupTask.NAVY)
|
||||
@@ -351,7 +358,7 @@ class CarrierGroundObjectGenerator(GenericCarrierGroundObjectGenerator):
|
||||
self.control_point.name,
|
||||
self.control_point.position,
|
||||
self.game.theater,
|
||||
self.control_point.starts_blue,
|
||||
self.control_point.starting_coalition,
|
||||
)
|
||||
self.control_point.finish_init(self.game)
|
||||
self.game.theater.controlpoints.append(self.control_point)
|
||||
|
||||
@@ -21,6 +21,7 @@ from game.sidc import (
|
||||
)
|
||||
from game.theater.presetlocation import PresetLocation
|
||||
from .missiontarget import MissionTarget
|
||||
from .player import Player
|
||||
from ..data.groups import GroupTask
|
||||
from ..utils import Distance, Heading, meters
|
||||
|
||||
@@ -89,6 +90,8 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC):
|
||||
|
||||
@property
|
||||
def sidc_status(self) -> Status:
|
||||
if self.control_point.captured.is_neutral:
|
||||
return Status.PRESENT
|
||||
if self.is_dead:
|
||||
return Status.PRESENT_DESTROYED
|
||||
elif self.dead_units:
|
||||
@@ -98,11 +101,12 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC):
|
||||
|
||||
@property
|
||||
def standard_identity(self) -> StandardIdentity:
|
||||
return (
|
||||
StandardIdentity.FRIEND
|
||||
if self.control_point.captured
|
||||
else StandardIdentity.HOSTILE_FAKER
|
||||
)
|
||||
if self.control_point.captured.is_blue:
|
||||
return StandardIdentity.FRIEND
|
||||
elif self.control_point.captured.is_neutral:
|
||||
return StandardIdentity.UNKNOWN
|
||||
else:
|
||||
return StandardIdentity.HOSTILE_FAKER
|
||||
|
||||
@property
|
||||
def is_dead(self) -> bool:
|
||||
@@ -154,10 +158,12 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC):
|
||||
def faction_color(self) -> str:
|
||||
return "BLUE" if self.control_point.captured else "RED"
|
||||
|
||||
def is_friendly(self, to_player: bool) -> bool:
|
||||
def is_friendly(self, to_player: Player) -> bool:
|
||||
if self.control_point.captured.is_neutral:
|
||||
return False
|
||||
return self.control_point.is_friendly(to_player)
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if self.is_friendly(for_player):
|
||||
@@ -360,7 +366,7 @@ class BuildingGroundObject(TheaterGroundObject):
|
||||
|
||||
|
||||
class NavalGroundObject(TheaterGroundObject, ABC):
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
@@ -466,7 +472,7 @@ class MissileSiteGroundObject(TheaterGroundObject):
|
||||
def should_head_to_conflict(self) -> bool:
|
||||
return True
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
@@ -507,7 +513,7 @@ class CoastalSiteGroundObject(TheaterGroundObject):
|
||||
def should_head_to_conflict(self) -> bool:
|
||||
return True
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
@@ -534,7 +540,7 @@ class IadsGroundObject(TheaterGroundObject, ABC):
|
||||
task=task,
|
||||
)
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
@@ -571,6 +577,8 @@ class SamGroundObject(IadsGroundObject):
|
||||
|
||||
@property
|
||||
def sidc_status(self) -> Status:
|
||||
if self.control_point.captured.is_neutral:
|
||||
return Status.PRESENT
|
||||
if self.is_dead:
|
||||
return Status.PRESENT_DESTROYED
|
||||
elif self.dead_units:
|
||||
@@ -585,7 +593,7 @@ class SamGroundObject(IadsGroundObject):
|
||||
def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]:
|
||||
return SymbolSet.LAND_UNIT, LandUnitEntity.AIR_DEFENSE
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
@@ -642,7 +650,7 @@ class VehicleGroupGroundObject(TheaterGroundObject):
|
||||
def should_head_to_conflict(self) -> bool:
|
||||
return True
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
@@ -697,7 +705,7 @@ class ShipGroundObject(NavalGroundObject):
|
||||
|
||||
|
||||
class IadsBuildingGroundObject(BuildingGroundObject):
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
|
||||
@@ -8,7 +8,7 @@ from dcs.triggers import TriggerZone
|
||||
from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType, VehicleType
|
||||
|
||||
from game.data.radar_db import LAUNCHER_TRACKER_PAIRS, TELARS, TRACK_RADARS
|
||||
from game.data.units import ANTI_AIR_UNIT_CLASSES
|
||||
from game.data.units import ANTI_AIR_UNIT_CLASSES, UnitClass
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.dcs.shipunittype import ShipUnitType
|
||||
from game.dcs.unittype import UnitType
|
||||
@@ -82,9 +82,17 @@ class TheaterUnit:
|
||||
iads = self.ground_object.control_point.coalition.game.theater.iads_network
|
||||
iads.update_tgo(self.ground_object, events)
|
||||
if self.ground_object.is_naval_control_point:
|
||||
cp = self.ground_object.control_point
|
||||
for squadron in cp.squadrons:
|
||||
cp.coalition.air_wing.squadrons[squadron.aircraft].remove(squadron)
|
||||
for unit in self.ground_object.units:
|
||||
if (
|
||||
unit.unit_type
|
||||
and unit.unit_type.unit_class is UnitClass.AIRCRAFT_CARRIER
|
||||
and not unit.alive
|
||||
):
|
||||
cp = self.ground_object.control_point
|
||||
for squadron in cp.squadrons:
|
||||
cp.coalition.air_wing.squadrons[squadron.aircraft].remove(
|
||||
squadron
|
||||
)
|
||||
|
||||
def revive(self, events: GameUpdateEvents) -> None:
|
||||
self.alive = True
|
||||
|
||||
@@ -9,6 +9,7 @@ from typing import Dict, Iterator, List, Optional, Set, Tuple
|
||||
|
||||
from .conflicttheater import ConflictTheater
|
||||
from .controlpoint import ControlPoint
|
||||
from .player import Player
|
||||
|
||||
|
||||
class NoPathError(RuntimeError):
|
||||
@@ -152,7 +153,7 @@ class TransitNetwork:
|
||||
|
||||
|
||||
class TransitNetworkBuilder:
|
||||
def __init__(self, theater: ConflictTheater, for_player: bool) -> None:
|
||||
def __init__(self, theater: ConflictTheater, for_player: Player) -> None:
|
||||
self.control_points = list(theater.control_points_for(for_player))
|
||||
self.network = TransitNetwork()
|
||||
self.airports: Set[ControlPoint] = {
|
||||
|
||||
@@ -26,6 +26,7 @@ from game.utils import Distance, meters, nautical_miles
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.theater.player import Player
|
||||
|
||||
|
||||
ThreatPoly = Union[MultiPolygon, Polygon]
|
||||
@@ -187,7 +188,7 @@ class ThreatZones:
|
||||
return min(cap_threat_range, max_distance)
|
||||
|
||||
@classmethod
|
||||
def for_faction(cls, game: Game, player: bool) -> ThreatZones:
|
||||
def for_faction(cls, game: Game, player: Player) -> ThreatZones:
|
||||
"""Generates the threat zones projected by the given coalition.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -38,7 +38,16 @@ from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from functools import singledispatchmethod
|
||||
from typing import Generic, Iterator, List, Optional, Sequence, TYPE_CHECKING, TypeVar
|
||||
from typing import (
|
||||
Any,
|
||||
Generic,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
TYPE_CHECKING,
|
||||
TypeVar,
|
||||
)
|
||||
|
||||
from dcs.mapping import Point
|
||||
|
||||
@@ -50,7 +59,14 @@ from game.dcs.aircrafttype import AircraftType
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.naming import namegen
|
||||
from game.procurement import AircraftProcurementRequest
|
||||
from game.theater import ControlPoint, MissionTarget, ParkingType, Carrier, Airfield
|
||||
from game.theater import (
|
||||
ControlPoint,
|
||||
MissionTarget,
|
||||
ParkingType,
|
||||
Carrier,
|
||||
Airfield,
|
||||
Player,
|
||||
)
|
||||
from game.theater.transitnetwork import (
|
||||
TransitConnection,
|
||||
TransitNetwork,
|
||||
@@ -92,7 +108,7 @@ class TransferOrder:
|
||||
position: ControlPoint = field(init=False)
|
||||
|
||||
#: True if the transfer order belongs to the player.
|
||||
player: bool = field(init=False)
|
||||
player: Player = field(init=False)
|
||||
|
||||
#: The units being transferred.
|
||||
units: dict[GroundUnitType, int]
|
||||
@@ -111,7 +127,7 @@ class TransferOrder:
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.position = self.origin
|
||||
self.player = self.origin.is_friendly(to_player=True)
|
||||
self.player = self.origin.captured
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
@@ -239,7 +255,7 @@ class Airlift(Transport):
|
||||
|
||||
@property
|
||||
def player_owned(self) -> bool:
|
||||
return self.transfer.player
|
||||
return self.transfer.player.is_blue
|
||||
|
||||
def find_escape_route(self) -> Optional[ControlPoint]:
|
||||
# TODO: Move units to closest base.
|
||||
@@ -384,8 +400,10 @@ class MultiGroupTransport(MissionTarget, Transport):
|
||||
self.origin = origin
|
||||
self.transfers: List[TransferOrder] = []
|
||||
|
||||
def is_friendly(self, to_player: bool) -> bool:
|
||||
return self.origin.captured
|
||||
def is_friendly(self, to_player: Player) -> bool:
|
||||
if self.origin.captured == to_player:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_units(self, transfer: TransferOrder) -> None:
|
||||
self.transfers.append(transfer)
|
||||
@@ -432,7 +450,7 @@ class MultiGroupTransport(MissionTarget, Transport):
|
||||
yield unit_type
|
||||
|
||||
@property
|
||||
def player_owned(self) -> bool:
|
||||
def player_owned(self) -> Player:
|
||||
return self.origin.captured
|
||||
|
||||
def find_escape_route(self) -> Optional[ControlPoint]:
|
||||
@@ -450,7 +468,7 @@ class Convoy(MultiGroupTransport):
|
||||
def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None:
|
||||
super().__init__(namegen.next_convoy_name(), origin, destination)
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
if self.is_friendly(for_player):
|
||||
return
|
||||
|
||||
@@ -476,7 +494,7 @@ class CargoShip(MultiGroupTransport):
|
||||
def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None:
|
||||
super().__init__(namegen.next_cargo_ship_name(), origin, destination)
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
def mission_types(self, for_player: Player) -> Iterator[FlightType]:
|
||||
if self.is_friendly(for_player):
|
||||
return
|
||||
|
||||
@@ -570,13 +588,25 @@ class CargoShipMap(TransportMap[CargoShip]):
|
||||
|
||||
|
||||
class PendingTransfers:
|
||||
def __init__(self, game: Game, player: bool) -> None:
|
||||
def __init__(self, game: Game, player: Player) -> None:
|
||||
self.game = game
|
||||
self.player = player
|
||||
self.convoys = ConvoyMap()
|
||||
self.cargo_ships = CargoShipMap()
|
||||
self.pending_transfers: List[TransferOrder] = []
|
||||
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
# Migration: Convert old boolean player values to Player enum
|
||||
if "player" in state and isinstance(state["player"], bool):
|
||||
from game.theater.player import Player
|
||||
|
||||
if state["player"]:
|
||||
state["player"] = Player.BLUE
|
||||
else:
|
||||
state["player"] = Player.RED
|
||||
|
||||
self.__dict__.update(state)
|
||||
|
||||
def __iter__(self) -> Iterator[TransferOrder]:
|
||||
yield from self.pending_transfers
|
||||
|
||||
|
||||
@@ -184,5 +184,8 @@ VERSION = _build_version_string()
|
||||
#: * Support for defining squadron sizes.
|
||||
#: * Definition of "spawn-routes" allowing convoys to spawn on the road
|
||||
#: please note that an insufficiently long route can cause trouble in case of large convoys
|
||||
#:
|
||||
#: Version 10.8
|
||||
#: * Neutral base support, neutral FOB support, invisible FOBs, and control point influence zones
|
||||
|
||||
CAMPAIGN_FORMAT_VERSION = (10, 7)
|
||||
CAMPAIGN_FORMAT_VERSION = (10, 8)
|
||||
|
||||
@@ -22,6 +22,7 @@ from .hercules import *
|
||||
from .highdigitsams import *
|
||||
from .irondome import *
|
||||
from .jas39 import *
|
||||
from .mam import *
|
||||
from .mig31bm import *
|
||||
from .mirage3 import *
|
||||
from .oh6 import *
|
||||
|
||||
@@ -152,18 +152,21 @@ class B_47(PlaneType):
|
||||
|
||||
property_defaults: Dict[str, Any] = {}
|
||||
|
||||
properties = {}
|
||||
|
||||
livery_name = "B_47" # from type
|
||||
|
||||
class Pylon1:
|
||||
GAM_63_RASCAL = (1, WeaponsColdWarAssets.GAM_63_RASCAL)
|
||||
GAM_63_RASCAL = (1, Weapons.GAM_63_RASCAL)
|
||||
|
||||
class Pylon2:
|
||||
Mk_53 = (2, WeaponsColdWarAssets.Mk_53)
|
||||
Mk_53 = (2, Weapons.Mk_53)
|
||||
# ERRR {72CAC282-AE18-490B-BD4D-35E7EE969E73}
|
||||
# ERRR {B84DFE16-6AC7-4854-8F6D-34137892E166}
|
||||
Mk_84_28 = (2, Weapons.Mk_84_28)
|
||||
# ERRR {F092B80C-BB54-477E-9408-66DEEF740008}
|
||||
# ERRR {574EDEDF-20DE-4942-B2A2-B2EDFD621562}
|
||||
|
||||
# ERRR {F092B80C-BB54-477E-9408-66DEEF740008}
|
||||
# ERRR {574EDEDF-20DE-4942-B2A2-B2EDFD621562}
|
||||
|
||||
pylons: Set[int] = {1, 2}
|
||||
|
||||
@@ -176,7 +179,6 @@ class B_47(PlaneType):
|
||||
task.CAS,
|
||||
task.Reconnaissance,
|
||||
]
|
||||
|
||||
task_default = task.AntishipStrike
|
||||
|
||||
|
||||
@@ -197,26 +199,23 @@ class B_58(PlaneType):
|
||||
livery_name = "B_58" # from type
|
||||
|
||||
class Pylon1:
|
||||
B_43 = (1, WeaponsColdWarAssets.B_43)
|
||||
B_43 = (1, Weapons.B_43)
|
||||
Mk_84___2000lb_GP_Bomb_LD = (1, Weapons.Mk_84___2000lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon2:
|
||||
B_43 = (2, WeaponsColdWarAssets.B_43)
|
||||
B_43 = (2, Weapons.B_43)
|
||||
Mk_84___2000lb_GP_Bomb_LD = (2, Weapons.Mk_84___2000lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon3:
|
||||
B_43 = (3, WeaponsColdWarAssets.B_43)
|
||||
B_43 = (3, Weapons.B_43)
|
||||
Mk_84___2000lb_GP_Bomb_LD = (3, Weapons.Mk_84___2000lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon4:
|
||||
B_43 = (4, WeaponsColdWarAssets.B_43)
|
||||
B_43 = (4, Weapons.B_43)
|
||||
Mk_84___2000lb_GP_Bomb_LD = (4, Weapons.Mk_84___2000lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon5:
|
||||
W_53_H_Bomb_with_fuel_tank = (
|
||||
5,
|
||||
WeaponsColdWarAssets.W_53_H_Bomb_with_fuel_tank,
|
||||
)
|
||||
W_53_H_Bomb_with_fuel_tank = (5, Weapons.W_53_H_Bomb_with_fuel_tank)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5}
|
||||
|
||||
@@ -246,16 +245,17 @@ class Tu_4K(PlaneType):
|
||||
}
|
||||
|
||||
class Properties:
|
||||
|
||||
class Belly_Bay_Door:
|
||||
id = "Belly Bay Door"
|
||||
|
||||
livery_name = "TU-4K" # from type
|
||||
|
||||
class Pylon1:
|
||||
KS_1 = (1, WeaponsColdWarAssets.KS_1)
|
||||
KS_1 = (1, Weapons.KS_1)
|
||||
|
||||
class Pylon2:
|
||||
KS_1 = (2, WeaponsColdWarAssets.KS_1)
|
||||
KS_1 = (2, Weapons.KS_1)
|
||||
|
||||
pylons: Set[int] = {1, 2}
|
||||
|
||||
@@ -280,44 +280,40 @@ class Tu_16(PlaneType):
|
||||
|
||||
property_defaults: Dict[str, Any] = {}
|
||||
|
||||
properties = {}
|
||||
|
||||
livery_name = "TU-16" # from type
|
||||
|
||||
class Pylon1:
|
||||
KS_1_late = (1, WeaponsColdWarAssets.KS_1_late)
|
||||
KSR_2 = (1, WeaponsColdWarAssets.KSR_2)
|
||||
KSR_2_086__Passive_seeker_ = (
|
||||
1,
|
||||
WeaponsColdWarAssets.KSR_2_086__Passive_seeker_,
|
||||
)
|
||||
KSR_2D_decoy_missile = (1, WeaponsColdWarAssets.KSR_2D_decoy_missile)
|
||||
KSR5P__Passive_seeker_ = (1, WeaponsColdWarAssets.KSR5P__Passive_seeker_)
|
||||
KSR_5 = (1, WeaponsColdWarAssets.KSR_5)
|
||||
KS_1_late = (1, Weapons.KS_1_late)
|
||||
KSR_2 = (1, Weapons.KSR_2)
|
||||
KSR_2_086__Passive_seeker_ = (1, Weapons.KSR_2_086__Passive_seeker_)
|
||||
KSR_2D_decoy_missile = (1, Weapons.KSR_2D_decoy_missile)
|
||||
KSR5P__Passive_seeker_ = (1, Weapons.KSR5P__Passive_seeker_)
|
||||
KSR_5 = (1, Weapons.KSR_5)
|
||||
|
||||
class Pylon2:
|
||||
FAB_3000_M54 = (2, WeaponsColdWarAssets.FAB_3000_M54)
|
||||
FAB_9000_M54 = (2, WeaponsColdWarAssets.FAB_9000_M54)
|
||||
RDS_37 = (2, WeaponsColdWarAssets.RDS_37)
|
||||
FAB_3000_M54 = (2, Weapons.FAB_3000_M54)
|
||||
FAB_9000_M54 = (2, Weapons.FAB_9000_M54)
|
||||
RDS_37 = (2, Weapons.RDS_37)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon3:
|
||||
_33_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
_33_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons._33_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons._33_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon4:
|
||||
KS_1_late = (4, WeaponsColdWarAssets.KS_1_late)
|
||||
KSR_2 = (4, WeaponsColdWarAssets.KSR_2)
|
||||
KSR_2_086__Passive_seeker_ = (
|
||||
4,
|
||||
WeaponsColdWarAssets.KSR_2_086__Passive_seeker_,
|
||||
)
|
||||
KSR_2D_decoy_missile = (4, WeaponsColdWarAssets.KSR_2D_decoy_missile)
|
||||
KSR5P__Passive_seeker_ = (4, WeaponsColdWarAssets.KSR5P__Passive_seeker_)
|
||||
KSR_5 = (4, WeaponsColdWarAssets.KSR_5)
|
||||
KS_1_late = (4, Weapons.KS_1_late)
|
||||
KSR_2 = (4, Weapons.KSR_2)
|
||||
KSR_2_086__Passive_seeker_ = (4, Weapons.KSR_2_086__Passive_seeker_)
|
||||
KSR_2D_decoy_missile = (4, Weapons.KSR_2D_decoy_missile)
|
||||
KSR5P__Passive_seeker_ = (4, Weapons.KSR5P__Passive_seeker_)
|
||||
KSR_5 = (4, Weapons.KSR_5)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4}
|
||||
|
||||
@@ -350,10 +346,12 @@ class Tu_95K(PlaneType):
|
||||
|
||||
property_defaults: Dict[str, Any] = {}
|
||||
|
||||
properties = {}
|
||||
|
||||
livery_name = "TU_95K" # from type
|
||||
|
||||
class Pylon1:
|
||||
Kh_20 = (1, WeaponsColdWarAssets.Kh_20)
|
||||
Kh_20 = (1, Weapons.Kh_20)
|
||||
|
||||
pylons: Set[int] = {1}
|
||||
|
||||
@@ -387,8 +385,8 @@ class tu_22D(PlaneType):
|
||||
livery_name = "TU_22D" # from type
|
||||
|
||||
class Pylon1:
|
||||
FAB_3000_M54 = (1, WeaponsColdWarAssets.FAB_3000_M54)
|
||||
FAB_9000_M54 = (1, WeaponsColdWarAssets.FAB_9000_M54)
|
||||
FAB_3000_M54 = (1, Weapons.FAB_3000_M54)
|
||||
FAB_9000_M54 = (1, Weapons.FAB_9000_M54)
|
||||
_6_x_FAB_1500_M_54___1500kg_GP_Bombs_LD = (
|
||||
1,
|
||||
Weapons._6_x_FAB_1500_M_54___1500kg_GP_Bombs_LD,
|
||||
@@ -397,9 +395,9 @@ class tu_22D(PlaneType):
|
||||
1,
|
||||
Weapons.MBD3_U2T_with_2_x_FAB_1500_M_54___1500kg_GP_Bombs_LD,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_500_M_62___500kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_FAB_500M_62___500_kg_GP_Bomb_LD = (
|
||||
1,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_500_M_62___500kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_FAB_500M_62___500_kg_GP_Bomb_LD,
|
||||
)
|
||||
RN_24___470kg__nuclear_bomb__free_fall = (
|
||||
1,
|
||||
@@ -409,14 +407,14 @@ class tu_22D(PlaneType):
|
||||
1,
|
||||
Weapons.RN_28___260_kg__nuclear_bomb__free_fall,
|
||||
)
|
||||
RDS_37 = (1, WeaponsColdWarAssets.RDS_37)
|
||||
RDS_37 = (1, Weapons.RDS_37)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon2:
|
||||
_33_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
_33_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
2,
|
||||
Weapons._33_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons._33_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
@@ -455,12 +453,12 @@ class tu_22KD(PlaneType):
|
||||
1,
|
||||
Weapons.Kh_22__AS_4_Kitchen____1000kg__AShM__IN__Act_Pas_Rdr,
|
||||
)
|
||||
Kh_22MA = (1, WeaponsColdWarAssets.Kh_22MA)
|
||||
Kh_22P__Passive_seeker_ = (1, WeaponsColdWarAssets.Kh_22P__Passive_seeker_)
|
||||
Kh_22MA = (1, Weapons.Kh_22MA)
|
||||
Kh_22P__Passive_seeker_ = (1, Weapons.Kh_22P__Passive_seeker_)
|
||||
|
||||
class Pylon2:
|
||||
FAB_3000_M54 = (2, WeaponsColdWarAssets.FAB_3000_M54)
|
||||
FAB_9000_M54 = (2, WeaponsColdWarAssets.FAB_9000_M54)
|
||||
FAB_3000_M54 = (2, Weapons.FAB_3000_M54)
|
||||
FAB_9000_M54 = (2, Weapons.FAB_9000_M54)
|
||||
_6_x_FAB_1500_M_54___1500kg_GP_Bombs_LD = (
|
||||
2,
|
||||
Weapons._6_x_FAB_1500_M_54___1500kg_GP_Bombs_LD,
|
||||
@@ -469,18 +467,18 @@ class tu_22KD(PlaneType):
|
||||
2,
|
||||
Weapons.MBD3_U2T_with_2_x_FAB_1500_M_54___1500kg_GP_Bombs_LD,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_500_M_62___500kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_FAB_500M_62___500_kg_GP_Bomb_LD = (
|
||||
2,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_500_M_62___500kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_FAB_500M_62___500_kg_GP_Bomb_LD,
|
||||
)
|
||||
RDS_37 = (1, WeaponsColdWarAssets.RDS_37)
|
||||
RDS_37 = (2, Weapons.RDS_37)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon3:
|
||||
_33_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
_33_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons._33_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons._33_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
@@ -517,20 +515,20 @@ class Yak_28(PlaneType):
|
||||
1,
|
||||
Weapons.APU_13U_2_with_R_3S__AA_2_Atoll_B____IR_AAM,
|
||||
)
|
||||
R_8M1R = (1, WeaponsColdWarAssets.R_8M1R_Yak_28)
|
||||
R_8M1T = (1, WeaponsColdWarAssets.R_8M1T_Yak_28)
|
||||
R_98MT = (1, WeaponsColdWarAssets.R_98MT_Yak_28)
|
||||
R_98MR = (1, WeaponsColdWarAssets.R_98MR_Yak_28)
|
||||
R_8M1R = (1, Weapons.R_8M1R)
|
||||
R_8M1T = (1, Weapons.R_8M1T)
|
||||
R_98MT = (1, Weapons.R_98MT)
|
||||
R_98MR = (1, Weapons.R_98MR)
|
||||
|
||||
class Pylon2:
|
||||
APU_13U_2_with_R_3S__AA_2_Atoll_B____IR_AAM = (
|
||||
2,
|
||||
Weapons.APU_13U_2_with_R_3S__AA_2_Atoll_B____IR_AAM,
|
||||
)
|
||||
R_8M1R = (2, WeaponsColdWarAssets.R_8M1R_Yak_28)
|
||||
R_8M1T = (2, WeaponsColdWarAssets.R_8M1T_Yak_28)
|
||||
R_98MT = (2, WeaponsColdWarAssets.R_98MT_Yak_28)
|
||||
R_98MR = (2, WeaponsColdWarAssets.R_98MR_Yak_28)
|
||||
R_8M1R = (2, Weapons.R_8M1R)
|
||||
R_8M1T = (2, Weapons.R_8M1T)
|
||||
R_98MT = (2, Weapons.R_98MT)
|
||||
R_98MR = (2, Weapons.R_98MR)
|
||||
ORO_57K___S_5M_x_8 = (2, Weapons.ORO_57K___S_5M_x_8)
|
||||
|
||||
class Pylon3:
|
||||
@@ -546,25 +544,29 @@ class Yak_28(PlaneType):
|
||||
3,
|
||||
Weapons.FAB_1500_M_54___1500kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U4T_with_4_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U4T___4_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U4T_with_4_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U4T___4_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_3_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___3_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U6_68_with_3_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___3_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
FAB_500_M54_TU___480_kg__bomb__parachute = (
|
||||
3,
|
||||
Weapons.FAB_500_M54_TU___480_kg__bomb__parachute,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
|
||||
class Pylon4:
|
||||
@@ -572,20 +574,20 @@ class Yak_28(PlaneType):
|
||||
4,
|
||||
Weapons.APU_13U_2_with_R_3S__AA_2_Atoll_B____IR_AAM,
|
||||
)
|
||||
R_8M1R = (4, WeaponsColdWarAssets.R_8M1R_Yak_28)
|
||||
R_8M1T = (4, WeaponsColdWarAssets.R_8M1T_Yak_28)
|
||||
R_98MT = (4, WeaponsColdWarAssets.R_98MT_Yak_28)
|
||||
R_98MR = (4, WeaponsColdWarAssets.R_98MR_Yak_28)
|
||||
R_8M1R = (4, Weapons.R_8M1R)
|
||||
R_8M1T = (4, Weapons.R_8M1T)
|
||||
R_98MT = (4, Weapons.R_98MT)
|
||||
R_98MR = (4, Weapons.R_98MR)
|
||||
|
||||
class Pylon5:
|
||||
APU_13U_2_with_R_3S__AA_2_Atoll_B____IR_AAM = (
|
||||
5,
|
||||
Weapons.APU_13U_2_with_R_3S__AA_2_Atoll_B____IR_AAM,
|
||||
)
|
||||
R_8M1R = (5, WeaponsColdWarAssets.R_8M1R_Yak_28)
|
||||
R_8M1T = (5, WeaponsColdWarAssets.R_8M1T_Yak_28)
|
||||
R_98MT = (5, WeaponsColdWarAssets.R_98MT_Yak_28)
|
||||
R_98MR = (5, WeaponsColdWarAssets.R_98MR_Yak_28)
|
||||
R_8M1R = (5, Weapons.R_8M1R)
|
||||
R_8M1T = (5, Weapons.R_8M1T)
|
||||
R_98MT = (5, Weapons.R_98MT)
|
||||
R_98MR = (5, Weapons.R_98MR)
|
||||
ORO_57K___S_5M_x_8 = (5, Weapons.ORO_57K___S_5M_x_8)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5}
|
||||
@@ -618,6 +620,8 @@ class Tu_126(PlaneType):
|
||||
|
||||
property_defaults: Dict[str, Any] = {}
|
||||
|
||||
properties = {}
|
||||
|
||||
livery_name = "TU_126" # from type
|
||||
|
||||
pylons: Set[int] = set()
|
||||
@@ -645,20 +649,20 @@ class Tu_128M(PlaneType):
|
||||
livery_name = "TU_128M" # from type
|
||||
|
||||
class Pylon1:
|
||||
R_4RM = (1, WeaponsColdWarAssets.R_4RM)
|
||||
R_4TM = (1, WeaponsColdWarAssets.R_4TM)
|
||||
R_4RM = (1, Weapons.R_4RM)
|
||||
R_4TM = (1, Weapons.R_4TM)
|
||||
|
||||
class Pylon2:
|
||||
R_4RM = (2, WeaponsColdWarAssets.R_4RM)
|
||||
R_4TM = (2, WeaponsColdWarAssets.R_4TM)
|
||||
R_4RM = (2, Weapons.R_4RM)
|
||||
R_4TM = (2, Weapons.R_4TM)
|
||||
|
||||
class Pylon3:
|
||||
R_4RM = (3, WeaponsColdWarAssets.R_4RM)
|
||||
R_4TM = (3, WeaponsColdWarAssets.R_4TM)
|
||||
R_4RM = (3, Weapons.R_4RM)
|
||||
R_4TM = (3, Weapons.R_4TM)
|
||||
|
||||
class Pylon4:
|
||||
R_4RM = (4, WeaponsColdWarAssets.R_4RM)
|
||||
R_4TM = (4, WeaponsColdWarAssets.R_4TM)
|
||||
R_4RM = (4, Weapons.R_4RM)
|
||||
R_4TM = (4, Weapons.R_4TM)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1
pydcs_extensions/mam/__init__.py
Normal file
1
pydcs_extensions/mam/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .mam import *
|
||||
468
pydcs_extensions/mam/mam.py
Normal file
468
pydcs_extensions/mam/mam.py
Normal file
@@ -0,0 +1,468 @@
|
||||
from typing import Any, Dict, Set
|
||||
|
||||
from dcs import task
|
||||
from dcs.planes import PlaneType
|
||||
from dcs.weapons_data import Weapons
|
||||
|
||||
from game.modsupport import planemod
|
||||
from pydcs_extensions.weapon_injector import inject_weapons
|
||||
|
||||
|
||||
class WeaponsB2:
|
||||
|
||||
B2_AGM_154C_8 = {
|
||||
"clsid": "{B2_AGM-154C*8}",
|
||||
"name": "B2 AGM-154C*8",
|
||||
"weight": 3872,
|
||||
}
|
||||
B2_CBU87_18 = {"clsid": "{B2_CBU87*18}", "name": "B2 CBU87*18", "weight": 7740}
|
||||
B2_CBU_97_18 = {"clsid": "{B2_CBU97*18}", "name": "B2 CBU-97*18", "weight": 7506}
|
||||
B2_GBU_27_4 = {"clsid": "{B2_GBU-27*4}", "name": "B2 GBU-27*4", "weight": 4800}
|
||||
B2_GBU_28_4 = {"clsid": "{B2_GBU-28*4}", "name": "B2 GBU-28*4", "weight": 8520}
|
||||
B2_GBU_38_40 = {"clsid": "{B2_GBU-38*40}", "name": "B2 GBU-38*40", "weight": 9640}
|
||||
B2_Mk_82_40 = {"clsid": "{B2_Mk82*40}", "name": "B2 Mk-82*40", "weight": 9640}
|
||||
|
||||
|
||||
inject_weapons(WeaponsB2)
|
||||
|
||||
|
||||
@planemod
|
||||
class A400M_Atlas(PlaneType):
|
||||
id = "A400M_Atlas"
|
||||
height = 11.66
|
||||
width = 40.4
|
||||
length = 29.79
|
||||
fuel_max = 20830
|
||||
max_speed = 621
|
||||
chaff = 120
|
||||
flare = 60
|
||||
charge_total = 240
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
|
||||
radio_frequency = 127.5
|
||||
|
||||
livery_name = "A400M_ATLAS" # from type
|
||||
|
||||
pylons: Set[int] = set()
|
||||
|
||||
tasks = [task.Transport]
|
||||
task_default = task.Transport
|
||||
|
||||
|
||||
@planemod
|
||||
class B2_Spirit(PlaneType):
|
||||
id = "B2_Spirit"
|
||||
group_size_max = 1
|
||||
height = 10.36
|
||||
width = 41.67
|
||||
length = 44.81
|
||||
fuel_max = 88450
|
||||
max_speed = 1329.84
|
||||
chaff = 60
|
||||
flare = 30
|
||||
charge_total = 120
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
eplrs = True
|
||||
radio_frequency = 127.5
|
||||
|
||||
livery_name = "B2_SPIRIT" # from type
|
||||
|
||||
class Pylon1:
|
||||
B2_Mk_82_40 = (1, WeaponsB2.B2_Mk_82_40)
|
||||
B2_CBU87_18 = (1, WeaponsB2.B2_CBU87_18)
|
||||
B2_CBU_97_18 = (1, WeaponsB2.B2_CBU_97_18)
|
||||
B2_GBU_38_40 = (1, WeaponsB2.B2_GBU_38_40)
|
||||
B2_GBU_28_4 = (1, WeaponsB2.B2_GBU_28_4)
|
||||
B2_GBU_27_4 = (1, WeaponsB2.B2_GBU_27_4)
|
||||
B2_AGM_154C_8 = (1, WeaponsB2.B2_AGM_154C_8)
|
||||
B_1B_Mk_84_8 = (1, Weapons.B_1B_Mk_84_8)
|
||||
|
||||
class Pylon2:
|
||||
B2_Mk_82_40 = (2, WeaponsB2.B2_Mk_82_40)
|
||||
B2_CBU87_18 = (2, WeaponsB2.B2_CBU87_18)
|
||||
B2_CBU_97_18 = (2, WeaponsB2.B2_CBU_97_18)
|
||||
B2_GBU_38_40 = (2, WeaponsB2.B2_GBU_38_40)
|
||||
B2_GBU_28_4 = (2, WeaponsB2.B2_GBU_28_4)
|
||||
B2_GBU_27_4 = (2, WeaponsB2.B2_GBU_27_4)
|
||||
B2_AGM_154C_8 = (2, WeaponsB2.B2_AGM_154C_8)
|
||||
B_1B_Mk_84_8 = (2, Weapons.B_1B_Mk_84_8)
|
||||
|
||||
pylons: Set[int] = {1, 2}
|
||||
|
||||
tasks = [task.GroundAttack, task.RunwayAttack, task.PinpointStrike, task.CAS]
|
||||
task_default = task.GroundAttack
|
||||
|
||||
|
||||
@planemod
|
||||
class C2A_Greyhound(PlaneType):
|
||||
id = "C2A_Greyhound"
|
||||
group_size_max = 1
|
||||
height = 4.85
|
||||
width = 24.6
|
||||
length = 17.3
|
||||
fuel_max = 5624
|
||||
max_speed = 625.68
|
||||
chaff = 120
|
||||
flare = 60
|
||||
charge_total = 240
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
eplrs = True
|
||||
radio_frequency = 127.5
|
||||
|
||||
livery_name = "C2A_GREYHOUND" # from type
|
||||
|
||||
pylons: Set[int] = set()
|
||||
|
||||
tasks = [task.Transport]
|
||||
task_default = task.Transport
|
||||
|
||||
|
||||
@planemod
|
||||
class C5_Galaxy(PlaneType):
|
||||
id = "C5_Galaxy"
|
||||
group_size_max = 1
|
||||
height = 16.79
|
||||
width = 60.89
|
||||
length = 53.04
|
||||
fuel_max = 157768
|
||||
max_speed = 856.008
|
||||
chaff = 120
|
||||
flare = 60
|
||||
charge_total = 240
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
|
||||
radio_frequency = 127.5
|
||||
|
||||
livery_name = "C5_GALAXY" # from type
|
||||
|
||||
pylons: Set[int] = set()
|
||||
|
||||
tasks = [task.Transport]
|
||||
task_default = task.Transport
|
||||
|
||||
|
||||
@planemod
|
||||
class KC_10_Extender(PlaneType):
|
||||
id = "KC_10_Extender"
|
||||
group_size_max = 1
|
||||
height = 17.7
|
||||
width = 50.41
|
||||
length = 55.35
|
||||
fuel_max = 160200
|
||||
max_speed = 996.012
|
||||
chaff = 120
|
||||
flare = 60
|
||||
charge_total = 240
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
tacan = True
|
||||
category = "Tankers" # {8A302789-A55D-4897-B647-66493FA6826F}
|
||||
|
||||
livery_name = "KC_10_EXTENDER" # from type
|
||||
|
||||
pylons: Set[int] = set()
|
||||
|
||||
tasks = [task.Transport, task.Refueling]
|
||||
task_default = task.Refueling
|
||||
|
||||
|
||||
@planemod
|
||||
class KC_10_Extender_D(PlaneType):
|
||||
id = "KC_10_Extender_D"
|
||||
group_size_max = 1
|
||||
height = 17.7
|
||||
width = 50.41
|
||||
length = 55.35
|
||||
fuel_max = 154000
|
||||
max_speed = 804.996
|
||||
chaff = 120
|
||||
flare = 60
|
||||
charge_total = 240
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
tacan = True
|
||||
category = "Tankers" # {8A302789-A55D-4897-B647-66493FA6826F}
|
||||
|
||||
livery_name = "KC_10_EXTENDER_D" # from type
|
||||
|
||||
pylons: Set[int] = set()
|
||||
|
||||
tasks = [task.Transport, task.Refueling]
|
||||
task_default = task.Refueling
|
||||
|
||||
|
||||
@planemod
|
||||
class P3C_Orion(PlaneType):
|
||||
id = "P3C_Orion"
|
||||
group_size_max = 1
|
||||
height = 10.27
|
||||
width = 30.37
|
||||
length = 35.61
|
||||
fuel_max = 28350
|
||||
max_speed = 1479.6
|
||||
chaff = 120
|
||||
flare = 60
|
||||
charge_total = 240
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
eplrs = True
|
||||
radio_frequency = 127.5
|
||||
|
||||
livery_name = "P3C_ORION" # from type
|
||||
|
||||
class Pylon1:
|
||||
Smokewinder___red = (1, Weapons.Smokewinder___red)
|
||||
Smokewinder___green = (1, Weapons.Smokewinder___green)
|
||||
Smokewinder___blue = (1, Weapons.Smokewinder___blue)
|
||||
Smokewinder___white = (1, Weapons.Smokewinder___white)
|
||||
Smokewinder___yellow = (1, Weapons.Smokewinder___yellow)
|
||||
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
|
||||
LAU_115_LAU_127_AIM_9L = (1, Weapons.LAU_115_LAU_127_AIM_9L)
|
||||
Mk_82___500lb_GP_Bomb_LD = (1, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
1,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
AGM_84D_Harpoon_AShM = (1, Weapons.AGM_84D_Harpoon_AShM)
|
||||
LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE = (
|
||||
1,
|
||||
Weapons.LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE,
|
||||
)
|
||||
|
||||
class Pylon2:
|
||||
LAU_115_LAU_127_AIM_9L = (2, Weapons.LAU_115_LAU_127_AIM_9L)
|
||||
Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
2,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = (
|
||||
2,
|
||||
Weapons.MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets,
|
||||
)
|
||||
AGM_84D_Harpoon_AShM = (2, Weapons.AGM_84D_Harpoon_AShM)
|
||||
AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = (
|
||||
2,
|
||||
Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_,
|
||||
)
|
||||
LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = (
|
||||
2,
|
||||
Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_,
|
||||
)
|
||||
LAU_117_AGM_65F = (2, Weapons.LAU_117_AGM_65F)
|
||||
LAU_117_AGM_65G = (2, Weapons.LAU_117_AGM_65G)
|
||||
LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE = (
|
||||
2,
|
||||
Weapons.LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE,
|
||||
)
|
||||
LTF_5b_Aerial_Torpedo = (2, Weapons.LTF_5b_Aerial_Torpedo)
|
||||
|
||||
class Pylon3:
|
||||
Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = (
|
||||
3,
|
||||
Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD,
|
||||
)
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
3,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = (
|
||||
3,
|
||||
Weapons.MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets,
|
||||
)
|
||||
AGM_84D_Harpoon_AShM = (3, Weapons.AGM_84D_Harpoon_AShM)
|
||||
AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = (
|
||||
3,
|
||||
Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_,
|
||||
)
|
||||
LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = (
|
||||
3,
|
||||
Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_,
|
||||
)
|
||||
LAU_117_AGM_65F = (3, Weapons.LAU_117_AGM_65F)
|
||||
LAU_117_AGM_65G = (3, Weapons.LAU_117_AGM_65G)
|
||||
LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE = (
|
||||
3,
|
||||
Weapons.LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE,
|
||||
)
|
||||
LTF_5b_Aerial_Torpedo = (3, Weapons.LTF_5b_Aerial_Torpedo)
|
||||
|
||||
class Pylon4:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
4,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (4, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon5:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
5,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (5, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
LTF_5b_Aerial_Torpedo = (5, Weapons.LTF_5b_Aerial_Torpedo)
|
||||
|
||||
class Pylon6:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
6,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (6, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_83___1000lb_GP_Bomb_LD = (6, Weapons.Mk_83___1000lb_GP_Bomb_LD)
|
||||
LTF_5b_Aerial_Torpedo = (6, Weapons.LTF_5b_Aerial_Torpedo)
|
||||
|
||||
class Pylon7:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
7,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (7, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_83___1000lb_GP_Bomb_LD = (7, Weapons.Mk_83___1000lb_GP_Bomb_LD)
|
||||
LTF_5b_Aerial_Torpedo = (7, Weapons.LTF_5b_Aerial_Torpedo)
|
||||
|
||||
class Pylon8:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
8,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_83___1000lb_GP_Bomb_LD = (8, Weapons.Mk_83___1000lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon9:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
9,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (9, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_83___1000lb_GP_Bomb_LD = (9, Weapons.Mk_83___1000lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon10:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
10,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (10, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon11:
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
11,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
Mk_82___500lb_GP_Bomb_LD = (11, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
|
||||
class Pylon12:
|
||||
Mk_82___500lb_GP_Bomb_LD = (12, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = (
|
||||
12,
|
||||
Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD,
|
||||
)
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
12,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = (
|
||||
12,
|
||||
Weapons.MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets,
|
||||
)
|
||||
AGM_84D_Harpoon_AShM = (12, Weapons.AGM_84D_Harpoon_AShM)
|
||||
AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = (
|
||||
12,
|
||||
Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_,
|
||||
)
|
||||
LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = (
|
||||
12,
|
||||
Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_,
|
||||
)
|
||||
LAU_117_AGM_65F = (12, Weapons.LAU_117_AGM_65F)
|
||||
LAU_117_AGM_65G = (12, Weapons.LAU_117_AGM_65G)
|
||||
LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE = (
|
||||
12,
|
||||
Weapons.LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE,
|
||||
)
|
||||
LTF_5b_Aerial_Torpedo = (12, Weapons.LTF_5b_Aerial_Torpedo)
|
||||
|
||||
class Pylon13:
|
||||
LAU_115_LAU_127_AIM_9L = (13, Weapons.LAU_115_LAU_127_AIM_9L)
|
||||
Mk_82___500lb_GP_Bomb_LD = (13, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
13,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = (
|
||||
13,
|
||||
Weapons.MER2_with_2_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets,
|
||||
)
|
||||
AGM_84D_Harpoon_AShM = (13, Weapons.AGM_84D_Harpoon_AShM)
|
||||
AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = (
|
||||
13,
|
||||
Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_,
|
||||
)
|
||||
LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = (
|
||||
13,
|
||||
Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_,
|
||||
)
|
||||
LAU_117_AGM_65F = (13, Weapons.LAU_117_AGM_65F)
|
||||
LAU_117_AGM_65G = (13, Weapons.LAU_117_AGM_65G)
|
||||
LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE = (
|
||||
13,
|
||||
Weapons.LAU_10___4_x_UnGd_Rkts__127_mm_Zuni_Mk__24_Mod__1_HE,
|
||||
)
|
||||
|
||||
class Pylon14:
|
||||
Smokewinder___red = (14, Weapons.Smokewinder___red)
|
||||
Smokewinder___green = (14, Weapons.Smokewinder___green)
|
||||
Smokewinder___blue = (14, Weapons.Smokewinder___blue)
|
||||
Smokewinder___white = (14, Weapons.Smokewinder___white)
|
||||
Smokewinder___yellow = (14, Weapons.Smokewinder___yellow)
|
||||
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (14, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
|
||||
LAU_115_LAU_127_AIM_9L = (14, Weapons.LAU_115_LAU_127_AIM_9L)
|
||||
Mk_82___500lb_GP_Bomb_LD = (14, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = (
|
||||
14,
|
||||
Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets,
|
||||
)
|
||||
AGM_84D_Harpoon_AShM = (14, Weapons.AGM_84D_Harpoon_AShM)
|
||||
LTF_5b_Aerial_Torpedo = (14, Weapons.LTF_5b_Aerial_Torpedo)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
|
||||
|
||||
tasks = [
|
||||
task.Transport,
|
||||
task.Reconnaissance,
|
||||
task.GroundAttack,
|
||||
task.CAS,
|
||||
task.AFAC,
|
||||
task.RunwayAttack,
|
||||
task.AntishipStrike,
|
||||
]
|
||||
task_default = task.AntishipStrike
|
||||
|
||||
|
||||
@planemod
|
||||
class V22_Osprey(PlaneType):
|
||||
id = "V22_Osprey"
|
||||
group_size_max = 1
|
||||
height = 6.63
|
||||
width = 25.78
|
||||
length = 17.48
|
||||
fuel_max = 3519.423
|
||||
max_speed = 990
|
||||
chaff = 120
|
||||
flare = 60
|
||||
charge_total = 240
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
eplrs = True
|
||||
category = "Air" # {C168A850-3C0B-436a-95B5-C4A015552560}
|
||||
|
||||
livery_name = "V22_OSPREY" # from type
|
||||
|
||||
pylons: Set[int] = set()
|
||||
|
||||
tasks = [task.Transport]
|
||||
task_default = task.Transport
|
||||
@@ -580,9 +580,9 @@ class CH_Ka52K(HelicopterType):
|
||||
1,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (1, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (1, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (1, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (1, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (1, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (1, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (1, Weapons.Fuel_tank_PTB_450)
|
||||
APU_6___6_x_9M127_Vikhr___ATGM__LOSBR__Tandem_HEAT_Frag = (
|
||||
1,
|
||||
@@ -625,9 +625,9 @@ class CH_Ka52K(HelicopterType):
|
||||
2,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (2, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (2, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (2, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (2, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (2, Weapons.Fuel_tank_PTB_450)
|
||||
APU_6___6_x_9M127_Vikhr___ATGM__LOSBR__Tandem_HEAT_Frag = (
|
||||
2,
|
||||
@@ -673,9 +673,9 @@ class CH_Ka52K(HelicopterType):
|
||||
3,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (3, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (3, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (3, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (3, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (3, Weapons.Fuel_tank_PTB_450)
|
||||
APU_6___6_x_9M127_Vikhr___ATGM__LOSBR__Tandem_HEAT_Frag = (
|
||||
3,
|
||||
@@ -721,9 +721,9 @@ class CH_Ka52K(HelicopterType):
|
||||
4,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (4, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (4, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (4, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (4, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (4, Weapons.Fuel_tank_PTB_450)
|
||||
APU_6___6_x_9M127_Vikhr___ATGM__LOSBR__Tandem_HEAT_Frag = (
|
||||
4,
|
||||
@@ -797,9 +797,9 @@ class CH_Ka52(HelicopterType):
|
||||
1,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (1, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (1, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (1, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (1, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (1, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (1, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (1, Weapons.Fuel_tank_PTB_450)
|
||||
APU_6___6_x_9M127_Vikhr___ATGM__LOSBR__Tandem_HEAT_Frag = (
|
||||
1,
|
||||
@@ -838,9 +838,9 @@ class CH_Ka52(HelicopterType):
|
||||
2,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (2, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (2, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (2, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (2, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (2, Weapons.Fuel_tank_PTB_450)
|
||||
|
||||
class Pylon3:
|
||||
@@ -867,9 +867,9 @@ class CH_Ka52(HelicopterType):
|
||||
3,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (3, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (3, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (3, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (3, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (3, Weapons.Fuel_tank_PTB_450)
|
||||
|
||||
class Pylon4:
|
||||
@@ -900,9 +900,9 @@ class CH_Ka52(HelicopterType):
|
||||
4,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (4, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (4, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (4, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (4, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (4, Weapons.Fuel_tank_PTB_450)
|
||||
APU_6___6_x_9M127_Vikhr___ATGM__LOSBR__Tandem_HEAT_Frag = (
|
||||
4,
|
||||
@@ -979,9 +979,9 @@ class CH_Mi28N(HelicopterType):
|
||||
1,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (1, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (1, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (1, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (1, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (1, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (1, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (1, Weapons.Fuel_tank_PTB_450)
|
||||
_6_x_9M120_Ataka__AT_9_Spiral_2____ATGM__SACLOS__Tandem_HEAT = (
|
||||
1,
|
||||
@@ -1017,9 +1017,9 @@ class CH_Mi28N(HelicopterType):
|
||||
2,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (2, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (2, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (2, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (2, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (2, Weapons.Fuel_tank_PTB_450)
|
||||
_6_x_9M120_Ataka__AT_9_Spiral_2____ATGM__SACLOS__Tandem_HEAT = (
|
||||
2,
|
||||
@@ -1055,9 +1055,9 @@ class CH_Mi28N(HelicopterType):
|
||||
3,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (3, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (3, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (3, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (3, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (3, Weapons.Fuel_tank_PTB_450)
|
||||
_6_x_9M120_Ataka__AT_9_Spiral_2____ATGM__SACLOS__Tandem_HEAT = (
|
||||
3,
|
||||
@@ -1089,9 +1089,9 @@ class CH_Mi28N(HelicopterType):
|
||||
4,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_250_M62___250_kg_GP_Bomb_LD = (4, Weapons.FAB_250_M62___250_kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (4, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_250M_62___250_kg_GP_Bomb_LD = (4, Weapons.FAB_250M_62___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (4, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
Fuel_tank_PTB_450 = (4, Weapons.Fuel_tank_PTB_450)
|
||||
_6_x_9M120_Ataka__AT_9_Spiral_2____ATGM__SACLOS__Tandem_HEAT = (
|
||||
4,
|
||||
@@ -1136,6 +1136,8 @@ class CH_Tu_95MSM(PlaneType):
|
||||
|
||||
property_defaults: Dict[str, Any] = {}
|
||||
|
||||
properties = {}
|
||||
|
||||
livery_name = "CH_TU-95MSM" # from type
|
||||
|
||||
class Pylon1:
|
||||
|
||||
@@ -40,15 +40,15 @@ class Su_15TM(PlaneType):
|
||||
livery_name = "SU_15TM" # from type
|
||||
|
||||
class Pylon1:
|
||||
R_98MR = (1, WeaponsSu15.R_98MR)
|
||||
R_98MT = (1, WeaponsSu15.R_98MT)
|
||||
R_8M1R = (1, WeaponsSu15.R_8M1R)
|
||||
R_8M1T = (1, WeaponsSu15.R_8M1T)
|
||||
UB_32A_pod___32_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
R_98MR = (1, Weapons.R_98MR)
|
||||
R_98MT = (1, Weapons.R_98MT)
|
||||
R_8M1R = (1, Weapons.R_8M1R)
|
||||
R_8M1T = (1, Weapons.R_8M1T)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
1,
|
||||
Weapons.UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
UB_16UM_pod___16_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
1,
|
||||
Weapons.UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
@@ -56,9 +56,9 @@ class Su_15TM(PlaneType):
|
||||
1,
|
||||
Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
)
|
||||
FAB_100___100kg_GP_Bomb_LD = (1, Weapons.FAB_100___100kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (1, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (1, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_100_120___100_kg_GP_Bomb_LD = (1, Weapons.OFAB_100_120___100_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (1, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (1, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
|
||||
class Pylon2:
|
||||
APU_60_1M_with_R_60__AA_8_Aphid____IR_AAM = (
|
||||
@@ -75,12 +75,12 @@ class Su_15TM(PlaneType):
|
||||
3,
|
||||
Weapons.SPPU_22_1___2_x_23mm__GSh_23L_Autocannon_Pod,
|
||||
)
|
||||
PTB_600 = (3, WeaponsSu15.PTB_600)
|
||||
UB_32A_pod___32_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
PTB_600 = (3, Weapons.PTB_600)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
3,
|
||||
Weapons.UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
UB_16UM_pod___16_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
3,
|
||||
Weapons.UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
@@ -88,21 +88,21 @@ class Su_15TM(PlaneType):
|
||||
3,
|
||||
Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
)
|
||||
FAB_100___100kg_GP_Bomb_LD = (3, Weapons.FAB_100___100kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (3, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_100_120___100_kg_GP_Bomb_LD = (3, Weapons.OFAB_100_120___100_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (3, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
|
||||
class Pylon4:
|
||||
SPPU_22_1___2_x_23mm__GSh_23L_Autocannon_Pod = (
|
||||
4,
|
||||
Weapons.SPPU_22_1___2_x_23mm__GSh_23L_Autocannon_Pod,
|
||||
)
|
||||
PTB_600 = (4, WeaponsSu15.PTB_600)
|
||||
UB_32A_pod___32_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
PTB_600 = (4, Weapons.PTB_600)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
4,
|
||||
Weapons.UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
UB_16UM_pod___16_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
4,
|
||||
Weapons.UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
@@ -110,9 +110,9 @@ class Su_15TM(PlaneType):
|
||||
4,
|
||||
Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
)
|
||||
FAB_100___100kg_GP_Bomb_LD = (4, Weapons.FAB_100___100kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (4, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_100_120___100_kg_GP_Bomb_LD = (4, Weapons.OFAB_100_120___100_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (4, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
|
||||
class Pylon5:
|
||||
APU_60_1M_with_R_60__AA_8_Aphid____IR_AAM = (
|
||||
@@ -125,15 +125,15 @@ class Su_15TM(PlaneType):
|
||||
)
|
||||
|
||||
class Pylon6:
|
||||
R_98MR = (6, WeaponsSu15.R_98MR)
|
||||
R_98MT = (6, WeaponsSu15.R_98MT)
|
||||
R_8M1R = (6, WeaponsSu15.R_8M1R)
|
||||
R_8M1T = (6, WeaponsSu15.R_8M1T)
|
||||
UB_32A_pod___32_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
R_98MR = (6, Weapons.R_98MR)
|
||||
R_98MT = (6, Weapons.R_98MT)
|
||||
R_8M1R = (6, Weapons.R_8M1R)
|
||||
R_8M1T = (6, Weapons.R_8M1T)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
6,
|
||||
Weapons.UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
UB_16UM_pod___16_x_S_5KO__57mm_UnGd_Rkts__HEAT_Frag = (
|
||||
UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
6,
|
||||
Weapons.UB_16_57UMP___16_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag,
|
||||
)
|
||||
@@ -141,9 +141,9 @@ class Su_15TM(PlaneType):
|
||||
6,
|
||||
Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
)
|
||||
FAB_100___100kg_GP_Bomb_LD = (6, Weapons.FAB_100___100kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (6, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (6, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_100_120___100_kg_GP_Bomb_LD = (6, Weapons.OFAB_100_120___100_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (6, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (6, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5, 6}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,17 +9,11 @@ from pydcs_extensions.weapon_injector import inject_weapons
|
||||
|
||||
|
||||
class Su57Weapons:
|
||||
Kh_59MK2 = {"clsid": "{KH_59MK2}", "name": "Kh-59MK2", "weight": None}
|
||||
RVV_AE = {"clsid": "{RVV-AE}", "name": "RVV-AE", "weight": 250}
|
||||
RVV_BD = {"clsid": "{RVV-BD}", "name": "RVV-BD", "weight": 600}
|
||||
RVV_L = {"clsid": "{RVV-L}", "name": "RVV-L", "weight": 748}
|
||||
RVV_M = {"clsid": "{RVV-M}", "name": "RVV-M", "weight": 190}
|
||||
R_37M_Active_Rdr = {"clsid": "{RVV-BD}", "name": "R-37M Active Rdr", "weight": 600}
|
||||
Su_57_Fuel_Tank = {
|
||||
"clsid": "{SU_57Tank}",
|
||||
"name": "Su-57 Fuel Tank",
|
||||
"weight": 1561.421,
|
||||
}
|
||||
R_77PD_Active_rdr = {
|
||||
"clsid": "{RVV-AE}",
|
||||
"name": "R-77PD Active rdr",
|
||||
@@ -56,8 +50,10 @@ class Su_57(PlaneType):
|
||||
|
||||
class Pylon1:
|
||||
R_73__AA_11_Archer____Infra_Red = (1, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
R_77PD_Active_rdr = (1, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (1, Su57Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (1, Weapons.KS_172_Passive_Rdr)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (1, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (1, Weapons.K_77M_Active_Rdr)
|
||||
L_081_Fantasmagoria_ELINT_pod = (1, Weapons.L_081_Fantasmagoria_ELINT_pod)
|
||||
Smoke_Generator___red = (1, Weapons.Smoke_Generator___red)
|
||||
Smoke_Generator___green = (1, Weapons.Smoke_Generator___green)
|
||||
@@ -93,37 +89,37 @@ class Su_57(PlaneType):
|
||||
2,
|
||||
Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr,
|
||||
)
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = (
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_ = (
|
||||
2,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_,
|
||||
)
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = (
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_ = (
|
||||
2,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_,
|
||||
)
|
||||
Kh_59M__AS_18_Kazoo____930kg__ASM__IN = (
|
||||
2,
|
||||
Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
2,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag = (
|
||||
2,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
)
|
||||
B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = (
|
||||
B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
2,
|
||||
Weapons.B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation,
|
||||
)
|
||||
S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = (
|
||||
O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator = (
|
||||
2,
|
||||
Weapons.O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator,
|
||||
)
|
||||
BetAB_500___500kg_Concrete_Piercing_Bomb_LD = (
|
||||
BetAB_500___500_kg_Concrete_Piercing_Bomb_LD = (
|
||||
2,
|
||||
Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD,
|
||||
Weapons.BetAB_500___500_kg_Concrete_Piercing_Bomb_LD,
|
||||
)
|
||||
KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = (
|
||||
2,
|
||||
@@ -133,12 +129,12 @@ class Su_57(PlaneType):
|
||||
2,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = (
|
||||
2,
|
||||
Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (2, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (2, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = (
|
||||
2,
|
||||
Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP,
|
||||
@@ -156,21 +152,20 @@ class Su_57(PlaneType):
|
||||
2,
|
||||
Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
2,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
R_37M_Active_Rdr = (2, Su57Weapons.R_37M_Active_Rdr)
|
||||
R_77PD_Active_rdr = (2, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (2, Su57Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (2, Su57Weapons.KS_172_Passive_Rdr)
|
||||
R_37M_Active_Rdr = (2, Weapons.R_37M_Active_Rdr)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (2, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (2, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (2, Weapons.KS_172_Passive_Rdr)
|
||||
Fuel_tank_800L_Wing = (2, Weapons.Fuel_tank_800L_Wing)
|
||||
RN_28___260_kg__nuclear_bomb__free_fall = (
|
||||
2,
|
||||
Weapons.RN_28___260_kg__nuclear_bomb__free_fall,
|
||||
)
|
||||
Su_57_Fuel_Tank = (2, Su57Weapons.Su_57_Fuel_Tank)
|
||||
Kh_59MK2 = (2, Su57Weapons.Kh_59MK2)
|
||||
Smoke_Generator___red = (2, Weapons.Smoke_Generator___red)
|
||||
Smoke_Generator___green = (2, Weapons.Smoke_Generator___green)
|
||||
Smoke_Generator___blue = (2, Weapons.Smoke_Generator___blue)
|
||||
@@ -214,37 +209,37 @@ class Su_57(PlaneType):
|
||||
4,
|
||||
Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr,
|
||||
)
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = (
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_ = (
|
||||
4,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_,
|
||||
)
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = (
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_ = (
|
||||
4,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_,
|
||||
)
|
||||
Kh_59M__AS_18_Kazoo____930kg__ASM__IN = (
|
||||
4,
|
||||
Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
4,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag = (
|
||||
4,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
)
|
||||
B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = (
|
||||
B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
4,
|
||||
Weapons.B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation,
|
||||
)
|
||||
S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = (
|
||||
O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator = (
|
||||
4,
|
||||
Weapons.O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator,
|
||||
)
|
||||
BetAB_500___500kg_Concrete_Piercing_Bomb_LD = (
|
||||
BetAB_500___500_kg_Concrete_Piercing_Bomb_LD = (
|
||||
4,
|
||||
Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD,
|
||||
Weapons.BetAB_500___500_kg_Concrete_Piercing_Bomb_LD,
|
||||
)
|
||||
KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = (
|
||||
4,
|
||||
@@ -254,12 +249,12 @@ class Su_57(PlaneType):
|
||||
4,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = (
|
||||
4,
|
||||
Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (4, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (4, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = (
|
||||
4,
|
||||
Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP,
|
||||
@@ -277,158 +272,61 @@ class Su_57(PlaneType):
|
||||
4,
|
||||
Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
4,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
R_37M_Active_Rdr = (4, Su57Weapons.R_37M_Active_Rdr)
|
||||
R_77PD_Active_rdr = (4, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (4, Su57Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (4, Su57Weapons.KS_172_Passive_Rdr)
|
||||
R_37M_Active_Rdr = (4, Weapons.R_37M_Active_Rdr)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (4, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (4, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (4, Weapons.KS_172_Passive_Rdr)
|
||||
RN_28___260_kg__nuclear_bomb__free_fall = (
|
||||
4,
|
||||
Weapons.RN_28___260_kg__nuclear_bomb__free_fall,
|
||||
)
|
||||
Su_57_Fuel_Tank = (4, Su57Weapons.Su_57_Fuel_Tank)
|
||||
Kh_59MK2 = (4, Su57Weapons.Kh_59MK2)
|
||||
|
||||
class Pylon5:
|
||||
R_77__AA_12_Adder____Active_Rdr = (5, Weapons.R_77__AA_12_Adder____Active_Rdr)
|
||||
R_77PD_Active_rdr = (5, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (5, Su57Weapons.K_77M_Active_Rdr)
|
||||
Kh_59MK2 = (5, Su57Weapons.Kh_59MK2)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (5, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (5, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (5, Weapons.KS_172_Passive_Rdr)
|
||||
|
||||
class Pylon6:
|
||||
R_77__AA_12_Adder____Active_Rdr = (6, Weapons.R_77__AA_12_Adder____Active_Rdr)
|
||||
R_77PD_Active_rdr = (6, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (6, Su57Weapons.K_77M_Active_Rdr)
|
||||
Kh_59MK2 = (6, Su57Weapons.Kh_59MK2)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (6, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (6, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (6, Weapons.KS_172_Passive_Rdr)
|
||||
|
||||
class Pylon7:
|
||||
R_77__AA_12_Adder____Active_Rdr = (7, Weapons.R_77__AA_12_Adder____Active_Rdr)
|
||||
R_77PD_Active_rdr = (7, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (7, Su57Weapons.K_77M_Active_Rdr)
|
||||
Kh_59MK2 = (7, Su57Weapons.Kh_59MK2)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (7, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (7, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (7, Weapons.KS_172_Passive_Rdr)
|
||||
|
||||
class Pylon8:
|
||||
R_77__AA_12_Adder____Active_Rdr = (8, Weapons.R_77__AA_12_Adder____Active_Rdr)
|
||||
R_77PD_Active_rdr = (8, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (8, Su57Weapons.K_77M_Active_Rdr)
|
||||
Kh_59MK2 = (8, Su57Weapons.Kh_59MK2)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (8, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (8, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (8, Weapons.KS_172_Passive_Rdr)
|
||||
|
||||
class Pylon9:
|
||||
R_27R__AA_10_Alamo_A____Semi_Act_Rdr = (
|
||||
9,
|
||||
Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr,
|
||||
)
|
||||
R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = (
|
||||
9,
|
||||
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
|
||||
)
|
||||
R_27T__AA_10_Alamo_B____Infra_Red = (
|
||||
9,
|
||||
Weapons.R_27T__AA_10_Alamo_B____Infra_Red,
|
||||
)
|
||||
R_27ET__AA_10_Alamo_D____IR_Extended_Range = (
|
||||
9,
|
||||
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
|
||||
)
|
||||
R_77__AA_12_Adder____Active_Rdr = (9, Weapons.R_77__AA_12_Adder____Active_Rdr)
|
||||
R_73__AA_11_Archer____Infra_Red = (9, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr = (
|
||||
9,
|
||||
Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr,
|
||||
)
|
||||
Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr = (
|
||||
9,
|
||||
Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr,
|
||||
)
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = (
|
||||
9,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser,
|
||||
)
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = (
|
||||
9,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided,
|
||||
)
|
||||
Kh_59M__AS_18_Kazoo____930kg__ASM__IN = (
|
||||
9,
|
||||
Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
9,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
)
|
||||
B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag = (
|
||||
9,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
)
|
||||
B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = (
|
||||
9,
|
||||
Weapons.B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation,
|
||||
)
|
||||
S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = (
|
||||
9,
|
||||
Weapons.O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator,
|
||||
)
|
||||
BetAB_500___500kg_Concrete_Piercing_Bomb_LD = (
|
||||
9,
|
||||
Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD,
|
||||
)
|
||||
KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = (
|
||||
9,
|
||||
Weapons.KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag,
|
||||
)
|
||||
KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP = (
|
||||
9,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (9, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = (
|
||||
9,
|
||||
Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (9, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = (
|
||||
9,
|
||||
Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP,
|
||||
)
|
||||
KAB_500LG___500kg_Laser_Guided_Bomb = (
|
||||
9,
|
||||
Weapons.KAB_500LG___500kg_Laser_Guided_Bomb,
|
||||
)
|
||||
KAB_500Kr___500kg_TV_Guided_Bomb = (9, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb)
|
||||
FAB_1500_M_54___1500kg_GP_Bomb_LD = (
|
||||
9,
|
||||
Weapons.FAB_1500_M_54___1500kg_GP_Bomb_LD,
|
||||
)
|
||||
KAB_1500L___1500kg_Laser_Guided_Bomb = (
|
||||
9,
|
||||
Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
9,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
)
|
||||
R_37M_Active_Rdr = (9, Su57Weapons.R_37M_Active_Rdr)
|
||||
R_77PD_Active_rdr = (9, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (9, Su57Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (9, Su57Weapons.KS_172_Passive_Rdr)
|
||||
RN_28___260_kg__nuclear_bomb__free_fall = (
|
||||
9,
|
||||
Weapons.RN_28___260_kg__nuclear_bomb__free_fall,
|
||||
)
|
||||
Su_57_Fuel_Tank = (9, Su57Weapons.Su_57_Fuel_Tank)
|
||||
Kh_59MK2 = (9, Su57Weapons.Kh_59MK2)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (9, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (9, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (9, Weapons.KS_172_Passive_Rdr)
|
||||
|
||||
class Pylon10:
|
||||
R_73__AA_11_Archer____Infra_Red = (10, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
Smoke_Generator___red = (10, Weapons.Smoke_Generator___red)
|
||||
Smoke_Generator___green = (10, Weapons.Smoke_Generator___green)
|
||||
Smoke_Generator___blue = (10, Weapons.Smoke_Generator___blue)
|
||||
Smoke_Generator___white = (10, Weapons.Smoke_Generator___white)
|
||||
Smoke_Generator___yellow = (10, Weapons.Smoke_Generator___yellow)
|
||||
Smoke_Generator___orange = (10, Weapons.Smoke_Generator___orange)
|
||||
R_77__AA_12_Adder____Active_Rdr = (10, Weapons.R_77__AA_12_Adder____Active_Rdr)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (10, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (10, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (10, Weapons.KS_172_Passive_Rdr)
|
||||
|
||||
class Pylon11:
|
||||
R_27R__AA_10_Alamo_A____Semi_Act_Rdr = (
|
||||
@@ -457,37 +355,37 @@ class Su_57(PlaneType):
|
||||
11,
|
||||
Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr,
|
||||
)
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = (
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_ = (
|
||||
11,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_,
|
||||
)
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = (
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_ = (
|
||||
11,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_,
|
||||
)
|
||||
Kh_59M__AS_18_Kazoo____930kg__ASM__IN = (
|
||||
11,
|
||||
Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
11,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag = (
|
||||
11,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
)
|
||||
B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = (
|
||||
B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
11,
|
||||
Weapons.B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation,
|
||||
)
|
||||
S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = (
|
||||
O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator = (
|
||||
11,
|
||||
Weapons.O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator,
|
||||
)
|
||||
BetAB_500___500kg_Concrete_Piercing_Bomb_LD = (
|
||||
BetAB_500___500_kg_Concrete_Piercing_Bomb_LD = (
|
||||
11,
|
||||
Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD,
|
||||
Weapons.BetAB_500___500_kg_Concrete_Piercing_Bomb_LD,
|
||||
)
|
||||
KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = (
|
||||
11,
|
||||
@@ -497,12 +395,15 @@ class Su_57(PlaneType):
|
||||
11,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (11, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
11,
|
||||
Weapons.OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = (
|
||||
11,
|
||||
Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (11, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (11, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = (
|
||||
11,
|
||||
Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP,
|
||||
@@ -523,33 +424,22 @@ class Su_57(PlaneType):
|
||||
11,
|
||||
Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
11,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
# ERRR {R-33}
|
||||
R_37M_Active_Rdr = (11, Su57Weapons.R_37M_Active_Rdr)
|
||||
R_77PD_Active_rdr = (11, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (11, Su57Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (11, Su57Weapons.KS_172_Passive_Rdr)
|
||||
Fuel_tank_800L_Wing = (11, Weapons.Fuel_tank_800L_Wing)
|
||||
Su_57_Fuel_Tank = (11, Su57Weapons.Su_57_Fuel_Tank)
|
||||
R_37M_Active_Rdr = (11, Weapons.R_37M_Active_Rdr)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (11, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (11, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (11, Weapons.KS_172_Passive_Rdr)
|
||||
RN_28___260_kg__nuclear_bomb__free_fall = (
|
||||
11,
|
||||
Weapons.RN_28___260_kg__nuclear_bomb__free_fall,
|
||||
)
|
||||
Smoke_Generator___red = (11, Weapons.Smoke_Generator___red)
|
||||
Smoke_Generator___green = (11, Weapons.Smoke_Generator___green)
|
||||
Smoke_Generator___blue = (11, Weapons.Smoke_Generator___blue)
|
||||
Smoke_Generator___white = (11, Weapons.Smoke_Generator___white)
|
||||
Smoke_Generator___yellow = (11, Weapons.Smoke_Generator___yellow)
|
||||
Smoke_Generator___orange = (11, Weapons.Smoke_Generator___orange)
|
||||
Kh_59MK2 = (11, Su57Weapons.Kh_59MK2)
|
||||
|
||||
class Pylon12:
|
||||
R_73__AA_11_Archer____Infra_Red = (12, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
R_77PD_Active_rdr = (12, Su57Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (12, Su57Weapons.K_77M_Active_Rdr)
|
||||
Smoke_Generator___red = (12, Weapons.Smoke_Generator___red)
|
||||
Smoke_Generator___green = (12, Weapons.Smoke_Generator___green)
|
||||
Smoke_Generator___blue = (12, Weapons.Smoke_Generator___blue)
|
||||
@@ -557,7 +447,140 @@ class Su_57(PlaneType):
|
||||
Smoke_Generator___yellow = (12, Weapons.Smoke_Generator___yellow)
|
||||
Smoke_Generator___orange = (12, Weapons.Smoke_Generator___orange)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
||||
class Pylon13:
|
||||
R_27R__AA_10_Alamo_A____Semi_Act_Rdr = (
|
||||
13,
|
||||
Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr,
|
||||
)
|
||||
R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = (
|
||||
13,
|
||||
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
|
||||
)
|
||||
R_27T__AA_10_Alamo_B____Infra_Red = (
|
||||
13,
|
||||
Weapons.R_27T__AA_10_Alamo_B____Infra_Red,
|
||||
)
|
||||
R_27ET__AA_10_Alamo_D____IR_Extended_Range = (
|
||||
13,
|
||||
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
|
||||
)
|
||||
R_77__AA_12_Adder____Active_Rdr = (13, Weapons.R_77__AA_12_Adder____Active_Rdr)
|
||||
R_73__AA_11_Archer____Infra_Red = (13, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr = (
|
||||
13,
|
||||
Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr,
|
||||
)
|
||||
Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr = (
|
||||
13,
|
||||
Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr,
|
||||
)
|
||||
Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_ = (
|
||||
13,
|
||||
Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser_,
|
||||
)
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_ = (
|
||||
13,
|
||||
Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_,
|
||||
)
|
||||
Kh_59M__AS_18_Kazoo____930kg__ASM__IN = (
|
||||
13,
|
||||
Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN,
|
||||
)
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
13,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag = (
|
||||
13,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
)
|
||||
B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
13,
|
||||
Weapons.B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation,
|
||||
)
|
||||
O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator = (
|
||||
13,
|
||||
Weapons.O_25___1_x_UnGd_Rkts__340_mm_S_25_OFM_Hardened_Target_Penetrator,
|
||||
)
|
||||
BetAB_500___500_kg_Concrete_Piercing_Bomb_LD = (
|
||||
13,
|
||||
Weapons.BetAB_500___500_kg_Concrete_Piercing_Bomb_LD,
|
||||
)
|
||||
KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = (
|
||||
13,
|
||||
Weapons.KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag,
|
||||
)
|
||||
KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP = (
|
||||
13,
|
||||
Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP,
|
||||
)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
13,
|
||||
Weapons.OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = (
|
||||
13,
|
||||
Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP,
|
||||
)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (13, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = (
|
||||
13,
|
||||
Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP,
|
||||
)
|
||||
KAB_500LG___500kg_Laser_Guided_Bomb = (
|
||||
13,
|
||||
Weapons.KAB_500LG___500kg_Laser_Guided_Bomb,
|
||||
)
|
||||
KAB_500Kr___500kg_TV_Guided_Bomb = (
|
||||
13,
|
||||
Weapons.KAB_500Kr___500kg_TV_Guided_Bomb,
|
||||
)
|
||||
FAB_1500_M_54___1500kg_GP_Bomb_LD = (
|
||||
13,
|
||||
Weapons.FAB_1500_M_54___1500kg_GP_Bomb_LD,
|
||||
)
|
||||
KAB_1500L___1500kg_Laser_Guided_Bomb = (
|
||||
13,
|
||||
Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb,
|
||||
)
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
13,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
# ERRR {R-33}
|
||||
R_37M_Active_Rdr = (13, Weapons.R_37M_Active_Rdr)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (13, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (13, Weapons.K_77M_Active_Rdr)
|
||||
KS_172_Passive_Rdr = (13, Weapons.KS_172_Passive_Rdr)
|
||||
Fuel_tank_800L_Wing = (13, Weapons.Fuel_tank_800L_Wing)
|
||||
RN_28___260_kg__nuclear_bomb__free_fall = (
|
||||
13,
|
||||
Weapons.RN_28___260_kg__nuclear_bomb__free_fall,
|
||||
)
|
||||
Smoke_Generator___red = (13, Weapons.Smoke_Generator___red)
|
||||
Smoke_Generator___green = (13, Weapons.Smoke_Generator___green)
|
||||
Smoke_Generator___blue = (13, Weapons.Smoke_Generator___blue)
|
||||
Smoke_Generator___white = (13, Weapons.Smoke_Generator___white)
|
||||
Smoke_Generator___yellow = (13, Weapons.Smoke_Generator___yellow)
|
||||
Smoke_Generator___orange = (13, Weapons.Smoke_Generator___orange)
|
||||
|
||||
class Pylon14:
|
||||
R_73__AA_11_Archer____Infra_Red = (14, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
# ERRR {RVV-AE}
|
||||
R_77PD_Active_rdr = (14, Weapons.R_77PD_Active_rdr)
|
||||
K_77M_Active_Rdr = (14, Weapons.K_77M_Active_Rdr)
|
||||
Smoke_Generator___red = (14, Weapons.Smoke_Generator___red)
|
||||
Smoke_Generator___green = (14, Weapons.Smoke_Generator___green)
|
||||
Smoke_Generator___blue = (14, Weapons.Smoke_Generator___blue)
|
||||
Smoke_Generator___white = (14, Weapons.Smoke_Generator___white)
|
||||
Smoke_Generator___yellow = (14, Weapons.Smoke_Generator___yellow)
|
||||
Smoke_Generator___orange = (14, Weapons.Smoke_Generator___orange)
|
||||
|
||||
class Pylon15:
|
||||
Mercury_LLTV_Pod = (15, Weapons.Mercury_LLTV_Pod)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
||||
|
||||
tasks = [
|
||||
task.CAP,
|
||||
|
||||
@@ -170,9 +170,9 @@ class Su_24MU(PlaneType):
|
||||
class Pylon1:
|
||||
R_60M__AA_8_Aphid_B____IR_AAM = (1, Weapons.R_60M__AA_8_Aphid_B____IR_AAM)
|
||||
R_73__AA_11_Archer____Infra_Red = (1, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
1,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
1,
|
||||
@@ -182,7 +182,7 @@ class Su_24MU(PlaneType):
|
||||
1,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (1, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (1, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
1,
|
||||
Weapons.B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation,
|
||||
@@ -202,9 +202,9 @@ class Su_24MU(PlaneType):
|
||||
CH_AASM_250_PGM = (1, Weapons.CH_AASM_250_PGM)
|
||||
|
||||
class Pylon2:
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
2,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_ = (
|
||||
2,
|
||||
@@ -214,8 +214,8 @@ class Su_24MU(PlaneType):
|
||||
2,
|
||||
Weapons.Kh_25ML__AS_10_Karen____300kg__ASM__Semi_Act_Laser_,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (2, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (2, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
KAB_500Kr___500kg_TV_Guided_Bomb = (2, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
2,
|
||||
@@ -247,12 +247,12 @@ class Su_24MU(PlaneType):
|
||||
CH_AASM_250_PGM = (2, Weapons.CH_AASM_250_PGM)
|
||||
|
||||
class Pylon3:
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (3, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (3, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
KAB_500Kr___500kg_TV_Guided_Bomb = (3, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
3,
|
||||
@@ -269,11 +269,11 @@ class Su_24MU(PlaneType):
|
||||
CH_AASM_250_PGM = (3, Weapons.CH_AASM_250_PGM)
|
||||
|
||||
class Pylon4:
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
4,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
KAB_1500L___1500kg_Laser_Guided_Bomb = (
|
||||
4,
|
||||
Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb,
|
||||
@@ -283,15 +283,15 @@ class Su_24MU(PlaneType):
|
||||
class Pylon5:
|
||||
Fuel_tank_2000L = (5, Weapons.Fuel_tank_2000L)
|
||||
L_081_Fantasmagoria_ELINT_pod = (5, Weapons.L_081_Fantasmagoria_ELINT_pod)
|
||||
FAB_250___250kg_GP_Bomb_LD = (5, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (5, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
|
||||
class Pylon6:
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
6,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (6, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (6, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (6, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (6, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
KAB_500Kr___500kg_TV_Guided_Bomb = (6, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
6,
|
||||
@@ -308,9 +308,9 @@ class Su_24MU(PlaneType):
|
||||
CH_AASM_250_PGM = (6, Weapons.CH_AASM_250_PGM)
|
||||
|
||||
class Pylon7:
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
7,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided_ = (
|
||||
7,
|
||||
@@ -320,8 +320,8 @@ class Su_24MU(PlaneType):
|
||||
7,
|
||||
Weapons.Kh_25ML__AS_10_Karen____300kg__ASM__Semi_Act_Laser_,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (7, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (7, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (7, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (7, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
KAB_500Kr___500kg_TV_Guided_Bomb = (7, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
7,
|
||||
@@ -355,9 +355,9 @@ class Su_24MU(PlaneType):
|
||||
class Pylon8:
|
||||
R_60M__AA_8_Aphid_B____IR_AAM = (8, Weapons.R_60M__AA_8_Aphid_B____IR_AAM)
|
||||
R_73__AA_11_Archer____Infra_Red = (8, Weapons.R_73__AA_11_Archer____Infra_Red)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
8,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
UB_32A___32_x_UnGd_Rkts__57_mm_S_5KO_HEAT_Frag = (
|
||||
8,
|
||||
@@ -367,7 +367,7 @@ class Su_24MU(PlaneType):
|
||||
8,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (8, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (8, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
8,
|
||||
Weapons.B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation,
|
||||
@@ -505,8 +505,8 @@ class MiG_29MU2(PlaneType):
|
||||
2,
|
||||
Weapons.Kh_25ML__AS_10_Karen____300kg__ASM__Semi_Act_Laser__,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (2, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (2, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_ = (
|
||||
2,
|
||||
Weapons.APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
@@ -577,8 +577,8 @@ class MiG_29MU2(PlaneType):
|
||||
3,
|
||||
Weapons.Kh_25ML__AS_10_Karen____300kg__ASM__Semi_Act_Laser__,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (3, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (3, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_ = (
|
||||
3,
|
||||
Weapons.APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
@@ -656,8 +656,8 @@ class MiG_29MU2(PlaneType):
|
||||
5,
|
||||
Weapons.Kh_25ML__AS_10_Karen____300kg__ASM__Semi_Act_Laser__,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (5, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (5, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (5, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (5, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_ = (
|
||||
5,
|
||||
Weapons.APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
@@ -735,8 +735,8 @@ class MiG_29MU2(PlaneType):
|
||||
6,
|
||||
Weapons.Kh_25ML__AS_10_Karen____300kg__ASM__Semi_Act_Laser__,
|
||||
)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (6, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
FAB_250___250kg_GP_Bomb_LD = (6, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (6, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (6, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_ = (
|
||||
6,
|
||||
Weapons.APU_68___S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk_,
|
||||
@@ -807,6 +807,8 @@ class CH_Su_27P1M(PlaneType):
|
||||
|
||||
property_defaults: Dict[str, Any] = {}
|
||||
|
||||
properties = {}
|
||||
|
||||
livery_name = "CH_SU-27P1M" # from type
|
||||
|
||||
class Pylon1:
|
||||
@@ -828,8 +830,8 @@ class CH_Su_27P1M(PlaneType):
|
||||
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
|
||||
)
|
||||
B_8M1___20_S_8OFP2 = (3, Weapons.B_8M1___20_S_8OFP2)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (3, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (3, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag = (
|
||||
3,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
@@ -842,13 +844,13 @@ class CH_Su_27P1M(PlaneType):
|
||||
3,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8TsM_SM_Orange,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
3,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
_2_x_B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
3,
|
||||
@@ -890,15 +892,15 @@ class CH_Su_27P1M(PlaneType):
|
||||
4,
|
||||
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (4, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (4, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
4,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_5_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___5_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
4,
|
||||
Weapons.MBD3_U6_68_with_5_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___5_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
ADM_160B_MALD___Miniature_Air_Launched_Decoy_ = (
|
||||
4,
|
||||
@@ -924,15 +926,15 @@ class CH_Su_27P1M(PlaneType):
|
||||
5,
|
||||
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (5, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (5, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (5, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (5, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
5,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_3_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___3_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
5,
|
||||
Weapons.MBD3_U6_68_with_3_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___3_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
ADM_160B_MALD___Miniature_Air_Launched_Decoy_ = (
|
||||
5,
|
||||
@@ -954,15 +956,15 @@ class CH_Su_27P1M(PlaneType):
|
||||
6,
|
||||
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (6, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (6, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (6, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (6, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
6,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
6,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
ADM_160B_MALD___Miniature_Air_Launched_Decoy_ = (
|
||||
6,
|
||||
@@ -984,15 +986,15 @@ class CH_Su_27P1M(PlaneType):
|
||||
7,
|
||||
Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range,
|
||||
)
|
||||
FAB_250___250kg_GP_Bomb_LD = (7, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (7, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (7, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (7, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
7,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_5_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___5_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
7,
|
||||
Weapons.MBD3_U6_68_with_5_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___5_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
ADM_160B_MALD___Miniature_Air_Launched_Decoy_ = (
|
||||
7,
|
||||
@@ -1024,8 +1026,8 @@ class CH_Su_27P1M(PlaneType):
|
||||
Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range,
|
||||
)
|
||||
B_8M1___20_S_8OFP2 = (8, Weapons.B_8M1___20_S_8OFP2)
|
||||
FAB_250___250kg_GP_Bomb_LD = (8, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
FAB_500_M_62___500kg_GP_Bomb_LD = (8, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (8, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
FAB_500M_62___500_kg_GP_Bomb_LD = (8, Weapons.FAB_500M_62___500_kg_GP_Bomb_LD)
|
||||
B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag = (
|
||||
8,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8KOM_HEAT_Frag,
|
||||
@@ -1038,13 +1040,13 @@ class CH_Su_27P1M(PlaneType):
|
||||
8,
|
||||
Weapons.B_8M1___20_x_UnGd_Rkts__80_mm_S_8TsM_SM_Orange,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD = (
|
||||
8,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_100_120___100_kg_GP_Bomb_LD,
|
||||
)
|
||||
MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = (
|
||||
MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD = (
|
||||
8,
|
||||
Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD,
|
||||
Weapons.MBD3_U6_68___6_x_OFAB_250_270___250_kg_GP_Bomb_LD,
|
||||
)
|
||||
_2_x_B_13L___5_x_UnGd_Rkts__122_mm_S_13OF_Blast_Fragmentation = (
|
||||
8,
|
||||
|
||||
@@ -761,7 +761,7 @@ class vwv_mig17f(PlaneType):
|
||||
|
||||
class Pylon1:
|
||||
FAB_50 = (1, Weapons.FAB_50)
|
||||
FAB_250___250kg_GP_Bomb_LD = (1, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (1, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_8V20A_CM = (1, Weapons.B_8V20A_CM)
|
||||
B_8V20A_OM = (1, Weapons.B_8V20A_OM)
|
||||
B_8M1___20_S_8OFP2 = (1, Weapons.B_8M1___20_S_8OFP2)
|
||||
@@ -774,7 +774,7 @@ class vwv_mig17f(PlaneType):
|
||||
|
||||
class Pylon2:
|
||||
FAB_50 = (2, Weapons.FAB_50)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_8V20A_CM = (2, Weapons.B_8V20A_CM)
|
||||
B_8V20A_OM = (2, Weapons.B_8V20A_OM)
|
||||
B_8M1___20_S_8OFP2 = (2, Weapons.B_8M1___20_S_8OFP2)
|
||||
@@ -828,7 +828,7 @@ class vwv_mig21mf(PlaneType):
|
||||
|
||||
class Pylon1:
|
||||
FAB_50 = (1, Weapons.FAB_50)
|
||||
FAB_250___250kg_GP_Bomb_LD = (1, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (1, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_8V20A_CM = (1, Weapons.B_8V20A_CM)
|
||||
B_8V20A_OM = (1, Weapons.B_8V20A_OM)
|
||||
B_8M1___20_S_8OFP2 = (1, Weapons.B_8M1___20_S_8OFP2)
|
||||
@@ -854,7 +854,7 @@ class vwv_mig21mf(PlaneType):
|
||||
|
||||
class Pylon2:
|
||||
FAB_50 = (2, Weapons.FAB_50)
|
||||
FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (2, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_8V20A_CM = (2, Weapons.B_8V20A_CM)
|
||||
B_8V20A_OM = (2, Weapons.B_8V20A_OM)
|
||||
B_8M1___20_S_8OFP2 = (2, Weapons.B_8M1___20_S_8OFP2)
|
||||
@@ -880,7 +880,7 @@ class vwv_mig21mf(PlaneType):
|
||||
|
||||
class Pylon3:
|
||||
FAB_50 = (3, Weapons.FAB_50)
|
||||
FAB_250___250kg_GP_Bomb_LD = (3, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (3, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_8V20A_CM = (3, Weapons.B_8V20A_CM)
|
||||
B_8V20A_OM = (3, Weapons.B_8V20A_OM)
|
||||
B_8M1___20_S_8OFP2 = (3, Weapons.B_8M1___20_S_8OFP2)
|
||||
@@ -906,7 +906,7 @@ class vwv_mig21mf(PlaneType):
|
||||
|
||||
class Pylon4:
|
||||
FAB_50 = (4, Weapons.FAB_50)
|
||||
FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD)
|
||||
OFAB_250_270___250_kg_GP_Bomb_LD = (4, Weapons.OFAB_250_270___250_kg_GP_Bomb_LD)
|
||||
B_8V20A_CM = (4, Weapons.B_8V20A_CM)
|
||||
B_8V20A_OM = (4, Weapons.B_8V20A_OM)
|
||||
B_8M1___20_S_8OFP2 = (4, Weapons.B_8M1___20_S_8OFP2)
|
||||
|
||||
@@ -24,7 +24,7 @@ from game.radio.tacan import TacanChannel
|
||||
from game.server import EventStream
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.squadrons.squadron import Pilot, Squadron
|
||||
from game.theater import NavalControlPoint
|
||||
from game.theater import NavalControlPoint, Player
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.transfers import PendingTransfers, TransferOrder
|
||||
from qt_ui.simcontroller import SimController
|
||||
@@ -377,7 +377,7 @@ class TransferModel(QAbstractListModel):
|
||||
|
||||
@property
|
||||
def transfers(self) -> PendingTransfers:
|
||||
return self.game_model.game.coalition_for(player=True).transfers
|
||||
return self.game_model.game.coalition_for(player=Player.BLUE).transfers
|
||||
|
||||
def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
|
||||
return self.transfers.pending_transfer_count
|
||||
@@ -433,7 +433,7 @@ class AirWingModel(QAbstractListModel):
|
||||
|
||||
SquadronRole = Qt.ItemDataRole.UserRole
|
||||
|
||||
def __init__(self, game_model: GameModel, player: bool) -> None:
|
||||
def __init__(self, game_model: GameModel, player: Player) -> None:
|
||||
super().__init__()
|
||||
self.game_model = game_model
|
||||
self.player = player
|
||||
@@ -548,8 +548,8 @@ class GameModel:
|
||||
self.game: Optional[Game] = game
|
||||
self.sim_controller = sim_controller
|
||||
self.transfer_model = TransferModel(self)
|
||||
self.blue_air_wing_model = AirWingModel(self, player=True)
|
||||
self.red_air_wing_model = AirWingModel(self, player=False)
|
||||
self.blue_air_wing_model = AirWingModel(self, player=Player.BLUE)
|
||||
self.red_air_wing_model = AirWingModel(self, player=Player.RED)
|
||||
if self.game is None:
|
||||
self.ato_model = AtoModel(self, AirTaskingOrder())
|
||||
self.red_ato_model = AtoModel(self, AirTaskingOrder())
|
||||
@@ -564,8 +564,8 @@ class GameModel:
|
||||
self.allocated_icls: list[int] = list()
|
||||
self.init_comms_registry()
|
||||
|
||||
def ato_model_for(self, player: bool) -> AtoModel:
|
||||
if player:
|
||||
def ato_model_for(self, player: Player) -> AtoModel:
|
||||
if player.is_blue:
|
||||
return self.ato_model
|
||||
return self.red_ato_model
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from PySide6.QtWidgets import QHBoxLayout, QGroupBox, QPushButton
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game import Game
|
||||
from game.income import Income
|
||||
from game.theater.player import Player
|
||||
from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu
|
||||
|
||||
|
||||
@@ -41,7 +42,9 @@ class QBudgetBox(QGroupBox):
|
||||
return
|
||||
|
||||
self.game = game
|
||||
self.setBudget(self.game.blue.budget, Income(self.game, player=True).total)
|
||||
self.setBudget(
|
||||
self.game.blue.budget, Income(self.game, player=Player.BLUE).total
|
||||
)
|
||||
self.finances.setEnabled(True)
|
||||
|
||||
def openFinances(self):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user