Will now generate control point trigger zones and AI aircraft for the Pretense campaign.

This commit is contained in:
MetalStormGhost 2023-09-09 16:04:44 +03:00
parent 975471e942
commit 31fb340ac8
5 changed files with 143 additions and 293 deletions

View File

@ -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)

View File

@ -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:

View File

@ -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:

View File

@ -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"

View File

@ -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