mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Will now generate control point trigger zones and AI aircraft for the Pretense campaign.
This commit is contained in:
parent
975471e942
commit
31fb340ac8
@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Any, Dict, List, TYPE_CHECKING, Tuple
|
from typing import Any, Dict, List, TYPE_CHECKING, Tuple
|
||||||
@ -33,18 +34,17 @@ from game.theater.controlpoint import (
|
|||||||
Fob,
|
Fob,
|
||||||
)
|
)
|
||||||
from game.unitmap import UnitMap
|
from game.unitmap import UnitMap
|
||||||
from .aircraftpainter import AircraftPainter
|
from game.missiongenerator.aircraft.aircraftpainter import AircraftPainter
|
||||||
from .flightdata import FlightData
|
from game.missiongenerator.aircraft.flightdata import FlightData
|
||||||
from .flightgroupconfigurator import FlightGroupConfigurator
|
from game.missiongenerator.aircraft.flightgroupspawner import FlightGroupSpawner
|
||||||
from .flightgroupspawner import FlightGroupSpawner
|
from game.data.weapons import WeaponType
|
||||||
from ...data.weapons import WeaponType
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
from game.squadrons import Squadron
|
from game.squadrons import Squadron
|
||||||
|
|
||||||
|
|
||||||
class AircraftGenerator:
|
class PretenseAircraftGenerator:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
mission: Mission,
|
mission: Mission,
|
||||||
@ -101,6 +101,7 @@ class AircraftGenerator:
|
|||||||
def generate_flights(
|
def generate_flights(
|
||||||
self,
|
self,
|
||||||
country: Country,
|
country: Country,
|
||||||
|
cp: ControlPoint,
|
||||||
ato: AirTaskingOrder,
|
ato: AirTaskingOrder,
|
||||||
dynamic_runways: Dict[str, RunwayData],
|
dynamic_runways: Dict[str, RunwayData],
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -115,6 +116,61 @@ class AircraftGenerator:
|
|||||||
ato: The ATO to spawn aircraft for.
|
ato: The ATO to spawn aircraft for.
|
||||||
dynamic_runways: Runway data for carriers and FARPs.
|
dynamic_runways: Runway data for carriers and FARPs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
num_of_sead = 0
|
||||||
|
num_of_cas = 0
|
||||||
|
num_of_strike = 0
|
||||||
|
num_of_cap = 0
|
||||||
|
for squadron in cp.squadrons:
|
||||||
|
squadron.owned_aircraft += 1
|
||||||
|
squadron.untasked_aircraft += 1
|
||||||
|
package = Package(cp, squadron.flight_db, auto_asap=False)
|
||||||
|
mission_types = squadron.auto_assignable_mission_types
|
||||||
|
if (
|
||||||
|
FlightType.TRANSPORT in mission_types
|
||||||
|
or FlightType.AIR_ASSAULT in mission_types
|
||||||
|
):
|
||||||
|
flight_type = FlightType.TRANSPORT
|
||||||
|
elif (
|
||||||
|
FlightType.SEAD in mission_types
|
||||||
|
or FlightType.SEAD_SWEEP
|
||||||
|
or FlightType.SEAD_ESCORT in mission_types
|
||||||
|
) and num_of_sead < 2:
|
||||||
|
flight_type = FlightType.SEAD
|
||||||
|
num_of_sead += 1
|
||||||
|
elif FlightType.DEAD in mission_types and num_of_sead < 2:
|
||||||
|
flight_type = FlightType.DEAD
|
||||||
|
num_of_sead += 1
|
||||||
|
elif (
|
||||||
|
FlightType.CAS in mission_types or FlightType.BAI in mission_types
|
||||||
|
) and num_of_cas < 2:
|
||||||
|
flight_type = FlightType.CAS
|
||||||
|
num_of_cas += 1
|
||||||
|
elif (
|
||||||
|
FlightType.STRIKE in mission_types
|
||||||
|
or FlightType.OCA_RUNWAY in mission_types
|
||||||
|
or FlightType.OCA_AIRCRAFT in mission_types
|
||||||
|
) and num_of_strike < 2:
|
||||||
|
flight_type = FlightType.STRIKE
|
||||||
|
num_of_strike += 1
|
||||||
|
elif (
|
||||||
|
FlightType.BARCAP in mission_types
|
||||||
|
or FlightType.TARCAP in mission_types
|
||||||
|
or FlightType.ESCORT in mission_types
|
||||||
|
) and num_of_cap < 2:
|
||||||
|
flight_type = FlightType.BARCAP
|
||||||
|
num_of_cap += 1
|
||||||
|
else:
|
||||||
|
flight_type = random.choice(list(mission_types))
|
||||||
|
flight = Flight(
|
||||||
|
package, squadron, 1, flight_type, StartType.COLD, divert=cp
|
||||||
|
)
|
||||||
|
flight.state = WaitingForStart(
|
||||||
|
flight, self.game.settings, self.game.conditions.start_time
|
||||||
|
)
|
||||||
|
package.add_flight(flight)
|
||||||
|
ato.add_package(package)
|
||||||
|
|
||||||
self._reserve_frequencies_and_tacan(ato)
|
self._reserve_frequencies_and_tacan(ato)
|
||||||
|
|
||||||
for package in reversed(sorted(ato.packages, key=lambda x: x.time_over_target)):
|
for package in reversed(sorted(ato.packages, key=lambda x: x.time_over_target)):
|
||||||
@ -134,103 +190,6 @@ class AircraftGenerator:
|
|||||||
flight, country, dynamic_runways
|
flight, country, dynamic_runways
|
||||||
)
|
)
|
||||||
self.unit_map.add_aircraft(group, flight)
|
self.unit_map.add_aircraft(group, flight)
|
||||||
if (
|
|
||||||
package.primary_flight is not None
|
|
||||||
and package.primary_flight.flight_plan.is_formation(
|
|
||||||
package.primary_flight.flight_plan
|
|
||||||
)
|
|
||||||
):
|
|
||||||
splittrigger = TriggerOnce(Event.NoEvent, f"Split-{id(package)}")
|
|
||||||
splittrigger.add_condition(FlagIsTrue(flag=f"split-{id(package)}"))
|
|
||||||
splittrigger.add_condition(Or())
|
|
||||||
splittrigger.add_condition(FlagIsFalse(flag=f"split-{id(package)}"))
|
|
||||||
splittrigger.add_condition(GroupDead(package.primary_flight.group_id))
|
|
||||||
for flight in package.flights:
|
|
||||||
if flight.flight_type in [
|
|
||||||
FlightType.ESCORT,
|
|
||||||
FlightType.SEAD_ESCORT,
|
|
||||||
]:
|
|
||||||
splittrigger.add_action(AITaskPush(flight.group_id, 1))
|
|
||||||
if len(splittrigger.actions) > 0:
|
|
||||||
self.mission.triggerrules.triggers.append(splittrigger)
|
|
||||||
|
|
||||||
def spawn_unused_aircraft(
|
|
||||||
self, player_country: Country, enemy_country: Country
|
|
||||||
) -> None:
|
|
||||||
for control_point in self.game.theater.controlpoints:
|
|
||||||
if not (
|
|
||||||
isinstance(control_point, Airfield) or isinstance(control_point, Fob)
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if control_point.captured:
|
|
||||||
country = player_country
|
|
||||||
else:
|
|
||||||
country = enemy_country
|
|
||||||
|
|
||||||
for squadron in control_point.squadrons:
|
|
||||||
try:
|
|
||||||
self._spawn_unused_for(squadron, country)
|
|
||||||
except NoParkingSlotError:
|
|
||||||
# If we run out of parking, stop spawning aircraft at this base.
|
|
||||||
break
|
|
||||||
|
|
||||||
def _spawn_unused_for(self, squadron: Squadron, country: Country) -> None:
|
|
||||||
assert isinstance(squadron.location, Airfield) or isinstance(
|
|
||||||
squadron.location, Fob
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
squadron.coalition.player
|
|
||||||
and self.game.settings.perf_disable_untasked_blufor_aircraft
|
|
||||||
):
|
|
||||||
return
|
|
||||||
elif (
|
|
||||||
not squadron.coalition.player
|
|
||||||
and self.game.settings.perf_disable_untasked_opfor_aircraft
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
for _ in range(squadron.untasked_aircraft):
|
|
||||||
# Creating a flight even those this isn't a fragged mission lets us
|
|
||||||
# reuse the existing debriefing code.
|
|
||||||
# TODO: Special flight type?
|
|
||||||
flight = Flight(
|
|
||||||
Package(squadron.location, self.game.db.flights),
|
|
||||||
squadron,
|
|
||||||
1,
|
|
||||||
FlightType.BARCAP,
|
|
||||||
StartType.COLD,
|
|
||||||
divert=None,
|
|
||||||
claim_inv=False,
|
|
||||||
)
|
|
||||||
flight.state = Completed(flight, self.game.settings)
|
|
||||||
|
|
||||||
group = FlightGroupSpawner(
|
|
||||||
flight,
|
|
||||||
country,
|
|
||||||
self.mission,
|
|
||||||
self.helipads,
|
|
||||||
self.ground_spawns_roadbase,
|
|
||||||
self.ground_spawns,
|
|
||||||
self.mission_data,
|
|
||||||
).create_idle_aircraft()
|
|
||||||
if group:
|
|
||||||
if (
|
|
||||||
not squadron.coalition.player
|
|
||||||
and squadron.aircraft.flyable
|
|
||||||
and (
|
|
||||||
self.game.settings.enable_squadron_pilot_limits
|
|
||||||
or squadron.number_of_available_pilots > 0
|
|
||||||
)
|
|
||||||
and self.game.settings.untasked_opfor_client_slots
|
|
||||||
):
|
|
||||||
flight.state = WaitingForStart(
|
|
||||||
flight, self.game.settings, self.game.conditions.start_time
|
|
||||||
)
|
|
||||||
group.uncontrolled = False
|
|
||||||
group.units[0].skill = Skill.Client
|
|
||||||
AircraftPainter(flight, group).apply_livery()
|
|
||||||
self.unit_map.add_aircraft(group, flight)
|
|
||||||
|
|
||||||
def create_and_configure_flight(
|
def create_and_configure_flight(
|
||||||
self, flight: Flight, country: Country, dynamic_runways: Dict[str, RunwayData]
|
self, flight: Flight, country: Country, dynamic_runways: Dict[str, RunwayData]
|
||||||
@ -245,21 +204,21 @@ class AircraftGenerator:
|
|||||||
self.ground_spawns,
|
self.ground_spawns,
|
||||||
self.mission_data,
|
self.mission_data,
|
||||||
).create_flight_group()
|
).create_flight_group()
|
||||||
self.flights.append(
|
# self.flights.append(
|
||||||
FlightGroupConfigurator(
|
# FlightGroupConfigurator(
|
||||||
flight,
|
# flight,
|
||||||
group,
|
# group,
|
||||||
self.game,
|
# self.game,
|
||||||
self.mission,
|
# self.mission,
|
||||||
self.time,
|
# self.time,
|
||||||
self.radio_registry,
|
# self.radio_registry,
|
||||||
self.tacan_registy,
|
# self.tacan_registy,
|
||||||
self.laser_code_registry,
|
# self.laser_code_registry,
|
||||||
self.mission_data,
|
# self.mission_data,
|
||||||
dynamic_runways,
|
# dynamic_runways,
|
||||||
self.use_client,
|
# self.use_client,
|
||||||
).configure()
|
# ).configure()
|
||||||
)
|
# )
|
||||||
|
|
||||||
if self.ewrj:
|
if self.ewrj:
|
||||||
self._track_ewrj_flight(flight, group)
|
self._track_ewrj_flight(flight, group)
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from pathlib import Path
|
|||||||
from typing import TYPE_CHECKING, cast
|
from typing import TYPE_CHECKING, cast
|
||||||
|
|
||||||
import dcs.lua
|
import dcs.lua
|
||||||
|
from dataclasses import field
|
||||||
from dcs import Mission, Point
|
from dcs import Mission, Point
|
||||||
from dcs.coalition import Coalition
|
from dcs.coalition import Coalition
|
||||||
from dcs.countries import country_dict
|
from dcs.countries import country_dict
|
||||||
@ -13,38 +14,40 @@ from dcs.task import OptReactOnThreat
|
|||||||
|
|
||||||
from game.atcdata import AtcData
|
from game.atcdata import AtcData
|
||||||
from game.dcs.beacons import Beacons
|
from game.dcs.beacons import Beacons
|
||||||
from game.dcs.helpers import unit_type_from_name
|
|
||||||
from game.missiongenerator.aircraft.aircraftgenerator import (
|
|
||||||
AircraftGenerator,
|
|
||||||
)
|
|
||||||
from game.naming import namegen
|
from game.naming import namegen
|
||||||
from game.radio.radios import RadioFrequency, RadioRegistry, MHz
|
from game.radio.radios import RadioFrequency, RadioRegistry, MHz
|
||||||
from game.radio.tacan import TacanRegistry
|
from game.radio.tacan import TacanRegistry
|
||||||
from game.theater import Airfield
|
from game.theater import Airfield
|
||||||
from game.theater.bullseye import Bullseye
|
from game.theater.bullseye import Bullseye
|
||||||
from game.unitmap import UnitMap
|
from game.unitmap import UnitMap
|
||||||
from .briefinggenerator import BriefingGenerator, MissionInfoGenerator
|
from game.pretense.pretenseaircraftgenerator import PretenseAircraftGenerator
|
||||||
from .cargoshipgenerator import CargoShipGenerator
|
from game.missiongenerator.briefinggenerator import (
|
||||||
from .convoygenerator import ConvoyGenerator
|
BriefingGenerator,
|
||||||
from .drawingsgenerator import DrawingsGenerator
|
MissionInfoGenerator,
|
||||||
from .environmentgenerator import EnvironmentGenerator
|
)
|
||||||
from .flotgenerator import FlotGenerator
|
from game.missiongenerator.convoygenerator import ConvoyGenerator
|
||||||
from .forcedoptionsgenerator import ForcedOptionsGenerator
|
from game.missiongenerator.environmentgenerator import EnvironmentGenerator
|
||||||
from .frontlineconflictdescription import FrontLineConflictDescription
|
from game.missiongenerator.flotgenerator import FlotGenerator
|
||||||
from .kneeboard import KneeboardGenerator
|
from game.missiongenerator.forcedoptionsgenerator import ForcedOptionsGenerator
|
||||||
from .lasercoderegistry import LaserCodeRegistry
|
from game.missiongenerator.frontlineconflictdescription import (
|
||||||
from .luagenerator import LuaGenerator
|
FrontLineConflictDescription,
|
||||||
from .missiondata import MissionData
|
)
|
||||||
from .tgogenerator import TgoGenerator
|
from game.missiongenerator.kneeboard import KneeboardGenerator
|
||||||
from .triggergenerator import TriggerGenerator
|
from game.missiongenerator.lasercoderegistry import LaserCodeRegistry
|
||||||
from .visualsgenerator import VisualsGenerator
|
from game.missiongenerator.luagenerator import LuaGenerator
|
||||||
|
from game.missiongenerator.missiondata import MissionData
|
||||||
|
from game.missiongenerator.tgogenerator import TgoGenerator
|
||||||
|
from .pretensetriggergenerator import PretenseTriggerGenerator
|
||||||
|
from game.missiongenerator.visualsgenerator import VisualsGenerator
|
||||||
|
from ..ato import Flight
|
||||||
from ..radio.TacanContainer import TacanContainer
|
from ..radio.TacanContainer import TacanContainer
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
|
|
||||||
|
|
||||||
class MissionGenerator:
|
class PretenseMissionGenerator:
|
||||||
def __init__(self, game: Game, time: datetime) -> None:
|
def __init__(self, game: Game, time: datetime) -> None:
|
||||||
self.game = game
|
self.game = game
|
||||||
self.time = time
|
self.time = time
|
||||||
@ -94,20 +97,16 @@ class MissionGenerator:
|
|||||||
tgo_generator.generate()
|
tgo_generator.generate()
|
||||||
|
|
||||||
ConvoyGenerator(self.mission, self.game, self.unit_map).generate()
|
ConvoyGenerator(self.mission, self.game, self.unit_map).generate()
|
||||||
CargoShipGenerator(self.mission, self.game, self.unit_map).generate()
|
|
||||||
|
|
||||||
self.generate_destroyed_units()
|
|
||||||
|
|
||||||
# Generate ground conflicts first so the JTACs get the first laser code (1688)
|
# Generate ground conflicts first so the JTACs get the first laser code (1688)
|
||||||
# rather than the first player flight with a TGP.
|
# rather than the first player flight with a TGP.
|
||||||
self.generate_ground_conflicts()
|
self.generate_ground_conflicts()
|
||||||
self.generate_air_units(tgo_generator)
|
self.generate_air_units(tgo_generator)
|
||||||
|
|
||||||
TriggerGenerator(self.mission, self.game).generate()
|
PretenseTriggerGenerator(self.mission, self.game).generate()
|
||||||
ForcedOptionsGenerator(self.mission, self.game).generate()
|
ForcedOptionsGenerator(self.mission, self.game).generate()
|
||||||
VisualsGenerator(self.mission, self.game).generate()
|
VisualsGenerator(self.mission, self.game).generate()
|
||||||
LuaGenerator(self.game, self.mission, self.mission_data).generate()
|
LuaGenerator(self.game, self.mission, self.mission_data).generate()
|
||||||
DrawingsGenerator(self.mission, self.game).generate()
|
|
||||||
|
|
||||||
self.setup_combined_arms()
|
self.setup_combined_arms()
|
||||||
|
|
||||||
@ -119,22 +118,6 @@ class MissionGenerator:
|
|||||||
|
|
||||||
return self.unit_map
|
return self.unit_map
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _configure_ewrj(gen: AircraftGenerator) -> None:
|
|
||||||
for groups in gen.ewrj_package_dict.values():
|
|
||||||
optrot = groups[0].points[0].tasks[0]
|
|
||||||
assert isinstance(optrot, OptReactOnThreat)
|
|
||||||
if (
|
|
||||||
len(groups) == 1
|
|
||||||
and optrot.value != OptReactOnThreat.Values.PassiveDefense
|
|
||||||
):
|
|
||||||
# primary flight with no EWR-Jamming capability
|
|
||||||
continue
|
|
||||||
for group in groups:
|
|
||||||
group.points[0].tasks[0] = OptReactOnThreat(
|
|
||||||
OptReactOnThreat.Values.PassiveDefense
|
|
||||||
)
|
|
||||||
|
|
||||||
def setup_mission_coalitions(self) -> None:
|
def setup_mission_coalitions(self) -> None:
|
||||||
self.mission.coalition["blue"] = Coalition(
|
self.mission.coalition["blue"] = Coalition(
|
||||||
"blue", bullseye=self.game.blue.bullseye.to_pydcs()
|
"blue", bullseye=self.game.blue.bullseye.to_pydcs()
|
||||||
@ -232,7 +215,7 @@ class MissionGenerator:
|
|||||||
"""Generate the air units for the Operation"""
|
"""Generate the air units for the Operation"""
|
||||||
|
|
||||||
# Generate Aircraft Activity on the map
|
# Generate Aircraft Activity on the map
|
||||||
aircraft_generator = AircraftGenerator(
|
aircraft_generator = PretenseAircraftGenerator(
|
||||||
self.mission,
|
self.mission,
|
||||||
self.game.settings,
|
self.game.settings,
|
||||||
self.game,
|
self.game,
|
||||||
@ -247,22 +230,25 @@ class MissionGenerator:
|
|||||||
ground_spawns=tgo_generator.ground_spawns,
|
ground_spawns=tgo_generator.ground_spawns,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Clear parking slots and ATOs
|
||||||
aircraft_generator.clear_parking_slots()
|
aircraft_generator.clear_parking_slots()
|
||||||
|
self.game.blue.ato.clear()
|
||||||
|
self.game.red.ato.clear()
|
||||||
|
|
||||||
aircraft_generator.generate_flights(
|
for cp in self.game.theater.controlpoints:
|
||||||
self.p_country,
|
if cp.captured:
|
||||||
self.game.blue.ato,
|
ato = self.game.blue.ato
|
||||||
tgo_generator.runways,
|
cp_country = self.p_country
|
||||||
)
|
else:
|
||||||
aircraft_generator.generate_flights(
|
ato = self.game.red.ato
|
||||||
self.e_country,
|
cp_country = self.e_country
|
||||||
self.game.red.ato,
|
print(f"Generating flights for {cp_country.name} at {cp}")
|
||||||
tgo_generator.runways,
|
aircraft_generator.generate_flights(
|
||||||
)
|
cp_country,
|
||||||
aircraft_generator.spawn_unused_aircraft(
|
cp,
|
||||||
self.p_country,
|
ato,
|
||||||
self.e_country,
|
tgo_generator.runways,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.mission_data.flights = aircraft_generator.flights
|
self.mission_data.flights = aircraft_generator.flights
|
||||||
|
|
||||||
@ -274,35 +260,6 @@ class MissionGenerator:
|
|||||||
if self.game.settings.plugins.get("ewrj"):
|
if self.game.settings.plugins.get("ewrj"):
|
||||||
self._configure_ewrj(aircraft_generator)
|
self._configure_ewrj(aircraft_generator)
|
||||||
|
|
||||||
def generate_destroyed_units(self) -> None:
|
|
||||||
"""Add destroyed units to the Mission"""
|
|
||||||
if not self.game.settings.perf_destroyed_units:
|
|
||||||
return
|
|
||||||
|
|
||||||
for d in self.game.get_destroyed_units():
|
|
||||||
try:
|
|
||||||
type_name = d["type"]
|
|
||||||
if not isinstance(type_name, str):
|
|
||||||
raise TypeError(
|
|
||||||
"Expected the type of the destroyed static to be a string"
|
|
||||||
)
|
|
||||||
utype = unit_type_from_name(type_name)
|
|
||||||
except KeyError:
|
|
||||||
logging.warning(f"Destroyed unit has no type: {d}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
pos = Point(cast(float, d["x"]), cast(float, d["z"]), self.mission.terrain)
|
|
||||||
if utype is not None and not self.game.position_culled(pos):
|
|
||||||
self.mission.static_group(
|
|
||||||
country=self.p_country,
|
|
||||||
name="",
|
|
||||||
_type=utype,
|
|
||||||
hidden=True,
|
|
||||||
position=pos,
|
|
||||||
heading=d["orientation"],
|
|
||||||
dead=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
def notify_info_generators(
|
def notify_info_generators(
|
||||||
self,
|
self,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class Silence(Option):
|
|||||||
Key = 7
|
Key = 7
|
||||||
|
|
||||||
|
|
||||||
class TriggerGenerator:
|
class PretenseTriggerGenerator:
|
||||||
capture_zone_types = (Fob, Airfield)
|
capture_zone_types = (Fob, Airfield)
|
||||||
capture_zone_flag = 600
|
capture_zone_flag = 600
|
||||||
|
|
||||||
@ -146,38 +146,7 @@ class TriggerGenerator:
|
|||||||
v += 1
|
v += 1
|
||||||
self.mission.triggerrules.triggers.append(mark_trigger)
|
self.mission.triggerrules.triggers.append(mark_trigger)
|
||||||
|
|
||||||
def _generate_clear_statics_trigger(self, scenery_clear_zones: List[Point]) -> None:
|
def _generate_pretense_zone_triggers(
|
||||||
for zone_center in scenery_clear_zones:
|
|
||||||
trigger_zone = self.mission.triggers.add_triggerzone(
|
|
||||||
zone_center,
|
|
||||||
radius=TRIGGER_RADIUS_CLEAR_SCENERY,
|
|
||||||
hidden=False,
|
|
||||||
name="CLEAR",
|
|
||||||
)
|
|
||||||
clear_trigger = TriggerCondition(Event.NoEvent, "Clear Trigger")
|
|
||||||
clear_flag = self.get_capture_zone_flag()
|
|
||||||
clear_trigger.add_condition(TimeSinceFlag(clear_flag, 30))
|
|
||||||
clear_trigger.add_action(ClearFlag(clear_flag))
|
|
||||||
clear_trigger.add_action(SetFlag(clear_flag))
|
|
||||||
clear_trigger.add_action(
|
|
||||||
RemoveSceneObjects(
|
|
||||||
objects_mask=RemoveSceneObjectsMask.OBJECTS_ONLY,
|
|
||||||
zone=trigger_zone.id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
clear_trigger.add_action(
|
|
||||||
SceneryDestructionZone(destruction_level=100, zone=trigger_zone.id)
|
|
||||||
)
|
|
||||||
self.mission.triggerrules.triggers.append(clear_trigger)
|
|
||||||
|
|
||||||
enable_clear_trigger = TriggerOnce(Event.NoEvent, "Enable Clear Trigger")
|
|
||||||
enable_clear_trigger.add_condition(TimeAfter(30))
|
|
||||||
enable_clear_trigger.add_action(ClearFlag(clear_flag))
|
|
||||||
enable_clear_trigger.add_action(SetFlag(clear_flag))
|
|
||||||
# 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
|
self, player_coalition: str, enemy_coalition: str
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Creates a pair of triggers for each control point of `cls.capture_zone_types`.
|
"""Creates a pair of triggers for each control point of `cls.capture_zone_types`.
|
||||||
@ -185,62 +154,16 @@ class TriggerGenerator:
|
|||||||
Directly appends to the global `base_capture_events` var declared by `dcs_libaration.lua`
|
Directly appends to the global `base_capture_events` var declared by `dcs_libaration.lua`
|
||||||
"""
|
"""
|
||||||
for cp in self.game.theater.controlpoints:
|
for cp in self.game.theater.controlpoints:
|
||||||
if isinstance(cp, self.capture_zone_types) and not cp.is_carrier:
|
if isinstance(cp, self.capture_zone_types) and not cp.is_fleet:
|
||||||
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
|
|
||||||
|
|
||||||
|
zone_color = {1: 0.0, 2: 0.0, 3: 0.0, 4: 0.149}
|
||||||
trigger_zone = self.mission.triggers.add_triggerzone(
|
trigger_zone = self.mission.triggers.add_triggerzone(
|
||||||
cp.position,
|
cp.position,
|
||||||
radius=TRIGGER_RADIUS_CAPTURE,
|
radius=TRIGGER_RADIUS_CAPTURE,
|
||||||
hidden=False,
|
hidden=False,
|
||||||
name="CAPTURE",
|
name=cp.name,
|
||||||
|
color=zone_color,
|
||||||
)
|
)
|
||||||
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_trigger.add_condition(
|
|
||||||
PartOfCoalitionInZone(
|
|
||||||
attacking_coalition, trigger_zone.id, unit_type="GROUND"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
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)
|
|
||||||
|
|
||||||
recapture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger")
|
|
||||||
recapture_trigger.add_condition(
|
|
||||||
AllOfCoalitionOutsideZone(
|
|
||||||
attacking_coalition, trigger_zone.id, unit_type="GROUND"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
recapture_trigger.add_condition(
|
|
||||||
PartOfCoalitionInZone(
|
|
||||||
defending_coalition, trigger_zone.id, unit_type="GROUND"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
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:
|
def generate(self) -> None:
|
||||||
player_coalition = "blue"
|
player_coalition = "blue"
|
||||||
@ -249,13 +172,7 @@ class TriggerGenerator:
|
|||||||
self._set_skill(player_coalition, enemy_coalition)
|
self._set_skill(player_coalition, enemy_coalition)
|
||||||
self._set_allegiances(player_coalition, enemy_coalition)
|
self._set_allegiances(player_coalition, enemy_coalition)
|
||||||
self._gen_markers()
|
self._gen_markers()
|
||||||
self._generate_capture_triggers(player_coalition, enemy_coalition)
|
self._generate_pretense_zone_triggers(player_coalition, enemy_coalition)
|
||||||
if self.game.settings.ground_start_scenery_remove_triggers:
|
|
||||||
try:
|
|
||||||
self._generate_clear_statics_trigger(self.game.scenery_clear_zones)
|
|
||||||
self.game.scenery_clear_zones.clear()
|
|
||||||
except AttributeError:
|
|
||||||
logging.info(f"Unable to create Clear Statics triggers")
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_capture_zone_flag(cls) -> int:
|
def get_capture_zone_flag(cls) -> int:
|
||||||
|
|||||||
@ -32,6 +32,7 @@ def load_icons():
|
|||||||
"./resources/ui/misc/" + get_theme_icons() + "/github.png"
|
"./resources/ui/misc/" + get_theme_icons() + "/github.png"
|
||||||
)
|
)
|
||||||
ICONS["Ukraine"] = QPixmap("./resources/ui/misc/ukraine.png")
|
ICONS["Ukraine"] = QPixmap("./resources/ui/misc/ukraine.png")
|
||||||
|
ICONS["Pretense"] = QPixmap("./resources/ui/misc/pretense.png")
|
||||||
|
|
||||||
ICONS["Control Points"] = QPixmap(
|
ICONS["Control Points"] = QPixmap(
|
||||||
"./resources/ui/misc/" + get_theme_icons() + "/circle.png"
|
"./resources/ui/misc/" + get_theme_icons() + "/circle.png"
|
||||||
|
|||||||
@ -21,6 +21,7 @@ from game import Game, VERSION, persistency, Migrator
|
|||||||
from game.debriefing import Debriefing
|
from game.debriefing import Debriefing
|
||||||
from game.game import TurnState
|
from game.game import TurnState
|
||||||
from game.layout import LAYOUTS
|
from game.layout import LAYOUTS
|
||||||
|
from game.pretense.pretensemissiongenerator import PretenseMissionGenerator
|
||||||
from game.server import EventStream, GameContext
|
from game.server import EventStream, GameContext
|
||||||
from game.server.dependencies import QtCallbacks, QtContext
|
from game.server.dependencies import QtCallbacks, QtContext
|
||||||
from game.theater import ControlPoint, MissionTarget, TheaterGroundObject
|
from game.theater import ControlPoint, MissionTarget, TheaterGroundObject
|
||||||
@ -41,6 +42,7 @@ from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu
|
|||||||
from qt_ui.windows.infos.QInfoPanel import QInfoPanel
|
from qt_ui.windows.infos.QInfoPanel import QInfoPanel
|
||||||
from qt_ui.windows.logs.QLogsWindow import QLogsWindow
|
from qt_ui.windows.logs.QLogsWindow import QLogsWindow
|
||||||
from qt_ui.windows.newgame.QNewGameWizard import NewGameWizard
|
from qt_ui.windows.newgame.QNewGameWizard import NewGameWizard
|
||||||
|
from qt_ui.windows.newgame.QNewPretenseWizard import NewPretenseWizard
|
||||||
from qt_ui.windows.notes.QNotesWindow import QNotesWindow
|
from qt_ui.windows.notes.QNotesWindow import QNotesWindow
|
||||||
from qt_ui.windows.preferences.QLiberationPreferencesWindow import (
|
from qt_ui.windows.preferences.QLiberationPreferencesWindow import (
|
||||||
QLiberationPreferencesWindow,
|
QLiberationPreferencesWindow,
|
||||||
@ -193,6 +195,10 @@ class QLiberationWindow(QMainWindow):
|
|||||||
lambda: webbrowser.open_new_tab("https://shdwp.github.io/ukraine/")
|
lambda: webbrowser.open_new_tab("https://shdwp.github.io/ukraine/")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.newPretenseAction = QAction("&New Pretense Campaign", self)
|
||||||
|
self.newPretenseAction.setIcon(QIcon(CONST.ICONS["Pretense"]))
|
||||||
|
self.newPretenseAction.triggered.connect(self.newPretenseCampaign)
|
||||||
|
|
||||||
self.openLogsAction = QAction("Show &logs", self)
|
self.openLogsAction = QAction("Show &logs", self)
|
||||||
self.openLogsAction.triggered.connect(self.showLogsDialog)
|
self.openLogsAction.triggered.connect(self.showLogsDialog)
|
||||||
|
|
||||||
@ -234,6 +240,7 @@ class QLiberationWindow(QMainWindow):
|
|||||||
self.links_bar.addAction(self.openDiscordAction)
|
self.links_bar.addAction(self.openDiscordAction)
|
||||||
self.links_bar.addAction(self.openGithubAction)
|
self.links_bar.addAction(self.openGithubAction)
|
||||||
self.links_bar.addAction(self.ukraineAction)
|
self.links_bar.addAction(self.ukraineAction)
|
||||||
|
self.links_bar.addAction(self.newPretenseAction)
|
||||||
|
|
||||||
self.actions_bar = self.addToolBar("Actions")
|
self.actions_bar = self.addToolBar("Actions")
|
||||||
self.actions_bar.addAction(self.openSettingsAction)
|
self.actions_bar.addAction(self.openSettingsAction)
|
||||||
@ -303,6 +310,15 @@ class QLiberationWindow(QMainWindow):
|
|||||||
wizard.show()
|
wizard.show()
|
||||||
wizard.accepted.connect(lambda: self.onGameGenerated(wizard.generatedGame))
|
wizard.accepted.connect(lambda: self.onGameGenerated(wizard.generatedGame))
|
||||||
|
|
||||||
|
def newPretenseCampaign(self):
|
||||||
|
output = persistency.mission_path_for("pretense_campaign.miz")
|
||||||
|
PretenseMissionGenerator(
|
||||||
|
self.game, self.game.conditions.start_time
|
||||||
|
).generate_miz(output)
|
||||||
|
title = "Pretense campaign generated"
|
||||||
|
msg = f"A Pretense campaign mission has been successfully generated in {output}"
|
||||||
|
QMessageBox.information(QApplication.focusWidget(), title, msg, QMessageBox.Ok)
|
||||||
|
|
||||||
def openFile(self):
|
def openFile(self):
|
||||||
if self.game is not None and self.game.savepath:
|
if self.game is not None and self.game.savepath:
|
||||||
save_dir = self.game.savepath
|
save_dir = self.game.savepath
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user