mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Merge branch 'develop' into frontline
This commit is contained in:
commit
edd02d9dd6
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
from typing import Dict, List, Optional, Type, TYPE_CHECKING
|
||||
from typing import Dict, List, Optional, TYPE_CHECKING, Type
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.task import Task
|
||||
@ -11,12 +11,12 @@ from dcs.unittype import UnitType
|
||||
from game import db, persistency
|
||||
from game.debriefing import Debriefing
|
||||
from game.infos.information import Information
|
||||
from game.operation.operation import Operation
|
||||
from game.theater import ControlPoint
|
||||
from gen.ground_forces.combat_stance import CombatStance
|
||||
from theater import ControlPoint
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..game import Game
|
||||
from game.operation.operation import Operation
|
||||
|
||||
DIFFICULTY_LOG_BASE = 1.1
|
||||
EVENT_DEPARTURE_MAX_DISTANCE = 340000
|
||||
|
||||
14
game/game.py
14
game/game.py
@ -160,9 +160,6 @@ class Game:
|
||||
def _budget_player(self):
|
||||
self.budget += self.budget_reward_amount
|
||||
|
||||
def awacs_expense_commit(self):
|
||||
self.budget -= AWACS_BUDGET_COST
|
||||
|
||||
def units_delivery_event(self, to_cp: ControlPoint) -> UnitsDeliveryEvent:
|
||||
event = UnitsDeliveryEvent(attacker_name=self.player_name,
|
||||
defender_name=self.player_name,
|
||||
@ -172,10 +169,6 @@ class Game:
|
||||
self.events.append(event)
|
||||
return event
|
||||
|
||||
def units_delivery_remove(self, event: Event):
|
||||
if event in self.events:
|
||||
self.events.remove(event)
|
||||
|
||||
def initiate_event(self, event: Event):
|
||||
#assert event in self.events
|
||||
logging.info("Generating {} (regular)".format(event))
|
||||
@ -202,12 +195,6 @@ class Game:
|
||||
LuaPluginManager.load_settings(self.settings)
|
||||
ObjectiveDistanceCache.set_theater(self.theater)
|
||||
|
||||
# Save game compatibility.
|
||||
|
||||
# TODO: Remove in 2.3.
|
||||
if not hasattr(self, "conditions"):
|
||||
self.conditions = self.generate_conditions()
|
||||
|
||||
def pass_turn(self, no_action: bool = False) -> None:
|
||||
logging.info("Pass turn")
|
||||
self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0))
|
||||
@ -248,6 +235,7 @@ class Game:
|
||||
|
||||
self.aircraft_inventory.reset()
|
||||
for cp in self.theater.controlpoints:
|
||||
cp.pending_unit_deliveries = self.units_delivery_event(cp)
|
||||
self.aircraft_inventory.set_from_control_point(cp)
|
||||
|
||||
# Plan flights & combat for next turn
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
"""Inventory management APIs."""
|
||||
from collections import defaultdict
|
||||
from typing import Dict, Iterable, Iterator, Set, Tuple
|
||||
from __future__ import annotations
|
||||
|
||||
from dcs.unittype import UnitType
|
||||
from collections import defaultdict
|
||||
from typing import Dict, Iterable, Iterator, Set, Tuple, TYPE_CHECKING
|
||||
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from gen.flights.flight import Flight
|
||||
from theater import ControlPoint
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.theater import ControlPoint
|
||||
|
||||
|
||||
class ControlPointAircraftInventory:
|
||||
@ -13,9 +17,9 @@ class ControlPointAircraftInventory:
|
||||
|
||||
def __init__(self, control_point: ControlPoint) -> None:
|
||||
self.control_point = control_point
|
||||
self.inventory: Dict[UnitType, int] = defaultdict(int)
|
||||
self.inventory: Dict[FlyingType, int] = defaultdict(int)
|
||||
|
||||
def add_aircraft(self, aircraft: UnitType, count: int) -> None:
|
||||
def add_aircraft(self, aircraft: FlyingType, count: int) -> None:
|
||||
"""Adds aircraft to the inventory.
|
||||
|
||||
Args:
|
||||
@ -24,7 +28,7 @@ class ControlPointAircraftInventory:
|
||||
"""
|
||||
self.inventory[aircraft] += count
|
||||
|
||||
def remove_aircraft(self, aircraft: UnitType, count: int) -> None:
|
||||
def remove_aircraft(self, aircraft: FlyingType, count: int) -> None:
|
||||
"""Removes aircraft from the inventory.
|
||||
|
||||
Args:
|
||||
@ -43,7 +47,7 @@ class ControlPointAircraftInventory:
|
||||
)
|
||||
self.inventory[aircraft] -= count
|
||||
|
||||
def available(self, aircraft: UnitType) -> int:
|
||||
def available(self, aircraft: FlyingType) -> int:
|
||||
"""Returns the number of available aircraft of the given type.
|
||||
|
||||
Args:
|
||||
@ -55,14 +59,14 @@ class ControlPointAircraftInventory:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def types_available(self) -> Iterator[UnitType]:
|
||||
def types_available(self) -> Iterator[FlyingType]:
|
||||
"""Iterates over all available aircraft types."""
|
||||
for aircraft, count in self.inventory.items():
|
||||
if count > 0:
|
||||
yield aircraft
|
||||
|
||||
@property
|
||||
def all_aircraft(self) -> Iterator[Tuple[UnitType, int]]:
|
||||
def all_aircraft(self) -> Iterator[Tuple[FlyingType, int]]:
|
||||
"""Iterates over all available aircraft types, including amounts."""
|
||||
for aircraft, count in self.inventory.items():
|
||||
if count > 0:
|
||||
@ -102,9 +106,9 @@ class GlobalAircraftInventory:
|
||||
return self.inventories[control_point]
|
||||
|
||||
@property
|
||||
def available_types_for_player(self) -> Iterator[UnitType]:
|
||||
def available_types_for_player(self) -> Iterator[FlyingType]:
|
||||
"""Iterates over all aircraft types available to the player."""
|
||||
seen: Set[UnitType] = set()
|
||||
seen: Set[FlyingType] = set()
|
||||
for control_point, inventory in self.inventories.items():
|
||||
if control_point.captured:
|
||||
for aircraft in inventory.types_available:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from theater import ControlPoint
|
||||
from game.theater import ControlPoint
|
||||
|
||||
|
||||
class FrontlineData:
|
||||
|
||||
@ -15,6 +15,7 @@ from dcs.triggers import TriggerStart
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from game.plugins import LuaPluginManager
|
||||
from game.theater import ControlPoint
|
||||
from gen import Conflict, FlightType, VisualGenerator
|
||||
from gen.aircraft import AIRCRAFT_DATA, AircraftConflictGenerator, FlightData
|
||||
from gen.airfields import AIRFIELD_DATA
|
||||
@ -29,7 +30,6 @@ from gen.kneeboard import KneeboardGenerator
|
||||
from gen.radios import RadioFrequency, RadioRegistry
|
||||
from gen.tacan import TacanRegistry
|
||||
from gen.triggergen import TRIGGER_RADIUS_MEDIUM, TriggersGenerator
|
||||
from theater import ControlPoint
|
||||
from .. import db
|
||||
from ..debriefing import Debriefing
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ from dcs.ships import (
|
||||
Type_071_Amphibious_Transport_Dock,
|
||||
)
|
||||
from dcs.terrain.terrain import Airport
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from game import db
|
||||
from gen.ground_forces.combat_stance import CombatStance
|
||||
@ -32,6 +33,7 @@ from .theatergroundobject import (
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from gen.flights.flight import FlightType
|
||||
from ..event import UnitsDeliveryEvent
|
||||
|
||||
|
||||
class ControlPointType(Enum):
|
||||
@ -157,6 +159,7 @@ class ControlPoint(MissionTarget):
|
||||
self.cptype = cptype
|
||||
self.stances: Dict[int, CombatStance] = {}
|
||||
self.airport = None
|
||||
self.pending_unit_deliveries: Optional[UnitsDeliveryEvent] = None
|
||||
|
||||
@property
|
||||
def ground_objects(self) -> List[TheaterGroundObject]:
|
||||
@ -366,6 +369,13 @@ class ControlPoint(MissionTarget):
|
||||
# TODO: FlightType.STRIKE
|
||||
]
|
||||
|
||||
def can_land(self, aircraft: FlyingType) -> bool:
|
||||
if self.is_carrier and aircraft not in db.CARRIER_CAPABLE:
|
||||
return False
|
||||
if self.is_lha and aircraft not in db.LHA_CAPABLE:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class OffMapSpawn(ControlPoint):
|
||||
def __init__(self, id: int, name: str, position: Point):
|
||||
@ -379,3 +389,7 @@ class OffMapSpawn(ControlPoint):
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
yield from []
|
||||
|
||||
@property
|
||||
def available_aircraft_slots(self) -> int:
|
||||
return 1000
|
||||
|
||||
@ -1 +0,0 @@
|
||||
"""Only here to keep compatibility for save games generated in version 2.2.0"""
|
||||
@ -39,10 +39,11 @@ from gen.sam.sam_group_generator import (
|
||||
generate_anti_air_group,
|
||||
generate_ewr_group, generate_shorad_group,
|
||||
)
|
||||
from theater import (
|
||||
from . import (
|
||||
ConflictTheater,
|
||||
ControlPoint,
|
||||
ControlPointType, OffMapSpawn,
|
||||
ControlPointType,
|
||||
OffMapSpawn,
|
||||
)
|
||||
|
||||
GroundObjectTemplates = Dict[str, Dict[str, Any]]
|
||||
|
||||
@ -10,7 +10,7 @@ from typing import Optional
|
||||
from dcs.weather import Weather as PydcsWeather, Wind
|
||||
|
||||
from game.settings import Settings
|
||||
from theater import ConflictTheater
|
||||
from game.theater import ConflictTheater
|
||||
|
||||
|
||||
class TimeOfDay(Enum):
|
||||
|
||||
@ -70,6 +70,12 @@ from dcs.unittype import FlyingType, UnitType
|
||||
from game import db
|
||||
from game.data.cap_capabilities_db import GUNFIGHTERS
|
||||
from game.settings import Settings
|
||||
from game.theater.controlpoint import (
|
||||
ControlPoint,
|
||||
ControlPointType,
|
||||
OffMapSpawn,
|
||||
)
|
||||
from game.theater.theatergroundobject import TheaterGroundObject
|
||||
from game.utils import knots_to_kph, nm_to_meter
|
||||
from gen.airsupportgen import AirSupport
|
||||
from gen.ato import AirTaskingOrder, Package
|
||||
@ -83,12 +89,6 @@ from gen.flights.flight import (
|
||||
)
|
||||
from gen.radios import MHz, Radio, RadioFrequency, RadioRegistry, get_radio
|
||||
from gen.runways import RunwayData
|
||||
from theater import TheaterGroundObject
|
||||
from game.theater.controlpoint import (
|
||||
ControlPoint,
|
||||
ControlPointType,
|
||||
OffMapSpawn,
|
||||
)
|
||||
from .conflictgen import Conflict
|
||||
from .flights.flightplan import (
|
||||
CasFlightPlan,
|
||||
@ -695,6 +695,18 @@ class AircraftConflictGenerator:
|
||||
return StartType.Cold
|
||||
return StartType.Warm
|
||||
|
||||
def determine_runway(self, cp: ControlPoint, dynamic_runways) -> RunwayData:
|
||||
fallback = RunwayData(cp.full_name, runway_heading=0, runway_name="")
|
||||
if cp.cptype == ControlPointType.AIRBASE:
|
||||
assigner = RunwayAssigner(self.game.conditions)
|
||||
return assigner.get_preferred_runway(cp.airport)
|
||||
elif cp.is_fleet:
|
||||
return dynamic_runways.get(cp.name, fallback)
|
||||
else:
|
||||
logging.warning(
|
||||
f"Unhandled departure/arrival control point: {cp.cptype}")
|
||||
return fallback
|
||||
|
||||
def _setup_group(self, group: FlyingGroup, for_task: Type[Task],
|
||||
package: Package, flight: Flight,
|
||||
dynamic_runways: Dict[str, RunwayData]) -> None:
|
||||
@ -752,19 +764,9 @@ class AircraftConflictGenerator:
|
||||
channel = self.get_intra_flight_channel(unit_type)
|
||||
group.set_frequency(channel.mhz)
|
||||
|
||||
# TODO: Support for different departure/arrival airfields.
|
||||
cp = flight.from_cp
|
||||
fallback_runway = RunwayData(cp.full_name, runway_heading=0,
|
||||
runway_name="")
|
||||
if cp.cptype == ControlPointType.AIRBASE:
|
||||
assigner = RunwayAssigner(self.game.conditions)
|
||||
departure_runway = assigner.get_preferred_runway(
|
||||
flight.from_cp.airport)
|
||||
elif cp.is_fleet:
|
||||
departure_runway = dynamic_runways.get(cp.name, fallback_runway)
|
||||
else:
|
||||
logging.warning(f"Unhandled departure control point: {cp.cptype}")
|
||||
departure_runway = fallback_runway
|
||||
divert = None
|
||||
if flight.divert is not None:
|
||||
divert = self.determine_runway(flight.divert, dynamic_runways)
|
||||
|
||||
self.flights.append(FlightData(
|
||||
package=package,
|
||||
@ -774,10 +776,9 @@ class AircraftConflictGenerator:
|
||||
friendly=flight.from_cp.captured,
|
||||
# Set later.
|
||||
departure_delay=timedelta(),
|
||||
departure=departure_runway,
|
||||
arrival=departure_runway,
|
||||
# TODO: Support for divert airfields.
|
||||
divert=None,
|
||||
departure=self.determine_runway(flight.departure, dynamic_runways),
|
||||
arrival=self.determine_runway(flight.arrival, dynamic_runways),
|
||||
divert=divert,
|
||||
# Waypoints are added later, after they've had their TOTs set.
|
||||
waypoints=[],
|
||||
intra_flight_channel=channel
|
||||
|
||||
@ -5,7 +5,8 @@ from typing import Tuple
|
||||
from dcs.country import Country
|
||||
from dcs.mapping import Point
|
||||
|
||||
from theater import ConflictTheater, ControlPoint, FrontLine
|
||||
from game.theater.conflicttheater import ConflictTheater, FrontLine
|
||||
from game.theater.controlpoint import ControlPoint
|
||||
|
||||
AIR_DISTANCE = 40000
|
||||
|
||||
|
||||
@ -16,11 +16,24 @@ from typing import (
|
||||
Type,
|
||||
)
|
||||
|
||||
from dcs.unittype import FlyingType, UnitType
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from game import db
|
||||
from game.data.radar_db import UNITS_WITH_RADAR
|
||||
from game.infos.information import Information
|
||||
from game.theater import (
|
||||
ControlPoint,
|
||||
FrontLine,
|
||||
MissionTarget,
|
||||
OffMapSpawn,
|
||||
SamGroundObject,
|
||||
TheaterGroundObject,
|
||||
)
|
||||
# Avoid importing some types that cause circular imports unless type checking.
|
||||
from game.theater.theatergroundobject import (
|
||||
EwrGroundObject,
|
||||
NavalGroundObject, VehicleGroupGroundObject,
|
||||
)
|
||||
from game.utils import nm_to_meter
|
||||
from gen import Conflict
|
||||
from gen.ato import Package
|
||||
@ -46,19 +59,6 @@ from gen.flights.flight import (
|
||||
)
|
||||
from gen.flights.flightplan import FlightPlanBuilder
|
||||
from gen.flights.traveltime import TotEstimator
|
||||
from theater import (
|
||||
ControlPoint,
|
||||
FrontLine,
|
||||
MissionTarget,
|
||||
OffMapSpawn, TheaterGroundObject,
|
||||
SamGroundObject,
|
||||
)
|
||||
|
||||
# Avoid importing some types that cause circular imports unless type checking.
|
||||
from game.theater.theatergroundobject import (
|
||||
EwrGroundObject,
|
||||
NavalGroundObject, VehicleGroupGroundObject,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@ -119,7 +119,7 @@ class AircraftAllocator:
|
||||
|
||||
def find_aircraft_for_flight(
|
||||
self, flight: ProposedFlight
|
||||
) -> Optional[Tuple[ControlPoint, UnitType]]:
|
||||
) -> Optional[Tuple[ControlPoint, FlyingType]]:
|
||||
"""Finds aircraft suitable for the given mission.
|
||||
|
||||
Searches for aircraft capable of performing the given mission within the
|
||||
@ -190,7 +190,7 @@ class AircraftAllocator:
|
||||
|
||||
def find_aircraft_of_type(
|
||||
self, flight: ProposedFlight, types: List[Type[FlyingType]],
|
||||
) -> Optional[Tuple[ControlPoint, UnitType]]:
|
||||
) -> Optional[Tuple[ControlPoint, FlyingType]]:
|
||||
airfields_in_range = self.closest_airfields.airfields_within(
|
||||
flight.max_distance
|
||||
)
|
||||
@ -214,6 +214,8 @@ class PackageBuilder:
|
||||
global_inventory: GlobalAircraftInventory,
|
||||
is_player: bool,
|
||||
start_type: str) -> None:
|
||||
self.closest_airfields = closest_airfields
|
||||
self.is_player = is_player
|
||||
self.package = Package(location)
|
||||
self.allocator = AircraftAllocator(closest_airfields, global_inventory,
|
||||
is_player)
|
||||
@ -236,11 +238,28 @@ class PackageBuilder:
|
||||
start_type = "In Flight"
|
||||
else:
|
||||
start_type = self.start_type
|
||||
flight = Flight(self.package, aircraft, plan.num_aircraft, airfield,
|
||||
plan.task, start_type)
|
||||
|
||||
flight = Flight(self.package, aircraft, plan.num_aircraft, plan.task,
|
||||
start_type, departure=airfield, arrival=airfield,
|
||||
divert=self.find_divert_field(aircraft, airfield))
|
||||
self.package.add_flight(flight)
|
||||
return True
|
||||
|
||||
def find_divert_field(self, aircraft: FlyingType,
|
||||
arrival: ControlPoint) -> Optional[ControlPoint]:
|
||||
divert_limit = nm_to_meter(150)
|
||||
for airfield in self.closest_airfields.airfields_within(divert_limit):
|
||||
if airfield.captured != self.is_player:
|
||||
continue
|
||||
if airfield == arrival:
|
||||
continue
|
||||
if not airfield.can_land(aircraft):
|
||||
continue
|
||||
if isinstance(airfield, OffMapSpawn):
|
||||
continue
|
||||
return airfield
|
||||
return None
|
||||
|
||||
def build(self) -> Package:
|
||||
"""Returns the built package."""
|
||||
return self.package
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"""Objective adjacency lists."""
|
||||
from typing import Dict, Iterator, List, Optional
|
||||
|
||||
from theater import ConflictTheater, ControlPoint, MissionTarget
|
||||
from game.theater import ConflictTheater, ControlPoint, MissionTarget
|
||||
|
||||
|
||||
class ClosestAirfields:
|
||||
|
||||
@ -65,6 +65,7 @@ class FlightWaypointType(Enum):
|
||||
INGRESS_DEAD = 20
|
||||
INGRESS_SWEEP = 21
|
||||
INGRESS_BAI = 22
|
||||
DIVERT = 23
|
||||
|
||||
|
||||
class FlightWaypoint:
|
||||
@ -133,12 +134,15 @@ class FlightWaypoint:
|
||||
class Flight:
|
||||
|
||||
def __init__(self, package: Package, unit_type: FlyingType, count: int,
|
||||
from_cp: ControlPoint, flight_type: FlightType,
|
||||
start_type: str) -> None:
|
||||
flight_type: FlightType, start_type: str,
|
||||
departure: ControlPoint, arrival: ControlPoint,
|
||||
divert: Optional[ControlPoint]) -> None:
|
||||
self.package = package
|
||||
self.unit_type = unit_type
|
||||
self.count = count
|
||||
self.from_cp = from_cp
|
||||
self.departure = departure
|
||||
self.arrival = arrival
|
||||
self.divert = divert
|
||||
self.flight_type = flight_type
|
||||
# TODO: Replace with FlightPlan.
|
||||
self.targets: List[MissionTarget] = []
|
||||
@ -157,6 +161,10 @@ class Flight:
|
||||
custom_waypoints=[]
|
||||
)
|
||||
|
||||
@property
|
||||
def from_cp(self) -> ControlPoint:
|
||||
return self.departure
|
||||
|
||||
@property
|
||||
def points(self) -> List[FlightWaypoint]:
|
||||
return self.flight_plan.waypoints[1:]
|
||||
|
||||
@ -7,20 +7,19 @@ generating the waypoints for the mission.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from datetime import timedelta
|
||||
from functools import cached_property
|
||||
import logging
|
||||
import math
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
from functools import cached_property
|
||||
from typing import Iterator, List, Optional, Set, TYPE_CHECKING, Tuple
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.unit import Unit
|
||||
|
||||
from game.data.doctrine import Doctrine
|
||||
from game.utils import nm_to_meter
|
||||
from theater import (
|
||||
from game.theater import (
|
||||
ControlPoint,
|
||||
FrontLine,
|
||||
MissionTarget,
|
||||
@ -28,6 +27,7 @@ from theater import (
|
||||
TheaterGroundObject,
|
||||
)
|
||||
from game.theater.theatergroundobject import EwrGroundObject
|
||||
from game.utils import nm_to_meter
|
||||
from .closestairfields import ObjectiveDistanceCache
|
||||
from .flight import Flight, FlightType, FlightWaypoint, FlightWaypointType
|
||||
from .traveltime import GroundSpeed, TravelTime
|
||||
@ -68,6 +68,10 @@ class FlightPlan:
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
"""A list of all waypoints in the flight plan, in order."""
|
||||
return list(self.iter_waypoints())
|
||||
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
"""Iterates over all waypoints in the flight plan, in order."""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@ -166,8 +170,7 @@ class FlightPlan:
|
||||
class LoiterFlightPlan(FlightPlan):
|
||||
hold: FlightWaypoint
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@ -193,8 +196,7 @@ class FormationFlightPlan(LoiterFlightPlan):
|
||||
join: FlightWaypoint
|
||||
split: FlightWaypoint
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@ -295,8 +297,7 @@ class PatrollingFlightPlan(FlightPlan):
|
||||
return self.patrol_end_time
|
||||
return None
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@ -312,15 +313,17 @@ class PatrollingFlightPlan(FlightPlan):
|
||||
class BarCapFlightPlan(PatrollingFlightPlan):
|
||||
takeoff: FlightWaypoint
|
||||
land: FlightWaypoint
|
||||
divert: Optional[FlightWaypoint]
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
return [
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield from [
|
||||
self.takeoff,
|
||||
self.patrol_start,
|
||||
self.patrol_end,
|
||||
self.land,
|
||||
]
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -328,16 +331,18 @@ class CasFlightPlan(PatrollingFlightPlan):
|
||||
takeoff: FlightWaypoint
|
||||
target: FlightWaypoint
|
||||
land: FlightWaypoint
|
||||
divert: Optional[FlightWaypoint]
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
return [
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield from [
|
||||
self.takeoff,
|
||||
self.patrol_start,
|
||||
self.target,
|
||||
self.patrol_end,
|
||||
self.land,
|
||||
]
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
|
||||
def request_escort_at(self) -> Optional[FlightWaypoint]:
|
||||
return self.patrol_start
|
||||
@ -350,16 +355,18 @@ class CasFlightPlan(PatrollingFlightPlan):
|
||||
class TarCapFlightPlan(PatrollingFlightPlan):
|
||||
takeoff: FlightWaypoint
|
||||
land: FlightWaypoint
|
||||
divert: Optional[FlightWaypoint]
|
||||
lead_time: timedelta
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
return [
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield from [
|
||||
self.takeoff,
|
||||
self.patrol_start,
|
||||
self.patrol_end,
|
||||
self.land,
|
||||
]
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
|
||||
@property
|
||||
def tot_offset(self) -> timedelta:
|
||||
@ -386,10 +393,6 @@ class TarCapFlightPlan(PatrollingFlightPlan):
|
||||
return super().patrol_end_time
|
||||
|
||||
|
||||
# TODO: Remove when breaking save compat.
|
||||
FrontLineCapFlightPlan = TarCapFlightPlan
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class StrikeFlightPlan(FormationFlightPlan):
|
||||
takeoff: FlightWaypoint
|
||||
@ -400,19 +403,23 @@ class StrikeFlightPlan(FormationFlightPlan):
|
||||
egress: FlightWaypoint
|
||||
split: FlightWaypoint
|
||||
land: FlightWaypoint
|
||||
divert: Optional[FlightWaypoint]
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
return [
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield from [
|
||||
self.takeoff,
|
||||
self.hold,
|
||||
self.join,
|
||||
self.ingress
|
||||
] + self.targets + [
|
||||
]
|
||||
yield from self.targets
|
||||
yield from[
|
||||
self.egress,
|
||||
self.split,
|
||||
self.land,
|
||||
]
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
|
||||
@property
|
||||
def package_speed_waypoints(self) -> Set[FlightWaypoint]:
|
||||
@ -511,17 +518,19 @@ class SweepFlightPlan(LoiterFlightPlan):
|
||||
sweep_start: FlightWaypoint
|
||||
sweep_end: FlightWaypoint
|
||||
land: FlightWaypoint
|
||||
divert: Optional[FlightWaypoint]
|
||||
lead_time: timedelta
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
return [
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield from [
|
||||
self.takeoff,
|
||||
self.hold,
|
||||
self.sweep_start,
|
||||
self.sweep_end,
|
||||
self.land,
|
||||
]
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
|
||||
@property
|
||||
def tot_waypoint(self) -> Optional[FlightWaypoint]:
|
||||
@ -567,9 +576,8 @@ class SweepFlightPlan(LoiterFlightPlan):
|
||||
class CustomFlightPlan(FlightPlan):
|
||||
custom_waypoints: List[FlightWaypoint]
|
||||
|
||||
@property
|
||||
def waypoints(self) -> List[FlightWaypoint]:
|
||||
return self.custom_waypoints
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield from self.custom_waypoints
|
||||
|
||||
@property
|
||||
def tot_waypoint(self) -> Optional[FlightWaypoint]:
|
||||
@ -774,10 +782,11 @@ class FlightPlanBuilder:
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
patrol_duration=self.doctrine.cap_duration,
|
||||
takeoff=builder.takeoff(flight.from_cp),
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
patrol_start=start,
|
||||
patrol_end=end,
|
||||
land=builder.land(flight.from_cp)
|
||||
land=builder.land(flight.arrival),
|
||||
divert=builder.divert(flight.divert)
|
||||
)
|
||||
|
||||
def generate_sweep(self, flight: Flight) -> SweepFlightPlan:
|
||||
@ -800,11 +809,12 @@ class FlightPlanBuilder:
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
lead_time=timedelta(minutes=5),
|
||||
takeoff=builder.takeoff(flight.from_cp),
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
hold=builder.hold(self._hold_point(flight)),
|
||||
sweep_start=start,
|
||||
sweep_end=end,
|
||||
land=builder.land(flight.from_cp)
|
||||
land=builder.land(flight.arrival),
|
||||
divert=builder.divert(flight.divert)
|
||||
)
|
||||
|
||||
def racetrack_for_objective(self,
|
||||
@ -900,10 +910,11 @@ class FlightPlanBuilder:
|
||||
# requests an escort the CAP flight will remain on station for the
|
||||
# duration of the escorted mission, or until it is winchester/bingo.
|
||||
patrol_duration=self.doctrine.cap_duration,
|
||||
takeoff=builder.takeoff(flight.from_cp),
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
patrol_start=start,
|
||||
patrol_end=end,
|
||||
land=builder.land(flight.from_cp)
|
||||
land=builder.land(flight.arrival),
|
||||
divert=builder.divert(flight.divert)
|
||||
)
|
||||
|
||||
def generate_dead(self, flight: Flight,
|
||||
@ -965,14 +976,15 @@ class FlightPlanBuilder:
|
||||
return StrikeFlightPlan(
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
takeoff=builder.takeoff(flight.from_cp),
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
hold=builder.hold(self._hold_point(flight)),
|
||||
join=builder.join(self.package.waypoints.join),
|
||||
ingress=ingress,
|
||||
targets=[target],
|
||||
egress=egress,
|
||||
split=builder.split(self.package.waypoints.split),
|
||||
land=builder.land(flight.from_cp)
|
||||
land=builder.land(flight.arrival),
|
||||
divert=builder.divert(flight.divert)
|
||||
)
|
||||
|
||||
def generate_cas(self, flight: Flight) -> CasFlightPlan:
|
||||
@ -999,11 +1011,12 @@ class FlightPlanBuilder:
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
patrol_duration=self.doctrine.cas_duration,
|
||||
takeoff=builder.takeoff(flight.from_cp),
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
patrol_start=builder.ingress_cas(ingress, location),
|
||||
target=builder.cas(center),
|
||||
patrol_end=builder.egress(egress, location),
|
||||
land=builder.land(flight.from_cp)
|
||||
land=builder.land(flight.arrival),
|
||||
divert=builder.divert(flight.divert)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@ -1030,7 +1043,7 @@ class FlightPlanBuilder:
|
||||
|
||||
def _hold_point(self, flight: Flight) -> Point:
|
||||
assert self.package.waypoints is not None
|
||||
origin = flight.from_cp.position
|
||||
origin = flight.departure.position
|
||||
target = self.package.target.position
|
||||
join = self.package.waypoints.join
|
||||
origin_to_target = origin.distance_to_point(target)
|
||||
@ -1118,14 +1131,15 @@ class FlightPlanBuilder:
|
||||
return StrikeFlightPlan(
|
||||
package=self.package,
|
||||
flight=flight,
|
||||
takeoff=builder.takeoff(flight.from_cp),
|
||||
takeoff=builder.takeoff(flight.departure),
|
||||
hold=builder.hold(self._hold_point(flight)),
|
||||
join=builder.join(self.package.waypoints.join),
|
||||
ingress=ingress,
|
||||
targets=target_waypoints,
|
||||
egress=builder.egress(self.package.waypoints.egress, location),
|
||||
split=builder.split(self.package.waypoints.split),
|
||||
land=builder.land(flight.from_cp)
|
||||
land=builder.land(flight.arrival),
|
||||
divert=builder.divert(flight.divert)
|
||||
)
|
||||
|
||||
def _retreating_rendezvous_point(self, attack_transition: Point) -> Point:
|
||||
@ -1201,7 +1215,7 @@ class FlightPlanBuilder:
|
||||
)
|
||||
for airfield in cache.closest_airfields:
|
||||
for flight in self.package.flights:
|
||||
if flight.from_cp == airfield:
|
||||
if flight.departure == airfield:
|
||||
return airfield
|
||||
raise RuntimeError(
|
||||
"Could not find any airfield assigned to this package"
|
||||
|
||||
@ -8,14 +8,13 @@ from dcs.unit import Unit
|
||||
from dcs.unitgroup import VehicleGroup
|
||||
|
||||
from game.data.doctrine import Doctrine
|
||||
from game.utils import feet_to_meter
|
||||
from game.weather import Conditions
|
||||
from theater import (
|
||||
from game.theater import (
|
||||
ControlPoint,
|
||||
MissionTarget,
|
||||
OffMapSpawn,
|
||||
TheaterGroundObject,
|
||||
)
|
||||
from game.weather import Conditions
|
||||
from .flight import Flight, FlightWaypoint, FlightWaypointType
|
||||
|
||||
|
||||
@ -104,6 +103,40 @@ class WaypointBuilder:
|
||||
waypoint.pretty_name = "Land"
|
||||
return waypoint
|
||||
|
||||
def divert(self,
|
||||
divert: Optional[ControlPoint]) -> Optional[FlightWaypoint]:
|
||||
"""Create divert waypoint for the given arrival airfield or carrier.
|
||||
|
||||
Args:
|
||||
divert: Divert airfield or carrier.
|
||||
"""
|
||||
if divert is None:
|
||||
return None
|
||||
|
||||
position = divert.position
|
||||
if isinstance(divert, OffMapSpawn):
|
||||
if self.is_helo:
|
||||
altitude = 500
|
||||
else:
|
||||
altitude = self.doctrine.rendezvous_altitude
|
||||
altitude_type = "BARO"
|
||||
else:
|
||||
altitude = 0
|
||||
altitude_type = "RADIO"
|
||||
|
||||
waypoint = FlightWaypoint(
|
||||
FlightWaypointType.DIVERT,
|
||||
position.x,
|
||||
position.y,
|
||||
altitude
|
||||
)
|
||||
waypoint.alt_type = altitude_type
|
||||
waypoint.name = "DIVERT"
|
||||
waypoint.description = "Divert"
|
||||
waypoint.pretty_name = "Divert"
|
||||
waypoint.only_for_player = True
|
||||
return waypoint
|
||||
|
||||
def hold(self, position: Point) -> FlightWaypoint:
|
||||
waypoint = FlightWaypoint(
|
||||
FlightWaypointType.LOITER,
|
||||
|
||||
@ -2,12 +2,12 @@ import random
|
||||
from enum import Enum
|
||||
from typing import Dict, List
|
||||
|
||||
from dcs.vehicles import Armor, Artillery, Infantry, Unarmed
|
||||
from dcs.unittype import VehicleType
|
||||
from dcs.vehicles import Armor, Artillery, Infantry, Unarmed
|
||||
|
||||
import pydcs_extensions.frenchpack.frenchpack as frenchpack
|
||||
from game.theater import ControlPoint
|
||||
from gen.ground_forces.combat_stance import CombatStance
|
||||
from theater import ControlPoint
|
||||
|
||||
TYPE_TANKS = [
|
||||
Armor.MBT_T_55,
|
||||
|
||||
@ -20,14 +20,14 @@ from dcs.task import (
|
||||
EPLRS,
|
||||
OptAlarmState,
|
||||
)
|
||||
from dcs.unit import Ship, Vehicle, Unit
|
||||
from dcs.unit import Ship, Unit, Vehicle
|
||||
from dcs.unitgroup import Group, ShipGroup, StaticGroup
|
||||
from dcs.unittype import StaticType, UnitType
|
||||
|
||||
from game import db
|
||||
from game.data.building_data import FORTIFICATION_UNITS, FORTIFICATION_UNITS_ID
|
||||
from game.db import unit_type_from_name
|
||||
from theater import ControlPoint, TheaterGroundObject
|
||||
from game.theater import ControlPoint, TheaterGroundObject
|
||||
from game.theater.theatergroundobject import (
|
||||
BuildingGroundObject, CarrierGroundObject,
|
||||
GenericCarrierGroundObject,
|
||||
|
||||
@ -7,8 +7,8 @@ from typing import Iterator, Optional
|
||||
|
||||
from dcs.terrain.terrain import Airport
|
||||
|
||||
from game.theater import ControlPoint, ControlPointType
|
||||
from game.weather import Conditions
|
||||
from theater import ControlPoint, ControlPointType
|
||||
from .airfields import AIRFIELD_DATA
|
||||
from .radios import RadioFrequency
|
||||
from .tacan import TacanChannel
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
from PySide2.QtWidgets import QGridLayout, QLabel, QGroupBox, QVBoxLayout, QLCDNumber
|
||||
|
||||
from theater import ControlPoint, Airport
|
||||
|
||||
|
||||
class QAirportInformation(QGroupBox):
|
||||
|
||||
def __init__(self, cp:ControlPoint, airport:Airport):
|
||||
super(QAirportInformation, self).__init__(airport.name)
|
||||
self.cp = cp
|
||||
self.airport = airport
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
self.layout = QGridLayout()
|
||||
|
||||
# Runway information
|
||||
self.runways = QGroupBox("Runways")
|
||||
self.runwayLayout = QGridLayout()
|
||||
for i, runway in enumerate(self.airport.runways):
|
||||
|
||||
# Seems like info is missing in pydcs, even if the attribute is there
|
||||
lr = ""
|
||||
if runway.leftright == 1:
|
||||
lr = "L"
|
||||
elif runway.leftright == 2:
|
||||
lr = "R"
|
||||
|
||||
self.runwayLayout.addWidget(QLabel("Runway " + str(runway.heading) + lr), i, 0)
|
||||
|
||||
# Seems like info is missing in pydcs, even if the attribute is there
|
||||
if runway.ils:
|
||||
self.runwayLayout.addWidget(QLabel("ILS "), i, 1)
|
||||
self.runwayLayout.addWidget(QLCDNumber(6, runway.ils), i, 1)
|
||||
else:
|
||||
self.runwayLayout.addWidget(QLabel("NO ILS"), i, 1)
|
||||
|
||||
|
||||
self.runways.setLayout(self.runwayLayout)
|
||||
self.layout.addWidget(self.runways, 0, 0)
|
||||
|
||||
self.layout.addWidget(QLabel("<b>Parking Slots :</b>"), 1, 0)
|
||||
self.layout.addWidget(QLabel(str(len(self.airport.parking_slots))), 1, 1)
|
||||
|
||||
|
||||
stretch = QVBoxLayout()
|
||||
stretch.addStretch()
|
||||
|
||||
self.layout.addLayout(stretch, 2, 0)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
|
||||
@ -3,13 +3,13 @@ from typing import Iterable
|
||||
|
||||
from PySide2.QtWidgets import QComboBox
|
||||
|
||||
from dcs.planes import PlaneType
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
|
||||
class QAircraftTypeSelector(QComboBox):
|
||||
"""Combo box for selecting among the given aircraft types."""
|
||||
|
||||
def __init__(self, aircraft_types: Iterable[PlaneType]) -> None:
|
||||
def __init__(self, aircraft_types: Iterable[FlyingType]) -> None:
|
||||
super().__init__()
|
||||
for aircraft in aircraft_types:
|
||||
self.addItem(f"{aircraft.id}", userData=aircraft)
|
||||
|
||||
40
qt_ui/widgets/combos/QArrivalAirfieldSelector.py
Normal file
40
qt_ui/widgets/combos/QArrivalAirfieldSelector.py
Normal file
@ -0,0 +1,40 @@
|
||||
"""Combo box for selecting a departure airfield."""
|
||||
from typing import Iterable
|
||||
|
||||
from PySide2.QtWidgets import QComboBox
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from game import db
|
||||
from game.theater.controlpoint import ControlPoint
|
||||
|
||||
|
||||
class QArrivalAirfieldSelector(QComboBox):
|
||||
"""A combo box for selecting a flight's arrival or divert airfield.
|
||||
|
||||
The combo box will automatically be populated with all airfields the given
|
||||
aircraft type is able to land at.
|
||||
"""
|
||||
|
||||
def __init__(self, destinations: Iterable[ControlPoint],
|
||||
aircraft: FlyingType, optional_text: str) -> None:
|
||||
super().__init__()
|
||||
self.destinations = list(destinations)
|
||||
self.aircraft = aircraft
|
||||
self.optional_text = optional_text
|
||||
self.rebuild_selector()
|
||||
self.setCurrentIndex(0)
|
||||
|
||||
def change_aircraft(self, aircraft: FlyingType) -> None:
|
||||
if self.aircraft == aircraft:
|
||||
return
|
||||
self.aircraft = aircraft
|
||||
self.rebuild_selector()
|
||||
|
||||
def rebuild_selector(self) -> None:
|
||||
self.clear()
|
||||
for destination in self.destinations:
|
||||
if destination.can_land(self.aircraft):
|
||||
self.addItem(destination.name, destination)
|
||||
self.model().sort(0)
|
||||
self.insertItem(0, self.optional_text, None)
|
||||
self.update()
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
from PySide2.QtWidgets import QComboBox
|
||||
|
||||
from theater import ConflictTheater, MissionTarget
|
||||
from game.theater import ConflictTheater, MissionTarget
|
||||
|
||||
|
||||
class QFlightTypeComboBox(QComboBox):
|
||||
|
||||
@ -3,7 +3,7 @@ from typing import Iterable
|
||||
|
||||
from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import QComboBox
|
||||
from dcs.planes import PlaneType
|
||||
from dcs.unittype import FlyingType
|
||||
|
||||
from game.inventory import GlobalAircraftInventory
|
||||
from game.theater.controlpoint import ControlPoint
|
||||
@ -20,7 +20,7 @@ class QOriginAirfieldSelector(QComboBox):
|
||||
|
||||
def __init__(self, global_inventory: GlobalAircraftInventory,
|
||||
origins: Iterable[ControlPoint],
|
||||
aircraft: PlaneType) -> None:
|
||||
aircraft: FlyingType) -> None:
|
||||
super().__init__()
|
||||
self.global_inventory = global_inventory
|
||||
self.origins = list(origins)
|
||||
@ -28,7 +28,7 @@ class QOriginAirfieldSelector(QComboBox):
|
||||
self.rebuild_selector()
|
||||
self.currentIndexChanged.connect(self.index_changed)
|
||||
|
||||
def change_aircraft(self, aircraft: PlaneType) -> None:
|
||||
def change_aircraft(self, aircraft: FlyingType) -> None:
|
||||
if self.aircraft == aircraft:
|
||||
return
|
||||
self.aircraft = aircraft
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||
|
||||
from game import Game
|
||||
from game.theater import ControlPointType
|
||||
from gen import BuildingGroundObject, Conflict, FlightWaypointType
|
||||
from gen.flights.flight import FlightWaypoint
|
||||
from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
|
||||
from theater import ControlPointType
|
||||
|
||||
|
||||
class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
|
||||
|
||||
@ -13,11 +13,11 @@ from PySide2.QtWidgets import (
|
||||
)
|
||||
|
||||
import qt_ui.uiconstants as const
|
||||
from game.theater import FrontLine
|
||||
from qt_ui.dialogs import Dialog
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.mission.QPackageDialog import QNewPackageDialog
|
||||
from theater import FrontLine
|
||||
|
||||
|
||||
class QFrontLine(QGraphicsLineItem):
|
||||
|
||||
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import datetime
|
||||
import logging
|
||||
import math
|
||||
from typing import Iterable, List, Optional, Tuple, Iterator
|
||||
from typing import Iterable, Iterator, List, Optional, Tuple
|
||||
|
||||
from PySide2.QtCore import QPointF, Qt
|
||||
from PySide2.QtGui import (
|
||||
@ -27,6 +27,13 @@ from dcs.mapping import point_from_heading
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game import Game, db
|
||||
from game.theater import ControlPoint
|
||||
from game.theater.conflicttheater import FrontLine
|
||||
from game.theater.theatergroundobject import (
|
||||
EwrGroundObject,
|
||||
MissileSiteGroundObject,
|
||||
TheaterGroundObject,
|
||||
)
|
||||
from game.utils import meter_to_feet
|
||||
from game.weather import TimeOfDay
|
||||
from gen import Conflict
|
||||
@ -39,13 +46,7 @@ from qt_ui.widgets.map.QLiberationScene import QLiberationScene
|
||||
from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint
|
||||
from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from theater import ControlPoint
|
||||
from game.theater.conflicttheater import FrontLine
|
||||
from game.theater.theatergroundobject import (
|
||||
EwrGroundObject,
|
||||
MissileSiteGroundObject,
|
||||
TheaterGroundObject,
|
||||
)
|
||||
|
||||
|
||||
def binomial(i: int, n: int) -> float:
|
||||
"""Binomial coefficient"""
|
||||
@ -373,6 +374,10 @@ class QLiberationMap(QGraphicsView):
|
||||
FlightWaypointType.TARGET_SHIP,
|
||||
)
|
||||
for idx, point in enumerate(flight.flight_plan.waypoints[1:]):
|
||||
if point.waypoint_type == FlightWaypointType.DIVERT:
|
||||
# Don't clutter the map showing divert points.
|
||||
continue
|
||||
|
||||
new_pos = self._transform_point(Point(point.x, point.y))
|
||||
self.draw_flight_path(scene, prev_pos, new_pos, is_player,
|
||||
selected)
|
||||
@ -386,7 +391,6 @@ class QLiberationMap(QGraphicsView):
|
||||
self.draw_waypoint_info(scene, idx + 1, point, new_pos,
|
||||
flight.flight_plan)
|
||||
prev_pos = tuple(new_pos)
|
||||
self.draw_flight_path(scene, prev_pos, pos, is_player, selected)
|
||||
|
||||
def draw_waypoint(self, scene: QGraphicsScene, position: Tuple[int, int],
|
||||
player: bool, selected: bool) -> None:
|
||||
|
||||
@ -4,9 +4,9 @@ from PySide2.QtGui import QColor, QPainter
|
||||
from PySide2.QtWidgets import QAction, QMenu
|
||||
|
||||
import qt_ui.uiconstants as const
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2
|
||||
from theater import ControlPoint
|
||||
from .QMapObject import QMapObject
|
||||
from ...displayoptions import DisplayOptions
|
||||
from ...windows.GameUpdateSignal import GameUpdateSignal
|
||||
|
||||
@ -8,8 +8,8 @@ import qt_ui.uiconstants as const
|
||||
from game import Game
|
||||
from game.data.building_data import FORTIFICATION_BUILDINGS
|
||||
from game.db import REWARDS
|
||||
from game.theater import ControlPoint, TheaterGroundObject
|
||||
from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu
|
||||
from theater import ControlPoint, TheaterGroundObject
|
||||
from .QMapObject import QMapObject
|
||||
from ...displayoptions import DisplayOptions
|
||||
|
||||
|
||||
@ -2,12 +2,12 @@ from PySide2.QtCore import Qt
|
||||
from PySide2.QtGui import QCloseEvent, QPixmap
|
||||
from PySide2.QtWidgets import QDialog, QGridLayout, QHBoxLayout, QLabel, QWidget
|
||||
|
||||
from game.theater import ControlPoint, ControlPointType
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.basemenu.QBaseMenuTabs import QBaseMenuTabs
|
||||
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
|
||||
from theater import ControlPoint, ControlPointType
|
||||
|
||||
|
||||
class QBaseMenu2(QDialog):
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
from PySide2.QtWidgets import QFrame, QGridLayout, QLabel, QTabWidget
|
||||
from PySide2.QtWidgets import QTabWidget
|
||||
|
||||
from game.theater import ControlPoint, OffMapSpawn
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.basemenu.airfield.QAirfieldCommand import QAirfieldCommand
|
||||
from qt_ui.windows.basemenu.base_defenses.QBaseDefensesHQ import QBaseDefensesHQ
|
||||
from qt_ui.windows.basemenu.ground_forces.QGroundForcesHQ import QGroundForcesHQ
|
||||
from qt_ui.windows.basemenu.intel.QIntelInfo import QIntelInfo
|
||||
from theater import ControlPoint, OffMapSpawn
|
||||
|
||||
|
||||
class QBaseMenuTabs(QTabWidget):
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import logging
|
||||
|
||||
from PySide2.QtWidgets import (
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
@ -6,17 +8,17 @@ from PySide2.QtWidgets import (
|
||||
QSizePolicy,
|
||||
QSpacerItem,
|
||||
)
|
||||
import logging
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from theater import db
|
||||
|
||||
from game import db
|
||||
from game.event import UnitsDeliveryEvent
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.models import GameModel
|
||||
|
||||
|
||||
class QRecruitBehaviour:
|
||||
game = None
|
||||
cp = None
|
||||
deliveryEvent = None
|
||||
game_model: GameModel
|
||||
cp: ControlPoint
|
||||
existing_units_labels = None
|
||||
bought_amount_labels = None
|
||||
maximum_units = -1
|
||||
@ -24,12 +26,16 @@ class QRecruitBehaviour:
|
||||
BUDGET_FORMAT = "Available Budget: <b>${}M</b>"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.deliveryEvent = None
|
||||
self.bought_amount_labels = {}
|
||||
self.existing_units_labels = {}
|
||||
self.recruitable_types = []
|
||||
self.update_available_budget()
|
||||
|
||||
@property
|
||||
def pending_deliveries(self) -> UnitsDeliveryEvent:
|
||||
assert self.cp.pending_unit_deliveries
|
||||
return self.cp.pending_unit_deliveries
|
||||
|
||||
@property
|
||||
def budget(self) -> int:
|
||||
return self.game_model.game.budget
|
||||
@ -47,7 +53,7 @@ class QRecruitBehaviour:
|
||||
exist.setLayout(existLayout)
|
||||
|
||||
existing_units = self.cp.base.total_units_of_type(unit_type)
|
||||
scheduled_units = self.deliveryEvent.units.get(unit_type, 0)
|
||||
scheduled_units = self.pending_deliveries.units.get(unit_type, 0)
|
||||
|
||||
unitName = QLabel("<b>" + db.unit_type_name_2(unit_type) + "</b>")
|
||||
unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
||||
@ -103,7 +109,7 @@ class QRecruitBehaviour:
|
||||
def _update_count_label(self, unit_type: UnitType):
|
||||
|
||||
self.bought_amount_labels[unit_type].setText("<b>{}</b>".format(
|
||||
unit_type in self.deliveryEvent.units and "{}".format(self.deliveryEvent.units[unit_type]) or "0"
|
||||
unit_type in self.pending_deliveries.units and "{}".format(self.pending_deliveries.units[unit_type]) or "0"
|
||||
))
|
||||
|
||||
self.existing_units_labels[unit_type].setText("<b>{}</b>".format(
|
||||
@ -129,7 +135,7 @@ class QRecruitBehaviour:
|
||||
|
||||
price = db.PRICES[unit_type]
|
||||
if self.budget >= price:
|
||||
self.deliveryEvent.deliver({unit_type: 1})
|
||||
self.pending_deliveries.deliver({unit_type: 1})
|
||||
self.budget -= price
|
||||
else:
|
||||
# TODO : display modal warning
|
||||
@ -138,12 +144,12 @@ class QRecruitBehaviour:
|
||||
self.update_available_budget()
|
||||
|
||||
def sell(self, unit_type):
|
||||
if self.deliveryEvent.units.get(unit_type, 0) > 0:
|
||||
if self.pending_deliveries.units.get(unit_type, 0) > 0:
|
||||
price = db.PRICES[unit_type]
|
||||
self.budget += price
|
||||
self.deliveryEvent.units[unit_type] = self.deliveryEvent.units[unit_type] - 1
|
||||
if self.deliveryEvent.units[unit_type] == 0:
|
||||
del self.deliveryEvent.units[unit_type]
|
||||
self.pending_deliveries.units[unit_type] = self.pending_deliveries.units[unit_type] - 1
|
||||
if self.pending_deliveries.units[unit_type] == 0:
|
||||
del self.pending_deliveries.units[unit_type]
|
||||
elif self.cp.base.total_units_of_type(unit_type) > 0:
|
||||
price = db.PRICES[unit_type]
|
||||
self.budget += price
|
||||
@ -154,20 +160,14 @@ class QRecruitBehaviour:
|
||||
|
||||
@property
|
||||
def total_units(self):
|
||||
|
||||
total = 0
|
||||
for unit_type in self.recruitables_types:
|
||||
total += self.cp.base.total_units(unit_type)
|
||||
print(unit_type, total, self.cp.base.total_units(unit_type))
|
||||
print("--------------------------------")
|
||||
|
||||
if self.deliveryEvent:
|
||||
for unit_bought in self.deliveryEvent.units:
|
||||
if self.pending_deliveries:
|
||||
for unit_bought in self.pending_deliveries.units:
|
||||
if db.unit_task(unit_bought) in self.recruitables_types:
|
||||
total += self.deliveryEvent.units[unit_bought]
|
||||
print(unit_bought, total, self.deliveryEvent.units[unit_bought])
|
||||
|
||||
print("=============================")
|
||||
total += self.pending_deliveries.units[unit_bought]
|
||||
|
||||
return total
|
||||
|
||||
@ -181,4 +181,4 @@ class QRecruitBehaviour:
|
||||
"""
|
||||
Set the maximum number of units that can be bought
|
||||
"""
|
||||
self.recruitables_types = recruitables_types
|
||||
self.recruitables_types = recruitables_types
|
||||
|
||||
@ -11,13 +11,14 @@ from PySide2.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from dcs.task import CAP, CAS
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from game.event.event import UnitsDeliveryEvent
|
||||
from game import db
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.uiconstants import ICONS
|
||||
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
|
||||
from theater import CAP, CAS, ControlPoint, db
|
||||
|
||||
|
||||
class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
@ -25,17 +26,10 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
QFrame.__init__(self)
|
||||
self.cp = cp
|
||||
self.game_model = game_model
|
||||
self.deliveryEvent: Optional[UnitsDeliveryEvent] = None
|
||||
|
||||
self.bought_amount_labels = {}
|
||||
self.existing_units_labels = {}
|
||||
|
||||
for event in self.game_model.game.events:
|
||||
if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp:
|
||||
self.deliveryEvent = event
|
||||
if not self.deliveryEvent:
|
||||
self.deliveryEvent = self.game_model.game.units_delivery_event(self.cp)
|
||||
|
||||
# Determine maximum number of aircrafts that can be bought
|
||||
self.set_maximum_units(self.cp.available_aircraft_slots)
|
||||
self.set_recruitable_types([CAP, CAS])
|
||||
@ -92,7 +86,7 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
def sell(self, unit_type: UnitType):
|
||||
# Don't need to remove aircraft from the inventory if we're canceling
|
||||
# orders.
|
||||
if self.deliveryEvent.units.get(unit_type, 0) <= 0:
|
||||
if self.pending_deliveries.units.get(unit_type, 0) <= 0:
|
||||
global_inventory = self.game_model.game.aircraft_inventory
|
||||
inventory = global_inventory.for_control_point(self.cp)
|
||||
try:
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
from PySide2.QtWidgets import QFrame, QGridLayout, QGroupBox, QVBoxLayout
|
||||
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.basemenu.airfield.QAircraftRecruitmentMenu import \
|
||||
QAircraftRecruitmentMenu
|
||||
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
|
||||
from theater import ControlPoint
|
||||
|
||||
|
||||
class QAirfieldCommand(QFrame):
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtWidgets import QGridLayout, QLabel, QGroupBox, QPushButton, QVBoxLayout
|
||||
from PySide2.QtWidgets import (
|
||||
QGridLayout,
|
||||
QGroupBox,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QVBoxLayout,
|
||||
)
|
||||
|
||||
from game.theater import ControlPoint, TheaterGroundObject
|
||||
from qt_ui.dialogs import Dialog
|
||||
from qt_ui.uiconstants import VEHICLES_ICONS
|
||||
from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu
|
||||
from theater import ControlPoint, TheaterGroundObject
|
||||
|
||||
|
||||
class QBaseDefenseGroupInfo(QGroupBox):
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
from PySide2.QtWidgets import QFrame, QGridLayout
|
||||
|
||||
from game import Game
|
||||
from qt_ui.windows.basemenu.base_defenses.QBaseInformation import QBaseInformation
|
||||
from theater import ControlPoint
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.windows.basemenu.base_defenses.QBaseInformation import \
|
||||
QBaseInformation
|
||||
|
||||
|
||||
class QBaseDefensesHQ(QFrame):
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
from PySide2.QtGui import Qt
|
||||
from PySide2.QtWidgets import QGridLayout, QLabel, QGroupBox, QVBoxLayout, QFrame, QWidget, QScrollArea
|
||||
from PySide2.QtWidgets import (
|
||||
QFrame,
|
||||
QGridLayout,
|
||||
QScrollArea,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from game import db
|
||||
from qt_ui.uiconstants import AIRCRAFT_ICONS, VEHICLES_ICONS
|
||||
from qt_ui.windows.basemenu.base_defenses.QBaseDefenseGroupInfo import QBaseDefenseGroupInfo
|
||||
from theater import ControlPoint, Airport
|
||||
from game.theater import Airport, ControlPoint
|
||||
from qt_ui.windows.basemenu.base_defenses.QBaseDefenseGroupInfo import \
|
||||
QBaseDefenseGroupInfo
|
||||
|
||||
|
||||
class QBaseInformation(QFrame):
|
||||
|
||||
@ -6,11 +6,12 @@ from PySide2.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from dcs.task import PinpointStrike
|
||||
|
||||
from game.event import UnitsDeliveryEvent
|
||||
from game import db
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
|
||||
from theater import ControlPoint, PinpointStrike, db
|
||||
|
||||
|
||||
class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
@ -23,12 +24,6 @@ class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
self.bought_amount_labels = {}
|
||||
self.existing_units_labels = {}
|
||||
|
||||
for event in self.game_model.game.events:
|
||||
if event.__class__ == UnitsDeliveryEvent and event.from_cp == self.cp:
|
||||
self.deliveryEvent = event
|
||||
if not self.deliveryEvent:
|
||||
self.deliveryEvent = self.game_model.game.units_delivery_event(self.cp)
|
||||
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
@ -61,4 +56,4 @@ class QArmorRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
scroll.setWidgetResizable(True)
|
||||
scroll.setWidget(scroll_content)
|
||||
main_layout.addWidget(scroll)
|
||||
self.setLayout(main_layout)
|
||||
self.setLayout(main_layout)
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
from PySide2.QtWidgets import QFrame, QGridLayout
|
||||
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.basemenu.ground_forces.QArmorRecruitmentMenu import \
|
||||
QArmorRecruitmentMenu
|
||||
from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategy import \
|
||||
QGroundForcesStrategy
|
||||
from theater import ControlPoint
|
||||
|
||||
|
||||
class QGroundForcesHQ(QFrame):
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
from PySide2.QtWidgets import QLabel, QGroupBox, QVBoxLayout
|
||||
from PySide2.QtWidgets import QGroupBox, QLabel, QVBoxLayout
|
||||
|
||||
from game import Game
|
||||
from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import QGroundForcesStrategySelector
|
||||
from theater import ControlPoint
|
||||
from game.theater import ControlPoint
|
||||
from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import \
|
||||
QGroundForcesStrategySelector
|
||||
|
||||
|
||||
class QGroundForcesStrategy(QGroupBox):
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from PySide2.QtWidgets import QComboBox
|
||||
|
||||
from theater import ControlPoint, CombatStance
|
||||
from game.theater import CombatStance, ControlPoint
|
||||
|
||||
|
||||
class QGroundForcesStrategySelector(QComboBox):
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
from PySide2.QtWidgets import (
|
||||
QFrame,
|
||||
QGridLayout,
|
||||
QGroupBox,
|
||||
QLabel,
|
||||
QVBoxLayout,
|
||||
)
|
||||
from dcs.task import CAP, CAS, Embarking, PinpointStrike
|
||||
|
||||
|
||||
from PySide2.QtWidgets import QLabel, QGroupBox, QVBoxLayout, QFrame, QGridLayout
|
||||
from dcs.task import Embarking, CAS, PinpointStrike, CAP
|
||||
|
||||
from game import Game
|
||||
from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import QGroundForcesStrategySelector
|
||||
from theater import ControlPoint, db
|
||||
from game import Game, db
|
||||
from game.theater import ControlPoint
|
||||
|
||||
|
||||
class QIntelInfo(QFrame):
|
||||
|
||||
@ -2,20 +2,31 @@ import logging
|
||||
|
||||
from PySide2 import QtCore
|
||||
from PySide2.QtGui import Qt
|
||||
from PySide2.QtWidgets import QHBoxLayout, QDialog, QGridLayout, QLabel, QGroupBox, QVBoxLayout, QPushButton, \
|
||||
QComboBox, QSpinBox, QMessageBox
|
||||
from PySide2.QtWidgets import (
|
||||
QComboBox,
|
||||
QDialog,
|
||||
QGridLayout,
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QMessageBox,
|
||||
QPushButton,
|
||||
QSpinBox,
|
||||
QVBoxLayout,
|
||||
)
|
||||
from dcs import Point
|
||||
|
||||
from game import Game, db
|
||||
from game.data.building_data import FORTIFICATION_BUILDINGS
|
||||
from game.db import PRICES, REWARDS, unit_type_of, PinpointStrike
|
||||
from gen.defenses.armor_group_generator import generate_armor_group_of_type_and_size
|
||||
from game.db import PRICES, PinpointStrike, REWARDS, unit_type_of
|
||||
from game.theater import ControlPoint, TheaterGroundObject
|
||||
from gen.defenses.armor_group_generator import \
|
||||
generate_armor_group_of_type_and_size
|
||||
from gen.sam.sam_group_generator import get_faction_possible_sams_generator
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.QBudgetBox import QBudgetBox
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.groundobject.QBuildingInfo import QBuildingInfo
|
||||
from theater import ControlPoint, TheaterGroundObject
|
||||
|
||||
|
||||
class QGroundObjectMenu(QDialog):
|
||||
|
||||
@ -10,15 +10,17 @@ from PySide2.QtWidgets import (
|
||||
from dcs.planes import PlaneType
|
||||
|
||||
from game import Game
|
||||
from game.theater import ControlPoint, OffMapSpawn
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.QFlightSizeSpinner import QFlightSizeSpinner
|
||||
from qt_ui.widgets.QLabeledWidget import QLabeledWidget
|
||||
from qt_ui.widgets.combos.QAircraftTypeSelector import QAircraftTypeSelector
|
||||
from qt_ui.widgets.combos.QArrivalAirfieldSelector import \
|
||||
QArrivalAirfieldSelector
|
||||
from qt_ui.widgets.combos.QFlightTypeComboBox import QFlightTypeComboBox
|
||||
from qt_ui.widgets.combos.QOriginAirfieldSelector import QOriginAirfieldSelector
|
||||
from theater import ControlPoint, OffMapSpawn
|
||||
|
||||
|
||||
class QFlightCreator(QDialog):
|
||||
@ -49,16 +51,30 @@ class QFlightCreator(QDialog):
|
||||
self.on_aircraft_changed)
|
||||
layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector))
|
||||
|
||||
self.airfield_selector = QOriginAirfieldSelector(
|
||||
self.departure = QOriginAirfieldSelector(
|
||||
self.game.aircraft_inventory,
|
||||
[cp for cp in game.theater.controlpoints if cp.captured],
|
||||
self.aircraft_selector.currentData()
|
||||
)
|
||||
self.airfield_selector.availability_changed.connect(self.update_max_size)
|
||||
layout.addLayout(QLabeledWidget("Airfield:", self.airfield_selector))
|
||||
self.departure.availability_changed.connect(self.update_max_size)
|
||||
layout.addLayout(QLabeledWidget("Departure:", self.departure))
|
||||
|
||||
self.arrival = QArrivalAirfieldSelector(
|
||||
[cp for cp in game.theater.controlpoints if cp.captured],
|
||||
self.aircraft_selector.currentData(),
|
||||
"Same as departure"
|
||||
)
|
||||
layout.addLayout(QLabeledWidget("Arrival:", self.arrival))
|
||||
|
||||
self.divert = QArrivalAirfieldSelector(
|
||||
[cp for cp in game.theater.controlpoints if cp.captured],
|
||||
self.aircraft_selector.currentData(),
|
||||
"None"
|
||||
)
|
||||
layout.addLayout(QLabeledWidget("Divert:", self.divert))
|
||||
|
||||
self.flight_size_spinner = QFlightSizeSpinner()
|
||||
self.update_max_size(self.airfield_selector.available)
|
||||
self.update_max_size(self.departure.available)
|
||||
layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner))
|
||||
|
||||
self.client_slots_spinner = QFlightSizeSpinner(
|
||||
@ -82,10 +98,16 @@ class QFlightCreator(QDialog):
|
||||
|
||||
def verify_form(self) -> Optional[str]:
|
||||
aircraft: PlaneType = self.aircraft_selector.currentData()
|
||||
origin: ControlPoint = self.airfield_selector.currentData()
|
||||
origin: ControlPoint = self.departure.currentData()
|
||||
arrival: ControlPoint = self.arrival.currentData()
|
||||
divert: ControlPoint = self.divert.currentData()
|
||||
size: int = self.flight_size_spinner.value()
|
||||
if not origin.captured:
|
||||
return f"{origin.name} is not owned by your coalition."
|
||||
if arrival is not None and not arrival.captured:
|
||||
return f"{arrival.name} is not owned by your coalition."
|
||||
if divert is not None and not divert.captured:
|
||||
return f"{divert.name} is not owned by your coalition."
|
||||
available = origin.base.aircraft.get(aircraft, 0)
|
||||
if not available:
|
||||
return f"{origin.name} has no {aircraft.id} available."
|
||||
@ -104,16 +126,22 @@ class QFlightCreator(QDialog):
|
||||
|
||||
task = self.task_selector.currentData()
|
||||
aircraft = self.aircraft_selector.currentData()
|
||||
origin = self.airfield_selector.currentData()
|
||||
origin = self.departure.currentData()
|
||||
arrival = self.arrival.currentData()
|
||||
divert = self.divert.currentData()
|
||||
size = self.flight_size_spinner.value()
|
||||
|
||||
if arrival is None:
|
||||
arrival = origin
|
||||
|
||||
if isinstance(origin, OffMapSpawn):
|
||||
start_type = "In Flight"
|
||||
elif self.game.settings.perf_ai_parking_start:
|
||||
start_type = "Cold"
|
||||
else:
|
||||
start_type = "Warm"
|
||||
flight = Flight(self.package, aircraft, size, origin, task, start_type)
|
||||
flight = Flight(self.package, aircraft, size, task, start_type, origin,
|
||||
arrival, divert)
|
||||
flight.client_count = self.client_slots_spinner.value()
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
@ -122,7 +150,9 @@ class QFlightCreator(QDialog):
|
||||
|
||||
def on_aircraft_changed(self, index: int) -> None:
|
||||
new_aircraft = self.aircraft_selector.itemData(index)
|
||||
self.airfield_selector.change_aircraft(new_aircraft)
|
||||
self.departure.change_aircraft(new_aircraft)
|
||||
self.arrival.change_aircraft(new_aircraft)
|
||||
self.divert.change_aircraft(new_aircraft)
|
||||
|
||||
def update_max_size(self, available: int) -> None:
|
||||
self.flight_size_spinner.setMaximum(min(available, 4))
|
||||
|
||||
@ -12,7 +12,7 @@ from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||
from PySide2.QtWidgets import QAbstractItemView, QListView
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from theater import ConflictTheater
|
||||
from game.theater import ConflictTheater
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
# For save game compatibility. Remove before 2.3.
|
||||
from game.theater import *
|
||||
@ -1,2 +0,0 @@
|
||||
# For save compat. Remove in 2.3.
|
||||
from game.theater.base import *
|
||||
@ -1,2 +0,0 @@
|
||||
# For save compat. Remove in 2.3.
|
||||
from game.theater.conflicttheater import *
|
||||
@ -1,2 +0,0 @@
|
||||
# For save compat. Remove in 2.3.
|
||||
from game.theater.controlpoint import *
|
||||
@ -1,3 +0,0 @@
|
||||
# For save compat. Remove in 2.3.
|
||||
from game.theater.frontline import *
|
||||
from game.theater.conflicttheater import FrontLine
|
||||
@ -1,2 +0,0 @@
|
||||
# For save compat. Remove in 2.3.
|
||||
from game.theater.theatergroundobject import *
|
||||
Loading…
x
Reference in New Issue
Block a user