Rename frontline vector to bounds, add a class.

This isn't actually the data that callers usually want. Most of the
callers just want the bounds. The heading and length are trivially
computed from that. Add a class to contain the result so it's easier to
refactor.
This commit is contained in:
Dan Albert 2022-09-11 14:12:07 -07:00 committed by Raffson
parent 46ddd884a2
commit a9f6e3a0c3
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
6 changed files with 65 additions and 58 deletions

View File

@ -77,11 +77,16 @@ class Builder(IBuilder[CasFlightPlan, CasLayout]):
FrontLineConflictDescription, FrontLineConflictDescription,
) )
ingress, heading, distance = FrontLineConflictDescription.frontline_vector( bounds = FrontLineConflictDescription.frontline_bounds(
location, self.theater, self.coalition.game.settings location, self.theater, self.coalition.game.settings
) )
center = ingress.point_from_heading(heading.degrees, distance / 2) ingress = bounds.left_position
egress = ingress.point_from_heading(heading.degrees, distance) center = ingress.point_from_heading(
bounds.heading_from_left_to_right.degrees, bounds.length / 2
)
egress = ingress.point_from_heading(
bounds.heading_from_left_to_right.degrees, bounds.length
)
ingress_distance = ingress.distance_to_point(self.flight.departure.position) ingress_distance = ingress.distance_to_point(self.flight.departure.position)
egress_distance = egress.distance_to_point(self.flight.departure.position) egress_distance = egress.distance_to_point(self.flight.departure.position)

View File

@ -15,14 +15,14 @@ from dcs.task import (
) )
from dcs.unittype import UnitType from dcs.unittype import UnitType
from game.ato.ai_flight_planner_db import AEWC_CAPABLE
from game.callsigns import callsign_for_support_unit from game.callsigns import callsign_for_support_unit
from game.naming import namegen from game.naming import namegen
from game.radio.radios import RadioRegistry from game.radio.radios import RadioRegistry
from game.radio.tacan import TacanBand, TacanRegistry, TacanUsage from game.radio.tacan import TacanBand, TacanRegistry, TacanUsage
from game.utils import Heading from game.utils import Heading
from game.ato.ai_flight_planner_db import AEWC_CAPABLE
from .missiondata import MissionData, AwacsInfo, TankerInfo
from .frontlineconflictdescription import FrontLineConflictDescription from .frontlineconflictdescription import FrontLineConflictDescription
from .missiondata import AwacsInfo, MissionData, TankerInfo
if TYPE_CHECKING: if TYPE_CHECKING:
from game import Game from game import Game

View File

@ -85,18 +85,16 @@ class DrawingsGenerator:
Generate a frontline "line" for each active frontline Generate a frontline "line" for each active frontline
""" """
for front_line in self.game.theater.conflicts(): for front_line in self.game.theater.conflicts():
( bounds = FrontLineConflictDescription.frontline_bounds(
plane_start,
heading,
distance,
) = FrontLineConflictDescription.frontline_vector(
front_line, self.game.theater, self.game.settings front_line, self.game.theater, self.game.settings
) )
end_point = plane_start.point_from_heading(heading.degrees, distance) end_point = bounds.left_position.point_from_heading(
bounds.heading_from_left_to_right.degrees, bounds.length
)
shape = self.player_layer.add_line_segment( shape = self.player_layer.add_line_segment(
plane_start, bounds.left_position,
end_point - plane_start, end_point - bounds.left_position,
line_thickness=16, line_thickness=16,
color=FRONTLINE_COLORS, color=FRONTLINE_COLORS,
line_style=LineStyle.Triangle, line_style=LineStyle.Triangle,

View File

@ -43,9 +43,9 @@ from game.radio.radios import RadioRegistry
from game.theater.controlpoint import ControlPoint from game.theater.controlpoint import ControlPoint
from game.unitmap import UnitMap from game.unitmap import UnitMap
from game.utils import Heading from game.utils import Heading
from .missiondata import MissionData, JtacInfo
from .frontlineconflictdescription import FrontLineConflictDescription from .frontlineconflictdescription import FrontLineConflictDescription
from .lasercoderegistry import LaserCodeRegistry from .lasercoderegistry import LaserCodeRegistry
from .missiondata import JtacInfo, MissionData
if TYPE_CHECKING: if TYPE_CHECKING:
from game import Game from game import Game
@ -100,18 +100,14 @@ class FlotGenerator:
self.conflict.front_line, self.game.theater, self.game.settings self.conflict.front_line, self.game.theater, self.game.settings
) )
frontline_vector = FrontLineConflictDescription.frontline_vector(
self.conflict.front_line, self.game.theater, self.game.settings
)
# Create player groups at random position # Create player groups at random position
player_groups = self._generate_groups( player_groups = self._generate_groups(
self.player_planned_combat_groups, frontline_vector, True self.player_planned_combat_groups, is_player=True
) )
# Create enemy groups at random position # Create enemy groups at random position
enemy_groups = self._generate_groups( enemy_groups = self._generate_groups(
self.enemy_planned_combat_groups, frontline_vector, False self.enemy_planned_combat_groups, is_player=False
) )
# TODO: Differentiate AirConflict and GroundConflict classes. # TODO: Differentiate AirConflict and GroundConflict classes.
@ -698,33 +694,33 @@ class FlotGenerator:
return rg return rg
def get_valid_position_for_group( def get_valid_position_for_group(
self, self, distance_from_frontline: int, spawn_heading: Heading
conflict_position: Point, ) -> Point | None:
combat_width: int, assert self.conflict.heading is not None
distance_from_frontline: int, assert self.conflict.size is not None
heading: Heading, shifted = self.conflict.position.point_from_heading(
spawn_heading: Heading, self.conflict.heading.degrees,
) -> Optional[Point]: random.randint(0, self.conflict.size),
shifted = conflict_position.point_from_heading(
heading.degrees, random.randint(0, combat_width)
) )
desired_point = shifted.point_from_heading( desired_point = shifted.point_from_heading(
spawn_heading.degrees, distance_from_frontline spawn_heading.degrees, distance_from_frontline
) )
return FrontLineConflictDescription.find_ground_position( return FrontLineConflictDescription.find_ground_position(
desired_point, combat_width, heading, self.conflict.theater desired_point,
self.conflict.size,
self.conflict.heading,
self.conflict.theater,
) )
def _generate_groups( def _generate_groups(
self, self, groups: list[CombatGroup], is_player: bool
groups: list[CombatGroup],
frontline_vector: Tuple[Point, Heading, int],
is_player: bool,
) -> List[Tuple[VehicleGroup, CombatGroup]]: ) -> List[Tuple[VehicleGroup, CombatGroup]]:
"""Finds valid positions for planned groups and generates a pydcs group for them""" """Finds valid positions for planned groups and generates a pydcs group for them"""
positioned_groups = [] positioned_groups = []
position, heading, combat_width = frontline_vector assert self.conflict.heading is not None
spawn_heading = heading.left if is_player else heading.right spawn_heading = (
self.conflict.heading.left if is_player else self.conflict.heading.right
)
country = self.game.coalition_for(is_player).country_name country = self.game.coalition_for(is_player).country_name
for group in groups: for group in groups:
if group.role == CombatGroupRole.ARTILLERY: if group.role == CombatGroupRole.ARTILLERY:
@ -738,7 +734,7 @@ class FlotGenerator:
) )
final_position = self.get_valid_position_for_group( final_position = self.get_valid_position_for_group(
position, combat_width, distance_from_frontline, heading, spawn_heading distance_from_frontline, spawn_heading
) )
if final_position is not None: if final_position is not None:

View File

