Merge pull request #487 from walterroach/fob

FOB Control Points
This commit is contained in:
walterroach 2020-11-30 23:29:15 -06:00 committed by GitHub
commit aef4316f72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 8 deletions

View File

@ -39,7 +39,7 @@ from dcs.unitgroup import (
StaticGroup,
VehicleGroup,
)
from dcs.vehicles import AirDefence, Armor, MissilesSS
from dcs.vehicles import AirDefence, Armor, MissilesSS, Unarmed
from gen.flights.flight import FlightType
from .controlpoint import (
@ -49,6 +49,7 @@ from .controlpoint import (
Lha,
MissionTarget,
OffMapSpawn,
Fob,
)
from .landmap import Landmap, load_landmap, poly_contains
from ..utils import nm_to_meter
@ -87,6 +88,8 @@ class MizCampaignLoader:
LHA_UNIT_TYPE = LHA_1_Tarawa.id
FRONT_LINE_UNIT_TYPE = Armor.APC_M113.id
FOB_UNIT_TYPE = Unarmed.CP_SKP_11_ATC_Mobile_Command_Post.id
EWR_UNIT_TYPE = AirDefence.EWR_55G6.id
SAM_UNIT_TYPE = AirDefence.SAM_SA_10_S_300PS_SR_64H6E.id
GARRISON_UNIT_TYPE = AirDefence.SAM_SA_19_Tunguska_2S6.id
@ -177,6 +180,11 @@ class MizCampaignLoader:
for group in self.country(blue).ship_group:
if group.units[0].type == self.LHA_UNIT_TYPE:
yield group
def fobs(self, blue: bool) -> Iterator[VehicleGroup]:
for group in self.country(blue).vehicle_group:
if group.units[0].type == self.FOB_UNIT_TYPE:
yield group
@property
def ships(self) -> Iterator[ShipGroup]:
@ -261,6 +269,13 @@ class MizCampaignLoader:
control_point.captured = blue
control_point.captured_invert = group.late_activation
control_points[control_point.id] = control_point
for group in self.fobs(blue):
control_point = Fob(
str(group.name), group.position, next(self.control_point_id)
)
control_point.captured = blue
control_point.captured_invert = group.late_activation
control_points[control_point.id] = control_point
return control_points
@ -279,14 +294,14 @@ class MizCampaignLoader:
# final waypoint at the destination CP. Intermediate waypoints
# define the curve of the front line.
waypoints = [p.position for p in group.points]
origin = self.mission.terrain.nearest_airport(waypoints[0])
origin = self.theater.closest_control_point(waypoints[0])
if origin is None:
raise RuntimeError(
f"No airport near the first waypoint of {group.name}")
destination = self.mission.terrain.nearest_airport(waypoints[-1])
f"No control point near the first waypoint of {group.name}")
destination = self.theater.closest_control_point(waypoints[-1])
if destination is None:
raise RuntimeError(
f"No airport near the final waypoint of {group.name}")
f"No control point near the final waypoint of {group.name}")
# Snap the begin and end points to the control points.
waypoints[0] = origin.position

View File

@ -623,3 +623,51 @@ class OffMapSpawn(ControlPoint):
@property
def runway_status(self) -> RunwayStatus:
return RunwayStatus()
class Fob(ControlPoint):
def __init__(self, name: str, at: Point, cp_id: int):
import game.theater.conflicttheater
super().__init__(cp_id, name, at, at,
game.theater.conflicttheater.SIZE_SMALL, 1,
has_frontline=True, cptype=ControlPointType.FOB)
self.name = name
def runway_is_operational(self) -> bool:
return False
def active_runway(self, conditions: Conditions,
dynamic_runways: Dict[str, RunwayData]) -> RunwayData:
logging.warning("TODO: FOBs have no runways.")
return RunwayData(self.full_name, runway_heading=0, runway_name="")
@property
def runway_status(self) -> RunwayStatus:
return RunwayStatus()
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
from gen.flights.flight import FlightType
if self.is_friendly(for_player):
yield from [
FlightType.BARCAP,
# TODO: FlightType.LOGISTICS
]
else:
yield from [
FlightType.STRIKE,
FlightType.SWEEP,
FlightType.ESCORT,
FlightType.SEAD,
]
@property
def total_aircraft_parking(self) -> int:
return 0
def can_operate(self, aircraft: FlyingType) -> bool:
return False
@property
def heading(self) -> int:
return 0

