Handle threat/detection per group.

Some SAMs have multiple groups (such as an SA-10 group with its
accompanying SA-15 and SA-19 groups). This shows each group's threat and
detection separately on the map, and also makes it so that an SA-10 with
dead radars will no longer contribute to the threat zone just because
the shilka next to it still has a functioning radar.

https://github.com/Khopa/dcs_liberation/issues/647
Fixes https://github.com/Khopa/dcs_liberation/issues/672
This commit is contained in:
Dan Albert 2020-12-26 15:52:36 -08:00
parent d946a9e526
commit a6dc3d2aff
4 changed files with 32 additions and 31 deletions

View File

@ -15,6 +15,7 @@ Saves from 2.3 are not compatible with 2.4.
* **[Balance]** Opfor now gains income using the same rules as the player, significantly increasing their income relative to the player for most campaigns.
* **[Economy]** FOBs generate only $10M per turn (previously $20M like airbases).
* **[Economy]** Carriers and off-map spawns generate no income (previously $20M like airbases).
* **[UI]** Multi-SAM objectives now show threat and detection rings per group.
# 2.3.3

View File

@ -157,12 +157,11 @@ class TheaterGroundObject(MissionTarget):
return True
return False
def _max_range_of_type(self, range_type: str) -> Distance:
def _max_range_of_type(self, group: Group, range_type: str) -> Distance:
if not self.might_have_aa:
return meters(0)
max_range = meters(0)
for group in self.groups:
for u in group.units:
unit = db.unit_type_from_name(u.type)
if unit is None:
@ -176,20 +175,18 @@ class TheaterGroundObject(MissionTarget):
max_range = max(max_range, meters(unit_range))
return max_range
@property
def detection_range(self) -> Distance:
return self._max_range_of_type("detection_range")
def detection_range(self, group: Group) -> Distance:
return self._max_range_of_type(group, "detection_range")
@property
def threat_range(self) -> Distance:
if not self.detection_range:
def threat_range(self, group: Group) -> Distance:
if not self.detection_range(group):
# For simple SAMs like shilkas, the unit has both a threat and
# detection range. For complex sites like SA-2s, the launcher has a
# threat range and the search/track radars have detection ranges. If
# the site has no detection range it has no radars and can't fire,
# so it's not actually a threat even if it still has launchers.
return meters(0)
return self._max_range_of_type("threat_range")
return self._max_range_of_type(group, "threat_range")
class BuildingGroundObject(TheaterGroundObject):

View File

@ -95,9 +95,10 @@ class ThreatZones:
airbases.append(point.buffer(cap_threat_range.meters))
for tgo in control_point.ground_objects:
threat_range = tgo.threat_range
# Any system with a shorter range than this is not worth even
# avoiding.
for group in tgo.groups:
threat_range = tgo.threat_range(group)
# Any system with a shorter range than this is not worth
# even avoiding.
if threat_range > nautical_miles(3):
point = ShapelyPoint(tgo.position.x, tgo.position.y)
threat_zone = point.buffer(threat_range.meters)

View File

@ -28,6 +28,7 @@ from PySide2.QtWidgets import (
from dcs import Point
from dcs.planes import F_16C_50
from dcs.mapping import point_from_heading
from dcs.unitgroup import Group
from shapely.geometry import (
LineString,
MultiPolygon,
@ -36,7 +37,7 @@ from shapely.geometry import (
)
import qt_ui.uiconstants as CONST
from game import Game, db
from game import Game
from game.navmesh import NavMesh
from game.theater import ControlPoint, Enum
from game.theater.conflicttheater import FrontLine, ReferencePoint
@ -446,10 +447,10 @@ class QLiberationMap(QGraphicsView):
return ((DisplayOptions.sam_ranges and cp.captured) or
(DisplayOptions.enemy_sam_ranges and not cp.captured))
def draw_threat_range(self, scene: QGraphicsScene, ground_object: TheaterGroundObject, cp: ControlPoint) -> None:
def draw_threat_range(self, scene: QGraphicsScene, group: Group, ground_object: TheaterGroundObject, cp: ControlPoint) -> None:
go_pos = self._transform_point(ground_object.position)
detection_range = ground_object.detection_range
threat_range = ground_object.threat_range
detection_range = ground_object.detection_range(group)
threat_range = ground_object.threat_range(group)
if threat_range:
threat_pos = self._transform_point(
ground_object.position + Point(threat_range.meters,
@ -482,7 +483,8 @@ class QLiberationMap(QGraphicsView):
should_display = self.should_display_ground_objects_at(cp)
if ground_object.might_have_aa and should_display:
self.draw_threat_range(scene, ground_object, cp)
for group in ground_object.groups:
self.draw_threat_range(scene, group, ground_object, cp)
added_objects.append(ground_object.obj_name)
def reload_scene(self):