Compare commits

...

9 Commits

Author SHA1 Message Date
Dan Albert
8c1f3e8116 Use python, not py.
py is a shortcut that launches the *latest* version of Python on the
machine. https://stackoverflow.com/a/50896577/632035

The build machines were updated to include python 3.9, so we were
doing everything with 3.9 instead of 3.8. pyproj doesn't have a binary
wheel for 3.9 on pypi yet, so we were falling back to building it from
source, which we aren't able to do, breaking the build.
2020-10-28 00:06:56 -07:00
Dan Albert
df00059d3f Fix initial frequencies for support aircraft.
Vaicom (a mod that adds voice control for the communications menus)
isn't able to follow the waypoint frequency change that normally sets
the radio channel for the AWACS/tanker flights. Set the group's
frequency correctly to start so it works.

(cherry picked from commit 4abf806837)
2020-10-17 15:56:48 -07:00
Khopa
2a3bf9821b Fixed EPLRS cherry pick merge. 2020-10-05 19:33:48 +02:00
Khopa
819d775282 EPLRS for 2.1.5 2020-10-05 19:30:43 +02:00
Khopa
efbc6fe3ae Enable EPLRS for ground units that can use it. 2020-10-05 19:29:34 +02:00
Khopa
262ba6c113 Chery picked another fix for this release, so updated changelog 2020-10-05 19:28:55 +02:00
Khopa
c41ecb6735 Fix aircrafts landing point 2020-10-05 19:27:03 +02:00
Khopa
f5c32c6b98 Version 2.1.5 2020-10-05 19:26:07 +02:00
Dan Albert
a1886e37f8 Fix save issues after aborting mission.
When the mission is aborted the pending mission is still in the event
list, which is part of the game option. That event has a reference to
the operation, which in turn contains all the mission generator
objects. Two of these objects are the radio/TACAN allocators, which
use a generator to track the next free channel. Generators cannot be
picked, so because these are transitively part of the game object the
game cannot be saved.

Aside from the briefing generator, none of those objects are
actually needed outside the generation function itself, so just make
them locals instead.

This probably needs a larger refactor at some point. It doesn't look
like we need so many calls into the operation type (it has an
initialize, a prepare, and a generate, and it doesn't seem to need
anything but the last one). The only reason breifinggen needs to
remain a part of the class is because the briefing title and
description are filled in from the derived class, where title and
description should probably be overridden properties instead. I'm also
not sure if we need to make the event list a part of game at all, and
also don't think that the mission needs to be one of these events.
2020-10-05 19:20:57 +02:00
11 changed files with 101 additions and 73 deletions

View File

@@ -18,12 +18,12 @@ jobs:
- name: Install environment - name: Install environment
run: | run: |
py -m venv ./venv python -m venv ./venv
- name: Install dependencies - name: Install dependencies
run: | run: |
./venv/scripts/activate ./venv/scripts/activate
pip install -r requirements.txt python -m pip install -r requirements.txt
# For some reason the shiboken2.abi3.dll is not found properly, so I copy it instead # For some reason the shiboken2.abi3.dll is not found properly, so I copy it instead
Copy-Item .\venv\Lib\site-packages\shiboken2\shiboken2.abi3.dll .\venv\Lib\site-packages\PySide2\ -Force Copy-Item .\venv\Lib\site-packages\shiboken2\shiboken2.abi3.dll .\venv\Lib\site-packages\PySide2\ -Force

View File

@@ -20,12 +20,12 @@ jobs:
- name: Install environment - name: Install environment
run: | run: |
py -m venv ./venv python -m venv ./venv
- name: Install dependencies - name: Install dependencies
run: | run: |
./venv/scripts/activate ./venv/scripts/activate
pip install -r requirements.txt python -m pip install -r requirements.txt
# For some reason the shiboken2.abi3.dll is not found properly, so I copy it instead # For some reason the shiboken2.abi3.dll is not found properly, so I copy it instead
Copy-Item .\venv\Lib\site-packages\shiboken2\shiboken2.abi3.dll .\venv\Lib\site-packages\PySide2\ -Force Copy-Item .\venv\Lib\site-packages\shiboken2\shiboken2.abi3.dll .\venv\Lib\site-packages\PySide2\ -Force

View File

@@ -1,3 +1,12 @@
# 2.1.5
## Features/Improvements :
* **[Units/Factions]** Enabled EPLRS for ground units that supports it (so they appear on A-10C II TAD and Helmet)
## Fixes :
* **[UI]** Fixed an issue that prevent saving after aborting a mission
* **[Mission Generator]** Fixed aircraft landing point type being wrong
# 2.1.4 # 2.1.4
## Fixes : ## Fixes :

View File

@@ -68,26 +68,8 @@ class Operation:
def initialize(self, mission: Mission, conflict: Conflict): def initialize(self, mission: Mission, conflict: Conflict):
self.current_mission = mission self.current_mission = mission
self.conflict = conflict self.conflict = conflict
self.radio_registry = RadioRegistry() self.briefinggen = BriefingGenerator(self.current_mission,
self.tacan_registry = TacanRegistry() self.conflict, self.game)
self.airgen = AircraftConflictGenerator(
mission, conflict, self.game.settings, self.game,
self.radio_registry)
self.airsupportgen = AirSupportConflictGenerator(
mission, conflict, self.game, self.radio_registry,
self.tacan_registry)
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
self.visualgen = VisualGenerator(mission, conflict, self.game)
self.envgen = EnviromentGenerator(mission, conflict, self.game)
self.forcedoptionsgen = ForcedOptionsGenerator(mission, conflict, self.game)
self.groundobjectgen = GroundObjectsGenerator(
mission,
conflict,
self.game,
self.radio_registry,
self.tacan_registry
)
self.briefinggen = BriefingGenerator(mission, conflict, self.game)
def prepare(self, terrain: Terrain, is_quick: bool): def prepare(self, terrain: Terrain, is_quick: bool):
with open("resources/default_options.lua", "r") as f: with open("resources/default_options.lua", "r") as f:
@@ -127,6 +109,9 @@ class Operation:
self.defenders_starting_position = self.to_cp.at self.defenders_starting_position = self.to_cp.at
def generate(self): def generate(self):
radio_registry = RadioRegistry()
tacan_registry = TacanRegistry()
# Dedup beacon/radio frequencies, since some maps have some frequencies # Dedup beacon/radio frequencies, since some maps have some frequencies
# used multiple times. # used multiple times.
beacons = load_beacons_for_terrain(self.game.theater.terrain.name) beacons = load_beacons_for_terrain(self.game.theater.terrain.name)
@@ -138,7 +123,7 @@ class Operation:
logging.error( logging.error(
f"TACAN beacon has no channel: {beacon.callsign}") f"TACAN beacon has no channel: {beacon.callsign}")
else: else:
self.tacan_registry.reserve(beacon.tacan_channel) tacan_registry.reserve(beacon.tacan_channel)
for airfield, data in AIRFIELD_DATA.items(): for airfield, data in AIRFIELD_DATA.items():
if data.theater == self.game.theater.terrain.name: if data.theater == self.game.theater.terrain.name:
@@ -150,16 +135,26 @@ class Operation:
# beacon list. # beacon list.
for frequency in unique_map_frequencies: for frequency in unique_map_frequencies:
self.radio_registry.reserve(frequency) radio_registry.reserve(frequency)
# Generate meteo # Generate meteo
envgen = EnviromentGenerator(self.current_mission, self.conflict,
self.game)
if self.environment_settings is None: if self.environment_settings is None:
self.environment_settings = self.envgen.generate() self.environment_settings = envgen.generate()
else: else:
self.envgen.load(self.environment_settings) envgen.load(self.environment_settings)
# Generate ground object first # Generate ground object first
self.groundobjectgen.generate()
groundobjectgen = GroundObjectsGenerator(
self.current_mission,
self.conflict,
self.game,
radio_registry,
tacan_registry
)
groundobjectgen.generate()
# Generate destroyed units # Generate destroyed units
for d in self.game.get_destroyed_units(): for d in self.game.get_destroyed_units():
@@ -180,11 +175,16 @@ class Operation:
dead=True, dead=True,
) )
# Air Support (Tanker & Awacs) # Air Support (Tanker & Awacs)
self.airsupportgen.generate(self.is_awacs_enabled) airsupportgen = AirSupportConflictGenerator(
self.current_mission, self.conflict, self.game, radio_registry,
tacan_registry)
airsupportgen.generate(self.is_awacs_enabled)
# Generate Activity on the map # Generate Activity on the map
airgen = AircraftConflictGenerator(
self.current_mission, self.conflict, self.game.settings, self.game,
radio_registry)
for cp in self.game.theater.controlpoints: for cp in self.game.theater.controlpoints:
side = cp.captured side = cp.captured
if side: if side:
@@ -192,11 +192,11 @@ class Operation:
else: else:
country = self.current_mission.country(self.game.enemy_country) country = self.current_mission.country(self.game.enemy_country)
if cp.id in self.game.planners.keys(): if cp.id in self.game.planners.keys():
self.airgen.generate_flights( airgen.generate_flights(
cp, cp,
country, country,
self.game.planners[cp.id], self.game.planners[cp.id],
self.groundobjectgen.runways groundobjectgen.runways
) )
# Generate ground units on frontline everywhere # Generate ground units on frontline everywhere
@@ -221,18 +221,20 @@ class Operation:
self.current_mission.groundControl.red_tactical_commander = self.ca_slots self.current_mission.groundControl.red_tactical_commander = self.ca_slots
# Triggers # Triggers
if self.game.is_player_attack(self.conflict.attackers_country): triggersgen = TriggersGenerator(self.current_mission, self.conflict,
cp = self.conflict.from_cp self.game)
else: triggersgen.generate()
cp = self.conflict.to_cp
self.triggersgen.generate()
# Options # Options
self.forcedoptionsgen.generate() forcedoptionsgen = ForcedOptionsGenerator(self.current_mission,
self.conflict, self.game)
forcedoptionsgen.generate()
# Generate Visuals Smoke Effects # Generate Visuals Smoke Effects
visualgen = VisualGenerator(self.current_mission, self.conflict,
self.game)
if self.game.settings.perf_smoke_gen: if self.game.settings.perf_smoke_gen:
self.visualgen.generate() visualgen.generate()
# Inject Plugins Lua Scripts # Inject Plugins Lua Scripts
listOfPluginsScripts = [] listOfPluginsScripts = []
@@ -327,19 +329,20 @@ class Operation:
trigger.add_action(DoScript(String(lua))) trigger.add_action(DoScript(String(lua)))
self.current_mission.triggerrules.triggers.append(trigger) self.current_mission.triggerrules.triggers.append(trigger)
self.assign_channels_to_flights() self.assign_channels_to_flights(airgen.flights,
airsupportgen.air_support)
kneeboard_generator = KneeboardGenerator(self.current_mission) kneeboard_generator = KneeboardGenerator(self.current_mission)
for dynamic_runway in self.groundobjectgen.runways.values(): for dynamic_runway in groundobjectgen.runways.values():
self.briefinggen.add_dynamic_runway(dynamic_runway) self.briefinggen.add_dynamic_runway(dynamic_runway)
for tanker in self.airsupportgen.air_support.tankers: for tanker in airsupportgen.air_support.tankers:
self.briefinggen.add_tanker(tanker) self.briefinggen.add_tanker(tanker)
kneeboard_generator.add_tanker(tanker) kneeboard_generator.add_tanker(tanker)
if self.is_awacs_enabled: if self.is_awacs_enabled:
for awacs in self.airsupportgen.air_support.awacs: for awacs in airsupportgen.air_support.awacs:
self.briefinggen.add_awacs(awacs) self.briefinggen.add_awacs(awacs)
kneeboard_generator.add_awacs(awacs) kneeboard_generator.add_awacs(awacs)
@@ -347,21 +350,23 @@ class Operation:
self.briefinggen.add_jtac(jtac) self.briefinggen.add_jtac(jtac)
kneeboard_generator.add_jtac(jtac) kneeboard_generator.add_jtac(jtac)
for flight in self.airgen.flights: for flight in airgen.flights:
self.briefinggen.add_flight(flight) self.briefinggen.add_flight(flight)
kneeboard_generator.add_flight(flight) kneeboard_generator.add_flight(flight)
self.briefinggen.generate() self.briefinggen.generate()
kneeboard_generator.generate() kneeboard_generator.generate()
def assign_channels_to_flights(self) -> None: def assign_channels_to_flights(self, flights: List[FlightData],
air_support: AirSupport) -> None:
"""Assigns preset radio channels for client flights.""" """Assigns preset radio channels for client flights."""
for flight in self.airgen.flights: for flight in flights:
if not flight.client_units: if not flight.client_units:
continue continue
self.assign_channels_to_flight(flight) self.assign_channels_to_flight(flight, air_support)
def assign_channels_to_flight(self, flight: FlightData) -> None: def assign_channels_to_flight(self, flight: FlightData,
air_support: AirSupport) -> None:
"""Assigns preset radio channels for a client flight.""" """Assigns preset radio channels for a client flight."""
airframe = flight.aircraft_type airframe = flight.aircraft_type
@@ -372,4 +377,5 @@ class Operation:
return return
aircraft_data.channel_allocator.assign_channels_for_flight( aircraft_data.channel_allocator.assign_channels_for_flight(
flight, self.airsupportgen.air_support) flight, air_support
)

View File

@@ -952,6 +952,7 @@ class AircraftConflictGenerator:
# pt.tasks.append(engagetgt) # pt.tasks.append(engagetgt)
elif point.waypoint_type == FlightWaypointType.LANDING_POINT: elif point.waypoint_type == FlightWaypointType.LANDING_POINT:
pt.type = "Land" pt.type = "Land"
pt.action = PointAction.Landing
elif point.waypoint_type == FlightWaypointType.INGRESS_STRIKE: elif point.waypoint_type == FlightWaypointType.INGRESS_STRIKE:
if group.units[0].unit_type == B_17G: if group.units[0].unit_type == B_17G:

View File

@@ -76,6 +76,7 @@ class AirSupportConflictGenerator:
speed=574, speed=574,
tacanchannel=str(tacan), tacanchannel=str(tacan),
) )
tanker_group.set_frequency(freq.mhz)
callsign = callsign_for_support_unit(tanker_group) callsign = callsign_for_support_unit(tanker_group)
tacan_callsign = { tacan_callsign = {
@@ -118,6 +119,8 @@ class AirSupportConflictGenerator:
frequency=freq.mhz, frequency=freq.mhz,
start_type=StartType.Warm, start_type=StartType.Warm,
) )
awacs_flight.set_frequency(freq.mhz)
awacs_flight.points[0].tasks.append(SetInvisibleCommand(True)) awacs_flight.points[0].tasks.append(SetInvisibleCommand(True))
awacs_flight.points[0].tasks.append(SetImmortalCommand(True)) awacs_flight.points[0].tasks.append(SetImmortalCommand(True))

View File

@@ -183,6 +183,11 @@ class GroundConflictGenerator:
return return
for dcs_group, group in ally_groups: for dcs_group, group in ally_groups:
if hasattr(group.units[0], 'eplrs'):
if group.units[0].eplrs:
dcs_group.points[0].tasks.append(EPLRS(dcs_group.id))
if group.role == CombatGroupRole.ARTILLERY: if group.role == CombatGroupRole.ARTILLERY:
# Fire on any ennemy in range # Fire on any ennemy in range
if self.game.settings.perf_artillery: if self.game.settings.perf_artillery:

View File

@@ -80,6 +80,10 @@ class GroundObjectsGenerator:
vehicle.heading = u.heading vehicle.heading = u.heading
vehicle.player_can_drive = True vehicle.player_can_drive = True
vg.add_unit(vehicle) vg.add_unit(vehicle)
if hasattr(utype, 'eplrs'):
if utype.eplrs:
vg.points[0].tasks.append(EPLRS(vg.id))
else: else:
vg = self.m.ship_group(side, g.name, utype, position=g.position, vg = self.m.ship_group(side, g.name, utype, position=g.position,
heading=g.units[0].heading) heading=g.units[0].heading)

2
pydcs

Submodule pydcs updated: ceea62a8e0...c203e5a1b8

View File

@@ -25,7 +25,7 @@ class ERC_90(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 4000 threat_range = 4000
air_weapon_dist = 4000 air_weapon_dist = 4000
eprls = True eplrs = True
class VAB__50(unittype.VehicleType): class VAB__50(unittype.VehicleType):
@@ -34,7 +34,7 @@ class VAB__50(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 1200 threat_range = 1200
air_weapon_dist = 1200 air_weapon_dist = 1200
eprls = True eplrs = True
class VAB_T20_13(unittype.VehicleType): class VAB_T20_13(unittype.VehicleType):
@@ -43,7 +43,7 @@ class VAB_T20_13(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 2000 threat_range = 2000
air_weapon_dist = 2000 air_weapon_dist = 2000
eprls = True eplrs = True
class VAB_MEPHISTO(unittype.VehicleType): class VAB_MEPHISTO(unittype.VehicleType):
@@ -52,7 +52,7 @@ class VAB_MEPHISTO(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 4000 threat_range = 4000
air_weapon_dist = 4000 air_weapon_dist = 4000
eprls = True eplrs = True
class VBL__50(unittype.VehicleType): class VBL__50(unittype.VehicleType):
@@ -61,7 +61,7 @@ class VBL__50(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 1200 threat_range = 1200
air_weapon_dist = 1200 air_weapon_dist = 1200
eprls = True eplrs = True
class VBL_AANF1(unittype.VehicleType): class VBL_AANF1(unittype.VehicleType):
@@ -70,7 +70,7 @@ class VBL_AANF1(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 1000 threat_range = 1000
air_weapon_dist = 1000 air_weapon_dist = 1000
eprls = True eplrs = True
class VBAE_CRAB(unittype.VehicleType): class VBAE_CRAB(unittype.VehicleType):
@@ -79,7 +79,7 @@ class VBAE_CRAB(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 3500 threat_range = 3500
air_weapon_dist = 3500 air_weapon_dist = 3500
eprls = True eplrs = True
class VBAE_CRAB_MMP(unittype.VehicleType): class VBAE_CRAB_MMP(unittype.VehicleType):
@@ -88,7 +88,7 @@ class VBAE_CRAB_MMP(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 3500 threat_range = 3500
air_weapon_dist = 3500 air_weapon_dist = 3500
eprls = True eplrs = True
class AMX_30B2(unittype.VehicleType): class AMX_30B2(unittype.VehicleType):
@@ -121,7 +121,7 @@ class DIM__TOYOTA_BLUE(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 1200 threat_range = 1200
air_weapon_dist = 1200 air_weapon_dist = 1200
eprls = True eplrs = True
class DIM__TOYOTA_GREEN(unittype.VehicleType): class DIM__TOYOTA_GREEN(unittype.VehicleType):
@@ -130,7 +130,7 @@ class DIM__TOYOTA_GREEN(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 1200 threat_range = 1200
air_weapon_dist = 1200 air_weapon_dist = 1200
eprls = True eplrs = True
class DIM__TOYOTA_DESERT(unittype.VehicleType): class DIM__TOYOTA_DESERT(unittype.VehicleType):
@@ -139,7 +139,7 @@ class DIM__TOYOTA_DESERT(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 1200 threat_range = 1200
air_weapon_dist = 1200 air_weapon_dist = 1200
eprls = True eplrs = True
class DIM__KAMIKAZE(unittype.VehicleType): class DIM__KAMIKAZE(unittype.VehicleType):
@@ -148,7 +148,7 @@ class DIM__KAMIKAZE(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 50 threat_range = 50
air_weapon_dist = 50 air_weapon_dist = 50
eprls = True eplrs = True
## FORTIFICATION ## FORTIFICATION
@@ -187,7 +187,7 @@ class TRM_2000(unittype.VehicleType):
detection_range = 3500 detection_range = 3500
threat_range = 0 threat_range = 0
air_weapon_dist = 0 air_weapon_dist = 0
eprls = True eplrs = True
class TRM_2000_Fuel(unittype.VehicleType): class TRM_2000_Fuel(unittype.VehicleType):
id = "TRM2000_Citerne" id = "TRM2000_Citerne"
@@ -195,7 +195,7 @@ class TRM_2000_Fuel(unittype.VehicleType):
detection_range = 3500 detection_range = 3500
threat_range = 0 threat_range = 0
air_weapon_dist = 0 air_weapon_dist = 0
eprls = True eplrs = True
class VAB_MEDICAL(unittype.VehicleType): class VAB_MEDICAL(unittype.VehicleType):
id = "VABH" id = "VABH"
@@ -203,7 +203,7 @@ class VAB_MEDICAL(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 0 threat_range = 0
air_weapon_dist = 0 air_weapon_dist = 0
eprls = True eplrs = True
class VAB(unittype.VehicleType): class VAB(unittype.VehicleType):
id = "VAB_RADIO" id = "VAB_RADIO"
@@ -211,7 +211,7 @@ class VAB(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 0 threat_range = 0
air_weapon_dist = 0 air_weapon_dist = 0
eprls = True eplrs = True
class VBL(unittype.VehicleType): class VBL(unittype.VehicleType):
id = "VBL-Radio" id = "VBL-Radio"
@@ -219,7 +219,7 @@ class VBL(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 0 threat_range = 0
air_weapon_dist = 0 air_weapon_dist = 0
eprls = True eplrs = True
class Tracma_TD_1500(unittype.VehicleType): class Tracma_TD_1500(unittype.VehicleType):
id = "Tracma" id = "Tracma"
@@ -236,7 +236,7 @@ class SMOKE_SAM_IR(unittype.VehicleType):
detection_range = 20000 detection_range = 20000
threat_range = 20000 threat_range = 20000
air_weapon_dist = 20000 air_weapon_dist = 20000
eprls = True eplrs = True
class _53T2(unittype.VehicleType): class _53T2(unittype.VehicleType):
id = "AA20" id = "AA20"
@@ -251,7 +251,7 @@ class TRM_2000_53T2(unittype.VehicleType):
detection_range = 6000 detection_range = 6000
threat_range = 2000 threat_range = 2000
air_weapon_dist = 2000 air_weapon_dist = 2000
eprls = True eplrs = True
class TRM_2000_PAMELA(unittype.VehicleType): class TRM_2000_PAMELA(unittype.VehicleType):
id = "TRMMISTRAL" id = "TRMMISTRAL"
@@ -259,7 +259,7 @@ class TRM_2000_PAMELA(unittype.VehicleType):
detection_range = 8000 detection_range = 8000
threat_range = 10000 threat_range = 10000
air_weapon_dist = 10000 air_weapon_dist = 10000
eprls = True eplrs = True
## INFANTRY ## INFANTRY
@@ -285,4 +285,4 @@ class VAB_MORTIER(unittype.VehicleType):
detection_range = 0 detection_range = 0
threat_range = 15000 threat_range = 15000
air_weapon_dist = 15000 air_weapon_dist = 15000
eprls = True eplrs = True

View File

@@ -8,7 +8,7 @@ from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
from theater.theatergroundobject import CATEGORY_MAP from theater.theatergroundobject import CATEGORY_MAP
from userdata.liberation_theme import get_theme_icons from userdata.liberation_theme import get_theme_icons
VERSION_STRING = "2.1.4" VERSION_STRING = "2.1.5"
URLS : Dict[str, str] = { URLS : Dict[str, str] = {
"Manual": "https://github.com/khopa/dcs_liberation/wiki", "Manual": "https://github.com/khopa/dcs_liberation/wiki",