View File

@ -45,6 +45,7 @@ from . import (
ControlPoint,
ControlPointType,
OffMapSpawn,
Fob,
)
GroundObjectTemplates = Dict[str, Dict[str, Any]]
@ -537,7 +538,26 @@ class BaseDefenseGenerator:
return
g.groups.append(group)
self.control_point.base_defenses.append(g)
class FobDefenseGenerator(BaseDefenseGenerator):
def generate(self) -> None:
self.generate_garrison()
self.generate_fob_defenses()
def generate_fob_defenses(self):
# First group has a 1/2 chance of being a SHORAD,
# and a 1/2 chance of a garrison.
#
# Further groups have a 1/3 chance of being SHORAD and 2/3 chance of
# being a garrison.
for i in range(random.randint(2, 5)):
if i == 0 and random.randint(0, 1) == 0:
self.generate_shorad()
elif i == 0 and random.randint(0, 1) == 0:
self.generate_garrison()
elif random.randint(0, 2) == 1:
self.generate_shorad()
else:
self.generate_garrison()
class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
def __init__(self, game: Game, control_point: ControlPoint,
@ -679,6 +699,35 @@ class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator):
self.control_point.connected_objectives.append(g)
return
class FobGroundObjectGenerator(AirbaseGroundObjectGenerator):
def generate(self) -> bool:
self.generate_fob()
FobDefenseGenerator(self.game, self.control_point).generate()
return True
def generate_fob(self) -> None:
try:
category = self.faction.building_set[self.faction.building_set.index('fob')]
except IndexError:
logging.exception("Faction has no fob buildings defined")
return
obj_name = self.control_point.name
template = random.choice(list(self.templates[category].values()))
point = self.control_point.position
# Pick from preset locations
object_id = 0
group_id = self.game.next_group_id()
# TODO: Create only one TGO per objective, each with multiple units.
for unit in template:
object_id += 1
template_point = Point(unit["offset"].x, unit["offset"].y)
g = BuildingGroundObject(
obj_name, category, group_id, object_id, point + template_point,
unit["heading"], self.control_point, unit["type"], airbase_group=True)
self.control_point.connected_objectives.append(g)
class GroundObjectGenerator:
def __init__(self, game: Game) -> None:
@ -702,6 +751,9 @@ class GroundObjectGenerator:
generator = LhaGroundObjectGenerator(self.game, control_point)
elif isinstance(control_point, OffMapSpawn):
generator = NoOpGroundObjectGenerator(self.game, control_point)
elif isinstance(control_point, Fob):
generator = FobGroundObjectGenerator(self.game, control_point,
self.templates)
else:
generator = AirbaseGroundObjectGenerator(self.game, control_point,
self.templates)

View File

@ -140,7 +140,7 @@ class TheaterGroundObject(MissionTarget):
class BuildingGroundObject(TheaterGroundObject):
def __init__(self, name: str, category: str, group_id: int, object_id: int,
position: Point, heading: int, control_point: ControlPoint,
dcs_identifier: str) -> None:
dcs_identifier: str, airbase_group=False) -> None:
super().__init__(
name=name,
category=category,
@ -149,7 +149,7 @@ class BuildingGroundObject(TheaterGroundObject):
heading=heading,
control_point=control_point,
dcs_identifier=dcs_identifier,
airbase_group=False,
airbase_group=airbase_group,
sea_object=False
)
self.object_id = object_id