@ -1,7 +1,8 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import Tuple, Optional from dataclasses import dataclass
from typing import Optional, Tuple
from dcs.country import Country from dcs.country import Country
from dcs.mapping import Point from dcs.mapping import Point
@ -12,6 +13,15 @@ from game.theater.conflicttheater import ConflictTheater, FrontLine
from game.theater.controlpoint import ControlPoint from game.theater.controlpoint import ControlPoint
from game.utils import Heading from game.utils import Heading
FRONTLINE_LENGTH = 80000
@dataclass(frozen=True)
class FrontLineBounds:
left_position: Point
heading_from_left_to_right: Heading
length: int
class FrontLineConflictDescription: class FrontLineConflictDescription:
def __init__( def __init__(
@ -26,7 +36,6 @@ class FrontLineConflictDescription:
heading: Optional[Heading] = None, heading: Optional[Heading] = None,
size: Optional[int] = None, size: Optional[int] = None,
): ):
self.attackers_side = attackers_side self.attackers_side = attackers_side
self.defenders_side = defenders_side self.defenders_side = defenders_side
self.attackers_country = attackers_country self.attackers_country = attackers_country
@ -66,9 +75,9 @@ class FrontLineConflictDescription:
return position, attack_heading.opposite return position, attack_heading.opposite
@classmethod @classmethod
def frontline_vector( def frontline_bounds(
cls, front_line: FrontLine, theater: ConflictTheater, settings: Settings cls, front_line: FrontLine, theater: ConflictTheater, settings: Settings
) -> Tuple[Point, Heading, int]: ) -> FrontLineBounds:
""" """
Returns a vector for a valid frontline location avoiding exclusion zones. Returns a vector for a valid frontline location avoiding exclusion zones.
""" """
@ -88,7 +97,7 @@ class FrontLineConflictDescription:
theater, theater,
) )
distance = int(left_position.distance_to_point(right_position)) distance = int(left_position.distance_to_point(right_position))
return left_position, right_heading, distance return FrontLineBounds(left_position, right_heading, distance)
@classmethod @classmethod
def frontline_cas_conflict( def frontline_cas_conflict(
@ -102,19 +111,20 @@ class FrontLineConflictDescription:
settings: Settings, settings: Settings,
) -> FrontLineConflictDescription: ) -> FrontLineConflictDescription:
assert cls.has_frontline_between(front_line.blue_cp, front_line.red_cp) assert cls.has_frontline_between(front_line.blue_cp, front_line.red_cp)
position, heading, distance = cls.frontline_vector( # TODO: Break apart the front-line and air conflict descriptions.
front_line, theater, settings # We're wastefully not caching the front-line bounds here because air conflicts
) # can't compute bounds, only a position.
bounds = cls.frontline_bounds(front_line, theater, settings)
conflict = cls( conflict = cls(
position=position, position=bounds.left_position,
heading=heading, heading=bounds.heading_from_left_to_right,
theater=theater, theater=theater,
front_line=front_line, front_line=front_line,
attackers_side=attacker_name, attackers_side=attacker_name,
defenders_side=defender_name, defenders_side=defender_name,
attackers_country=attacker, attackers_country=attacker,
defenders_country=defender, defenders_country=defender,
size=distance, size=bounds.length,
) )
return conflict return conflict

View File

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
import random import random
from typing import TYPE_CHECKING, Any from typing import Any, TYPE_CHECKING
from dcs.mission import Mission from dcs.mission import Mission
from dcs.unit import Static from dcs.unit import Static
@ -79,18 +79,16 @@ class VisualsGenerator:
if from_cp.is_global or to_cp.is_global: if from_cp.is_global or to_cp.is_global:
continue continue
( bounds = FrontLineConflictDescription.frontline_bounds(
plane_start,
heading,
distance,
) = FrontLineConflictDescription.frontline_vector(
front_line, self.game.theater, self.game.settings front_line, self.game.theater, self.game.settings
) )
if not plane_start:
continue
for offset in range(0, distance, self.game.settings.perf_smoke_spacing): for offset in range(
position = plane_start.point_from_heading(heading.degrees, offset) 0, bounds.length, self.game.settings.perf_smoke_spacing
):
position = bounds.left_position.point_from_heading(
bounds.heading_from_left_to_right.degrees, offset
)
for k, v in FRONT_SMOKE_TYPE_CHANCES.items(): for k, v in FRONT_SMOKE_TYPE_CHANCES.items():
if random.randint(0, 100) <= k: if random.randint(0, 100) <= k: