PBO: IADS

Finishes/Fixes part of advanced IADS in back-end
This commit is contained in:
Raffson 2022-08-14 15:26:40 +02:00
parent 6e555167e0
commit 244415b721
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
6 changed files with 94 additions and 12 deletions

View File

@ -33,7 +33,6 @@ import { threatZonesUpdated } from "./threatZonesSlice";
import { unculledZonesUpdated } from "./unculledZonesSlice"; import { unculledZonesUpdated } from "./unculledZonesSlice";
import { LatLng } from "leaflet"; import { LatLng } from "leaflet";
import { updateIadsConnection, removeIadsConnection } from "./iadsNetworkSlice"; import { updateIadsConnection, removeIadsConnection } from "./iadsNetworkSlice";
import { IadsConnection } from "./_liberationApi";
import { supplyRoutesUpdated } from "./supplyRoutesSlice"; import { supplyRoutesUpdated } from "./supplyRoutesSlice";
interface GameUpdateEvents { interface GameUpdateEvents {

View File

@ -839,10 +839,9 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
# All the attached TGOs have either been depopulated or captured. Tell the UI to # All the attached TGOs have either been depopulated or captured. Tell the UI to
# update their state. Also update orientation and IADS state for specific tgos # update their state. Also update orientation and IADS state for specific tgos
for tgo in self.connected_objectives: for tgo in self.connected_objectives:
if isinstance(tgo, IadsGroundObject) or isinstance( is_vehicle_go = isinstance(tgo, VehicleGroupGroundObject)
tgo, VehicleGroupGroundObject if tgo.is_iads or is_vehicle_go:
): if tgo.is_iads:
if isinstance(tgo, IadsGroundObject):
game.theater.iads_network.update_tgo(tgo, events) game.theater.iads_network.update_tgo(tgo, events)
conflict_heading = game.theater.heading_to_conflict_from(tgo.position) conflict_heading = game.theater.heading_to_conflict_from(tgo.position)
tgo.rotate(conflict_heading or tgo.heading) tgo.rotate(conflict_heading or tgo.heading)

View File

@ -120,13 +120,6 @@ class IadsNetwork:
# Skip culled ground objects # Skip culled ground objects
continue continue
# HOTFIX! Skip non-static nodes with no alive units left
# Delete this as soon as PRs #2285, #2286 & #2287 are merged
unit_count = len(node.group.units)
is_static = node.group.units[0].is_static if unit_count > 0 else False
if node.group.alive_units == 0 and not is_static:
continue
# SkynetNode.from_group(node.group) may raise an exception # SkynetNode.from_group(node.group) may raise an exception
# (originating from SkynetNode.dcs_name_for_group) # (originating from SkynetNode.dcs_name_for_group)
# but if it does, we want to know because it's supposed to be impossible afaict # but if it does, we want to know because it's supposed to be impossible afaict
@ -141,8 +134,53 @@ class IadsNetwork:
skynet_nodes.append(skynet_node) skynet_nodes.append(skynet_node)
return skynet_nodes return skynet_nodes
def _update_iads_comms_and_power(
self, tgo: TheaterGroundObject, events: GameUpdateEvents
) -> None:
assert self.advanced_iads, "_update_iads_comms_and_power requires advanced IADS"
is_comm_or_power = IadsRole.for_category(tgo.category).is_comms_or_power
assert is_comm_or_power, "Invalid TGO was given for _update_iads_building"
"""
Delete/Update connections to the comm tower/power station
If this function is called, it should imply only 2 possibilities (unless I missed one):
1) A capture event occurred, thus the building now belongs to the capturing team
=> All connections to this building are to the enemy, thus delete them
(mind that no new connections could have been formed since all TGOs were depopulated)
2) The building was destroyed during a mission
=> In this case we don't need to delete the connections
instead we just update the nodes that connect to this building
because those connections are still coming from friendly TGOs
Given the above, we should be able to use the following implications:
If the building is friendly compared to the node that we're checking
=> Building was destroyed during mission
=> Update nodes that connect to this building
Otherwise if the building is not friendly compared to the node we're checking
=> Capture event occurred
=> Delete all connections to this building
TODO: clean up the code below by wrapping comm towers and power stations
preferably in a class like IadsNetworkNode, keeping a reference to connected nodes
"""
for node in self.nodes:
to_delete = []
for cID in node.connections:
group = node.connections[cID]
if group.ground_object is tgo:
if self._is_friendly(node, tgo):
events.update_iads_node(node)
else:
to_delete.append(cID)
events.delete_iads_connection(cID)
for cID in to_delete:
del node.connections[cID]
if not self.iads_config:
self._update_network(tgo, events)
def update_tgo(self, tgo: TheaterGroundObject, events: GameUpdateEvents) -> None: def update_tgo(self, tgo: TheaterGroundObject, events: GameUpdateEvents) -> None:
"""Update the IADS Network for the given TGO""" """Update the IADS Network for the given TGO"""
if IadsRole.for_category(tgo.category).is_comms_or_power:
return self._update_iads_comms_and_power(tgo, events)
# Remove existing nodes for the given tgo # Remove existing nodes for the given tgo
for cn in self.nodes: for cn in self.nodes:
if cn.group.ground_object == tgo: if cn.group.ground_object == tgo:
@ -275,3 +313,23 @@ class IadsNetwork:
<= node.group.iads_role.connection_range.meters <= node.group.iads_role.connection_range.meters
): ):
node.add_connection_for_tgo(nearby_go) node.add_connection_for_tgo(nearby_go)
def _is_friendly(self, node: IadsNetworkNode, tgo: TheaterGroundObject) -> bool:
node_friendly = node.group.ground_object.is_friendly(True)
tgo_friendly = tgo.is_friendly(True)
return node_friendly == tgo_friendly
def _update_network(
self, tgo: TheaterGroundObject, events: GameUpdateEvents
) -> None:
if tgo.is_dead:
return
iads_role = IadsRole.for_category(tgo.category)
if not iads_role.is_comms_or_power:
return
for node in self.nodes:
dist = node.group.ground_object.position.distance_to_point(tgo.position)
in_range = dist < iads_role.connection_range.meters
if in_range and self._is_friendly(node, tgo):
node.add_connection_for_tgo(tgo)
events.update_iads_node(node)

View File

@ -79,3 +79,10 @@ class IadsRole(Enum):
IadsRole.NO_BEHAVIOR, IadsRole.NO_BEHAVIOR,
IadsRole.POINT_DEFENSE, IadsRole.POINT_DEFENSE,
] ]
@property
def is_comms_or_power(self) -> bool:
return self in [
IadsRole.POWER_SOURCE,
IadsRole.CONNECTION_NODE,
]

View File

@ -267,6 +267,10 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC):
"""Should this TGO head towards the closest conflict to work properly?""" """Should this TGO head towards the closest conflict to work properly?"""
return False return False
@property
def is_iads(self) -> bool:
return False
class BuildingGroundObject(TheaterGroundObject): class BuildingGroundObject(TheaterGroundObject):
def __init__( def __init__(
@ -353,6 +357,10 @@ class NavalGroundObject(TheaterGroundObject, ABC):
def purchasable(self) -> bool: def purchasable(self) -> bool:
return False return False
@property
def is_iads(self) -> bool:
return True
class GenericCarrierGroundObject(NavalGroundObject, ABC): class GenericCarrierGroundObject(NavalGroundObject, ABC):
@property @property
@ -490,6 +498,10 @@ class IadsGroundObject(TheaterGroundObject, ABC):
def should_head_to_conflict(self) -> bool: def should_head_to_conflict(self) -> bool:
return True return True
@property
def is_iads(self) -> bool:
return True
# The SamGroundObject represents all type of AA # The SamGroundObject represents all type of AA
# The TGO can have multiple types of units (AAA,SAM,Support...) # The TGO can have multiple types of units (AAA,SAM,Support...)
@ -630,3 +642,7 @@ class IadsBuildingGroundObject(BuildingGroundObject):
for mission_type in super().mission_types(for_player): for mission_type in super().mission_types(for_player):
if mission_type not in skippers: if mission_type not in skippers:
yield mission_type yield mission_type
@property
def is_iads(self) -> bool:
return True

View File

@ -63,6 +63,9 @@ class TheaterUnit:
self.alive = False self.alive = False
self.ground_object.invalidate_threat_poly() self.ground_object.invalidate_threat_poly()
events.update_tgo(self.ground_object) events.update_tgo(self.ground_object)
if self.ground_object.is_iads:
iads = self.ground_object.control_point.coalition.game.theater.iads_network
iads.update_tgo(self.ground_object, events)
@property @property
def unit_name(self) -> str: def unit_name(self) -> str: