Update pydcs, adapt to new Point APIs.

This is briefly moving us over to my fork of pydcs while we wait for
https://github.com/pydcs/dcs/pull/206 to be merged. The adaptation is
invasive enough that I don't want it lingering for long.
This commit is contained in:
Dan Albert 2022-02-21 18:14:49 -08:00
parent ff12b37431
commit 9e2e4ffa74
29 changed files with 155 additions and 186 deletions

View File

@ -701,8 +701,7 @@ class StrikeFlightPlan(FormationFlightPlan):
return FlightWaypoint( return FlightWaypoint(
"TARGET AREA", "TARGET AREA",
FlightWaypointType.TARGET_GROUP_LOC, FlightWaypointType.TARGET_GROUP_LOC,
self.package.target.position.x, self.package.target.position,
self.package.target.position.y,
meters(0), meters(0),
"RADIO", "RADIO",
) )
@ -906,8 +905,7 @@ class PackageRefuelingFlightPlan(RefuelingFlightPlan):
return FlightWaypoint( return FlightWaypoint(
"TARGET AREA", "TARGET AREA",
FlightWaypointType.TARGET_GROUP_LOC, FlightWaypointType.TARGET_GROUP_LOC,
self.package.target.position.x, self.package.target.position,
self.package.target.position.y,
meters(0), meters(0),
"RADIO", "RADIO",
) )
@ -924,13 +922,13 @@ class PackageRefuelingFlightPlan(RefuelingFlightPlan):
# Cheat in a FlightWaypoint for the split point. # Cheat in a FlightWaypoint for the split point.
split: Point = self.package.waypoints.split split: Point = self.package.waypoints.split
split_waypoint: FlightWaypoint = FlightWaypoint( split_waypoint: FlightWaypoint = FlightWaypoint(
"SPLIT", FlightWaypointType.SPLIT, split.x, split.y, altitude "SPLIT", FlightWaypointType.SPLIT, split, altitude
) )
# Cheat in a FlightWaypoint for the refuel point. # Cheat in a FlightWaypoint for the refuel point.
refuel: Point = self.package.waypoints.refuel refuel: Point = self.package.waypoints.refuel
refuel_waypoint: FlightWaypoint = FlightWaypoint( refuel_waypoint: FlightWaypoint = FlightWaypoint(
"REFUEL", FlightWaypointType.REFUEL, refuel.x, refuel.y, altitude "REFUEL", FlightWaypointType.REFUEL, refuel, altitude
) )
delay_target_to_split: timedelta = self.travel_time_between_waypoints( delay_target_to_split: timedelta = self.travel_time_between_waypoints(

View File

@ -31,12 +31,9 @@ class Navigating(InFlight):
) )
def estimate_position(self) -> Point: def estimate_position(self) -> Point:
x0 = self.current_waypoint.position.x return self.current_waypoint.position.lerp(
y0 = self.current_waypoint.position.y self.next_waypoint.position, self.progress()
x1 = self.next_waypoint.position.x )
y1 = self.next_waypoint.position.y
progress = self.progress()
return Point(lerp(x0, x1, progress), lerp(y0, y1, progress))
def estimate_altitude(self) -> tuple[Distance, str]: def estimate_altitude(self) -> tuple[Distance, str]:
return ( return (

View File

@ -22,8 +22,7 @@ AltitudeReference = Literal["BARO", "RADIO"]
class FlightWaypoint: class FlightWaypoint:
name: str name: str
waypoint_type: FlightWaypointType waypoint_type: FlightWaypointType
x: float position: Point
y: float
alt: Distance = meters(0) alt: Distance = meters(0)
alt_type: AltitudeReference = "BARO" alt_type: AltitudeReference = "BARO"
control_point: ControlPoint | None = None control_point: ControlPoint | None = None
@ -50,8 +49,12 @@ class FlightWaypoint:
departure_time: timedelta | None = None departure_time: timedelta | None = None
@property @property
def position(self) -> Point: def x(self) -> float:
return Point(self.x, self.y) return self.position.x
@property
def y(self) -> float:
return self.position.y
def __hash__(self) -> int: def __hash__(self) -> int:
return hash(id(self)) return hash(id(self))

View File

@ -12,7 +12,7 @@ from typing import (
Union, Union,
) )
from dcs.mapping import Point from dcs.mapping import Point, Vector2
from game.theater import ( from game.theater import (
ControlPoint, ControlPoint,
@ -71,8 +71,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"NAV", "NAV",
FlightWaypointType.NAV, FlightWaypointType.NAV,
position.x, position,
position.y,
meters(500) if self.is_helo else self.doctrine.rendezvous_altitude, meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
description="Enter theater", description="Enter theater",
pretty_name="Enter theater", pretty_name="Enter theater",
@ -81,8 +80,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"TAKEOFF", "TAKEOFF",
FlightWaypointType.TAKEOFF, FlightWaypointType.TAKEOFF,
position.x, position,
position.y,
meters(0), meters(0),
alt_type="RADIO", alt_type="RADIO",
description="Takeoff", description="Takeoff",
@ -100,8 +98,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"NAV", "NAV",
FlightWaypointType.NAV, FlightWaypointType.NAV,
position.x, position,
position.y,
meters(500) if self.is_helo else self.doctrine.rendezvous_altitude, meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
description="Exit theater", description="Exit theater",
pretty_name="Exit theater", pretty_name="Exit theater",
@ -110,8 +107,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"LANDING", "LANDING",
FlightWaypointType.LANDING_POINT, FlightWaypointType.LANDING_POINT,
position.x, position,
position.y,
meters(0), meters(0),
alt_type="RADIO", alt_type="RADIO",
description="Land", description="Land",
@ -143,8 +139,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"DIVERT", "DIVERT",
FlightWaypointType.DIVERT, FlightWaypointType.DIVERT,
position.x, position,
position.y,
altitude, altitude,
alt_type=altitude_type, alt_type=altitude_type,
description="Divert", description="Divert",
@ -157,8 +152,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"BULLSEYE", "BULLSEYE",
FlightWaypointType.BULLSEYE, FlightWaypointType.BULLSEYE,
self._bullseye.position.x, self._bullseye.position,
self._bullseye.position.y,
meters(0), meters(0),
description="Bullseye", description="Bullseye",
pretty_name="Bullseye", pretty_name="Bullseye",
@ -173,8 +167,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"HOLD", "HOLD",
FlightWaypointType.LOITER, FlightWaypointType.LOITER,
position.x, position,
position.y,
meters(500) if self.is_helo else self.doctrine.rendezvous_altitude, meters(500) if self.is_helo else self.doctrine.rendezvous_altitude,
alt_type, alt_type,
description="Wait until push time", description="Wait until push time",
@ -189,8 +182,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"JOIN", "JOIN",
FlightWaypointType.JOIN, FlightWaypointType.JOIN,
position.x, position,
position.y,
meters(80) if self.is_helo else self.doctrine.ingress_altitude, meters(80) if self.is_helo else self.doctrine.ingress_altitude,
alt_type, alt_type,
description="Rendezvous with package", description="Rendezvous with package",
@ -205,8 +197,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"REFUEL", "REFUEL",
FlightWaypointType.REFUEL, FlightWaypointType.REFUEL,
position.x, position,
position.y,
meters(80) if self.is_helo else self.doctrine.ingress_altitude, meters(80) if self.is_helo else self.doctrine.ingress_altitude,
alt_type, alt_type,
description="Refuel from tanker", description="Refuel from tanker",
@ -221,8 +212,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"SPLIT", "SPLIT",
FlightWaypointType.SPLIT, FlightWaypointType.SPLIT,
position.x, position,
position.y,
meters(80) if self.is_helo else self.doctrine.ingress_altitude, meters(80) if self.is_helo else self.doctrine.ingress_altitude,
alt_type, alt_type,
description="Depart from package", description="Depart from package",
@ -242,8 +232,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"INGRESS", "INGRESS",
ingress_type, ingress_type,
position.x, position,
position.y,
meters(60) if self.is_helo else self.doctrine.ingress_altitude, meters(60) if self.is_helo else self.doctrine.ingress_altitude,
alt_type, alt_type,
description=f"INGRESS on {objective.name}", description=f"INGRESS on {objective.name}",
@ -259,8 +248,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"EGRESS", "EGRESS",
FlightWaypointType.EGRESS, FlightWaypointType.EGRESS,
position.x, position,
position.y,
meters(60) if self.is_helo else self.doctrine.ingress_altitude, meters(60) if self.is_helo else self.doctrine.ingress_altitude,
alt_type, alt_type,
description=f"EGRESS from {target.name}", description=f"EGRESS from {target.name}",
@ -284,8 +272,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
target.name, target.name,
FlightWaypointType.TARGET_POINT, FlightWaypointType.TARGET_POINT,
target.target.position.x, target.target.position,
target.target.position.y,
meters(0), meters(0),
"RADIO", "RADIO",
description=description, description=description,
@ -315,8 +302,7 @@ class WaypointBuilder:
waypoint = FlightWaypoint( waypoint = FlightWaypoint(
name, name,
FlightWaypointType.TARGET_GROUP_LOC, FlightWaypointType.TARGET_GROUP_LOC,
location.position.x, location.position,
location.position.y,
meters(0), meters(0),
"RADIO", "RADIO",
description=name, description=name,
@ -340,8 +326,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"CAS", "CAS",
FlightWaypointType.CAS, FlightWaypointType.CAS,
position.x, position,
position.y,
meters(60) if self.is_helo else meters(1000), meters(60) if self.is_helo else meters(1000),
"RADIO", "RADIO",
description="Provide CAS", description="Provide CAS",
@ -359,8 +344,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"RACETRACK START", "RACETRACK START",
FlightWaypointType.PATROL_TRACK, FlightWaypointType.PATROL_TRACK,
position.x, position,
position.y,
altitude, altitude,
description="Orbit between this point and the next point", description="Orbit between this point and the next point",
pretty_name="Race-track start", pretty_name="Race-track start",
@ -377,8 +361,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"RACETRACK END", "RACETRACK END",
FlightWaypointType.PATROL, FlightWaypointType.PATROL,
position.x, position,
position.y,
altitude, altitude,
description="Orbit between this point and the previous point", description="Orbit between this point and the previous point",
pretty_name="Race-track end", pretty_name="Race-track end",
@ -411,8 +394,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"ORBIT", "ORBIT",
FlightWaypointType.LOITER, FlightWaypointType.LOITER,
start.x, start,
start.y,
altitude, altitude,
description="Anchor and hold at this point", description="Anchor and hold at this point",
pretty_name="Orbit", pretty_name="Orbit",
@ -429,8 +411,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"SWEEP START", "SWEEP START",
FlightWaypointType.INGRESS_SWEEP, FlightWaypointType.INGRESS_SWEEP,
position.x, position,
position.y,
altitude, altitude,
description="Proceed to the target and engage enemy aircraft", description="Proceed to the target and engage enemy aircraft",
pretty_name="Sweep start", pretty_name="Sweep start",
@ -447,8 +428,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"SWEEP END", "SWEEP END",
FlightWaypointType.EGRESS, FlightWaypointType.EGRESS,
position.x, position,
position.y,
altitude, altitude,
description="End of sweep", description="End of sweep",
pretty_name="Sweep end", pretty_name="Sweep end",
@ -491,8 +471,7 @@ class WaypointBuilder:
return ingress_wp, FlightWaypoint( return ingress_wp, FlightWaypoint(
"TARGET", "TARGET",
FlightWaypointType.TARGET_GROUP_LOC, FlightWaypointType.TARGET_GROUP_LOC,
target.position.x, target.position,
target.position.y,
meters(60) if self.is_helo else self.doctrine.ingress_altitude, meters(60) if self.is_helo else self.doctrine.ingress_altitude,
alt_type, alt_type,
description="Escort the package", description="Escort the package",
@ -509,8 +488,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"PICKUP", "PICKUP",
FlightWaypointType.PICKUP, FlightWaypointType.PICKUP,
control_point.position.x, control_point.position,
control_point.position.y,
meters(0), meters(0),
"RADIO", "RADIO",
description=f"Pick up cargo from {control_point}", description=f"Pick up cargo from {control_point}",
@ -527,8 +505,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"DROP OFF", "DROP OFF",
FlightWaypointType.PICKUP, FlightWaypointType.PICKUP,
control_point.position.x, control_point.position,
control_point.position.y,
meters(0), meters(0),
"RADIO", "RADIO",
description=f"Drop off cargo at {control_point}", description=f"Drop off cargo at {control_point}",
@ -554,8 +531,7 @@ class WaypointBuilder:
return FlightWaypoint( return FlightWaypoint(
"NAV", "NAV",
FlightWaypointType.NAV, FlightWaypointType.NAV,
position.x, position,
position.y,
altitude, altitude,
alt_type, alt_type,
description="NAV", description="NAV",
@ -617,4 +593,4 @@ class WaypointBuilder:
deviation = nautical_miles(1) deviation = nautical_miles(1)
x_adj = random.randint(int(-deviation.meters), int(deviation.meters)) x_adj = random.randint(int(-deviation.meters), int(deviation.meters))
y_adj = random.randint(int(-deviation.meters), int(deviation.meters)) y_adj = random.randint(int(-deviation.meters), int(deviation.meters))
return Point(point.x + x_adj, point.y + y_adj) return point + Vector2(x_adj, y_adj)

View File

@ -1,31 +1,30 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING, Any, Optional from typing import Any, Optional, TYPE_CHECKING
from dcs import Point
from faker import Faker from faker import Faker
from game.campaignloader import CampaignAirWingConfig from game.armedforces.armedforces import ArmedForces
from game.ato.airtaaskingorder import AirTaskingOrder
from game.campaignloader.defaultsquadronassigner import DefaultSquadronAssigner from game.campaignloader.defaultsquadronassigner import DefaultSquadronAssigner
from game.commander import TheaterCommander from game.commander import TheaterCommander
from game.commander.missionscheduler import MissionScheduler from game.commander.missionscheduler import MissionScheduler
from game.armedforces.armedforces import ArmedForces
from game.income import Income from game.income import Income
from game.navmesh import NavMesh from game.navmesh import NavMesh
from game.orderedset import OrderedSet from game.orderedset import OrderedSet
from game.profiling import logged_duration, MultiEventTracer from game.procurement import AircraftProcurementRequest, ProcurementAi
from game.profiling import MultiEventTracer, logged_duration
from game.squadrons import AirWing from game.squadrons import AirWing
from game.theater.bullseye import Bullseye
from game.theater.transitnetwork import TransitNetwork, TransitNetworkBuilder
from game.threatzones import ThreatZones from game.threatzones import ThreatZones
from game.transfers import PendingTransfers from game.transfers import PendingTransfers
if TYPE_CHECKING: if TYPE_CHECKING:
from game import Game from game import Game
from game.data.doctrine import Doctrine from game.campaignloader import CampaignAirWingConfig
from game.factions.faction import Faction from game.data.doctrine import Doctrine
from game.procurement import AircraftProcurementRequest, ProcurementAi from game.factions.faction import Faction
from game.theater.bullseye import Bullseye
from game.theater.transitnetwork import TransitNetwork, TransitNetworkBuilder
from game.ato.airtaaskingorder import AirTaskingOrder
class Coalition: class Coalition:
@ -39,7 +38,7 @@ class Coalition:
self.ato = AirTaskingOrder() self.ato = AirTaskingOrder()
self.transit_network = TransitNetwork() self.transit_network = TransitNetwork()
self.procurement_requests: OrderedSet[AircraftProcurementRequest] = OrderedSet() self.procurement_requests: OrderedSet[AircraftProcurementRequest] = OrderedSet()
self.bullseye = Bullseye(Point(0, 0)) self.bullseye = Bullseye(self.game.point_in_world(0, 0))
self.faker = Faker(self.faction.locales) self.faker = Faker(self.faction.locales)
self.air_wing = AirWing(player, game, self.faction) self.air_wing = AirWing(player, game, self.faction)
self.armed_forces = ArmedForces(self.faction) self.armed_forces = ArmedForces(self.faction)

View File

@ -64,6 +64,7 @@ class TheaterState(WorldState["TheaterState"]):
def _rebuild_threat_zones(self) -> None: def _rebuild_threat_zones(self) -> None:
"""Recreates the theater's threat zones based on the current planned state.""" """Recreates the theater's threat zones based on the current planned state."""
self.threat_zones = ThreatZones.for_threats( self.threat_zones = ThreatZones.for_threats(
self.context.theater,
self.context.coalition.opponent.doctrine, self.context.coalition.opponent.doctrine,
barcap_locations=self.enemy_barcaps, barcap_locations=self.enemy_barcaps,
air_defenses=itertools.chain(self.enemy_air_defenses, self.enemy_ships), air_defenses=itertools.chain(self.enemy_air_defenses, self.enemy_ships),

View File

@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
import shapely.ops import shapely.ops
from dcs import Point from dcs import Point
from shapely.geometry import Point as ShapelyPoint, Polygon, MultiPolygon from shapely.geometry import MultiPolygon, Point as ShapelyPoint, Polygon
from game.utils import nautical_miles from game.utils import nautical_miles
@ -29,6 +29,7 @@ class HoldZoneGeometry:
coalition: Coalition, coalition: Coalition,
theater: ConflictTheater, theater: ConflictTheater,
) -> None: ) -> None:
self._target = target
# Hold points are placed one of two ways. Either approach guarantees: # Hold points are placed one of two ways. Either approach guarantees:
# #
# * Safe hold point. # * Safe hold point.
@ -105,4 +106,4 @@ class HoldZoneGeometry:
hold, _ = shapely.ops.nearest_points(self.permissible_zones, self.home) hold, _ = shapely.ops.nearest_points(self.permissible_zones, self.home)
else: else:
hold, _ = shapely.ops.nearest_points(self.preferred_lines, self.join) hold, _ = shapely.ops.nearest_points(self.preferred_lines, self.join)
return Point(hold.x, hold.y) return self._target.new_in_same_map(hold.x, hold.y)

View File

@ -4,9 +4,9 @@ from typing import TYPE_CHECKING
import shapely.ops import shapely.ops
from dcs import Point from dcs import Point
from shapely.geometry import Point as ShapelyPoint, MultiPolygon from shapely.geometry import MultiPolygon, Point as ShapelyPoint
from game.utils import nautical_miles, meters from game.utils import meters, nautical_miles
if TYPE_CHECKING: if TYPE_CHECKING:
from game.coalition import Coalition from game.coalition import Coalition
@ -25,6 +25,7 @@ class IpZoneGeometry:
home: Point, home: Point,
coalition: Coalition, coalition: Coalition,
) -> None: ) -> None:
self._target = target
self.threat_zone = coalition.opponent.threat_zone.all self.threat_zone = coalition.opponent.threat_zone.all
self.home = ShapelyPoint(home.x, home.y) self.home = ShapelyPoint(home.x, home.y)
@ -115,4 +116,4 @@ class IpZoneGeometry:
ip = self._unsafe_ip() ip = self._unsafe_ip()
else: else:
ip = self._safe_ip() ip = self._safe_ip()
return Point(ip.x, ip.y) return self._target.new_in_same_map(ip.x, ip.y)

View File

@ -5,10 +5,10 @@ from typing import TYPE_CHECKING
import shapely.ops import shapely.ops
from dcs import Point from dcs import Point
from shapely.geometry import ( from shapely.geometry import (
MultiLineString,
MultiPolygon,
Point as ShapelyPoint, Point as ShapelyPoint,
Polygon, Polygon,
MultiPolygon,
MultiLineString,
) )
from game.utils import nautical_miles from game.utils import nautical_miles
@ -27,6 +27,7 @@ class JoinZoneGeometry:
def __init__( def __init__(
self, target: Point, home: Point, ip: Point, coalition: Coalition self, target: Point, home: Point, ip: Point, coalition: Coalition
) -> None: ) -> None:
self._target = target
# Normal join placement is based on the path from home to the IP. If no path is # Normal join placement is based on the path from home to the IP. If no path is
# found it means that the target is on a direct path. In that case we instead # found it means that the target is on a direct path. In that case we instead
# want to enforce that the join point is: # want to enforce that the join point is:
@ -100,4 +101,4 @@ class JoinZoneGeometry:
join, _ = shapely.ops.nearest_points(self.permissible_zones, self.ip) join, _ = shapely.ops.nearest_points(self.permissible_zones, self.ip)
else: else:
join, _ = shapely.ops.nearest_points(self.preferred_lines, self.home) join, _ = shapely.ops.nearest_points(self.preferred_lines, self.home)
return Point(join.x, join.y) return self._target.new_in_same_map(join.x, join.y)

View File

@ -143,6 +143,9 @@ class Game:
yield self.blue yield self.blue
yield self.red yield self.red
def point_in_world(self, x: float, y: float) -> Point:
return Point(x, y, self.theater.terrain)
def ato_for(self, player: bool) -> AirTaskingOrder: def ato_for(self, player: bool) -> AirTaskingOrder:
return self.coalition_for(player).ato return self.coalition_for(player).ato
@ -180,9 +183,6 @@ class Game:
def country_for(self, player: bool) -> str: def country_for(self, player: bool) -> str:
return self.coalition_for(player).country_name return self.coalition_for(player).country_name
def bullseye_for(self, player: bool) -> Bullseye:
return self.coalition_for(player).bullseye
@property @property
def neutral_country(self) -> Type[Country]: def neutral_country(self) -> Type[Country]:
"""Return the best fitting country that can be used as neutral faction in the generated mission""" """Return the best fitting country that can be used as neutral faction in the generated mission"""
@ -447,10 +447,7 @@ class Game:
d = cp.position.distance_to_point(cp2.position) d = cp.position.distance_to_point(cp2.position)
if d < min_distance: if d < min_distance:
min_distance = d min_distance = d
cpoint = Point( cpoint = cp.position.midpoint(cp2.position)
(cp.position.x + cp2.position.x) / 2,
(cp.position.y + cp2.position.y) / 2,
)
zones.append(cp.position) zones.append(cp.position)
zones.append(cp2.position) zones.append(cp2.position)
break break
@ -473,7 +470,9 @@ class Game:
self.__culling_zones = zones self.__culling_zones = zones
def add_destroyed_units(self, data: dict[str, Union[float, str]]) -> None: def add_destroyed_units(self, data: dict[str, Union[float, str]]) -> None:
pos = Point(cast(float, data["x"]), cast(float, data["z"])) pos = Point(
cast(float, data["x"]), cast(float, data["z"]), self.theater.terrain
)
if self.theater.is_on_land(pos): if self.theater.is_on_land(pos):
self.__destroyed_units.append(data) self.__destroyed_units.append(data)

View File

@ -3,8 +3,9 @@ import logging
import random import random
from typing import Any, Union from typing import Any, Union
from dcs import Mission, Point from dcs import Mission
from dcs.country import Country from dcs.country import Country
from dcs.mapping import Vector2
from dcs.mission import StartType as DcsStartType from dcs.mission import StartType as DcsStartType
from dcs.planes import F_14A, Su_33 from dcs.planes import F_14A, Su_33
from dcs.point import PointAction from dcs.point import PointAction
@ -139,7 +140,7 @@ class FlightGroupSpawner:
) )
speed = self.flight.state.estimate_speed() speed = self.flight.state.estimate_speed()
pos = self.flight.state.estimate_position() pos = self.flight.state.estimate_position()
pos += Point(random.randint(100, 1000), random.randint(100, 1000)) pos += Vector2(random.randint(100, 1000), random.randint(100, 1000))
alt, alt_type = self.flight.state.estimate_altitude() alt, alt_type = self.flight.state.estimate_altitude()
# We don't know where the ground is, so just make sure that any aircraft # We don't know where the ground is, so just make sure that any aircraft
@ -197,7 +198,7 @@ class FlightGroupSpawner:
alt = WARM_START_ALTITUDE alt = WARM_START_ALTITUDE
speed = GroundSpeed.for_flight(self.flight, alt) speed = GroundSpeed.for_flight(self.flight, alt)
pos = Point(at.x + random.randint(100, 1000), at.y + random.randint(100, 1000)) pos = at + Vector2(random.randint(100, 1000), random.randint(100, 1000))
group = self.mission.flight_group( group = self.mission.flight_group(
country=self.country, country=self.country,

View File

@ -3,10 +3,9 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Any, Iterable, Union from typing import Any, Iterable, Union
from dcs import Mission, Point from dcs import Mission
from dcs.planes import AJS37, F_14B, JF_17 from dcs.planes import AJS37, F_14B, JF_17
from dcs.point import MovingPoint, PointAction from dcs.point import MovingPoint, PointAction
from dcs.unit import Unit
from dcs.unitgroup import FlyingGroup from dcs.unitgroup import FlyingGroup
from game.ato import Flight, FlightWaypoint from game.ato import Flight, FlightWaypoint
@ -41,7 +40,7 @@ class PydcsWaypointBuilder:
def build(self) -> MovingPoint: def build(self) -> MovingPoint:
waypoint = self.group.add_waypoint( waypoint = self.group.add_waypoint(
Point(self.waypoint.x, self.waypoint.y), self.waypoint.position,
self.waypoint.alt.meters, self.waypoint.alt.meters,
name=self.waypoint.name, name=self.waypoint.name,
) )

View File

@ -1,4 +1,5 @@
from dcs import Point import copy
from dcs.planes import B_17G, B_52H, Tu_22M3 from dcs.planes import B_17G, B_52H, Tu_22M3
from dcs.point import MovingPoint from dcs.point import MovingPoint
from dcs.task import Bombing, OptFormation, WeaponType from dcs.task import Bombing, OptFormation, WeaponType
@ -20,12 +21,10 @@ class StrikeIngressBuilder(PydcsWaypointBuilder):
if not targets: if not targets:
return return
center = Point(0, 0) center = copy.copy(targets[0].position)
for target in targets: for target in targets[1:]:
center.x += target.position.x center += target.position
center.y += target.position.y center /= len(targets)
center.x /= len(targets)
center.y /= len(targets)
bombing = Bombing(center, weapon_type=WeaponType.Bombs) bombing = Bombing(center, weapon_type=WeaponType.Bombs)
bombing.params["expend"] = "All" bombing.params["expend"] = "All"
bombing.params["attackQtyLimit"] = False bombing.params["attackQtyLimit"] = False

View File

@ -1,11 +1,9 @@
from datetime import datetime
from dcs import Point from dcs import Point
from dcs.drawing import LineStyle, Rgba from dcs.drawing import LineStyle, Rgba
from dcs.drawing.drawings import StandardLayer from dcs.drawing.drawings import StandardLayer
from dcs.mission import Mission from dcs.mission import Mission
from game import Game, VERSION from game import Game
from game.missiongenerator.frontlineconflictdescription import ( from game.missiongenerator.frontlineconflictdescription import (
FrontLineConflictDescription, FrontLineConflictDescription,
) )
@ -73,7 +71,7 @@ class DrawingsGenerator:
# Add shape to layer # Add shape to layer
shape = self.player_layer.add_line_segments( shape = self.player_layer.add_line_segments(
cp.position, cp.position,
[Point(0, 0)] [Point(0, 0, self.game.theater.terrain)]
+ [p - cp.position for p in convoy_route] + [p - cp.position for p in convoy_route]
+ [destination.position - cp.position], + [destination.position - cp.position],
line_thickness=6, line_thickness=6,

View File

@ -9,7 +9,7 @@ from dcs import Mission
from dcs.action import AITaskPush from dcs.action import AITaskPush
from dcs.condition import GroupLifeLess, Or, TimeAfter, UnitDamaged from dcs.condition import GroupLifeLess, Or, TimeAfter, UnitDamaged
from dcs.country import Country from dcs.country import Country
from dcs.mapping import Point from dcs.mapping import Point, Vector2
from dcs.point import PointAction from dcs.point import PointAction
from dcs.task import ( from dcs.task import (
AFAC, AFAC,
@ -372,7 +372,7 @@ class FlotGenerator:
# Then move forward OR Attack enemy base if it is not too far away # Then move forward OR Attack enemy base if it is not too far away
target = self.find_nearest_enemy_group(dcs_group, enemy_groups) target = self.find_nearest_enemy_group(dcs_group, enemy_groups)
if target is not None: if target is not None:
rand_offset = Point( rand_offset = Vector2(
random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
) )
@ -419,7 +419,7 @@ class FlotGenerator:
# In elimination mode, the units focus on destroying as much enemy groups as possible # In elimination mode, the units focus on destroying as much enemy groups as possible
targets = self.find_n_nearest_enemy_groups(dcs_group, enemy_groups, 3) targets = self.find_n_nearest_enemy_groups(dcs_group, enemy_groups, 3)
for i, target in enumerate(targets, start=1): for i, target in enumerate(targets, start=1):
rand_offset = Point( rand_offset = Vector2(
random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK),
) )

View File

@ -766,7 +766,7 @@ class KneeboardGenerator(MissionInfoGenerator):
pages: List[KneeboardPage] = [ pages: List[KneeboardPage] = [
BriefingPage( BriefingPage(
flight, flight,
self.game.bullseye_for(flight.friendly), self.game.coalition_for(flight.friendly).bullseye,
self.game.theater, self.game.theater,
self.game.conditions.weather, self.game.conditions.weather,
zoned_time, zoned_time,

View File

@ -129,7 +129,7 @@ class MissionGenerator:
"red", bullseye=self.game.red.bullseye.to_pydcs() "red", bullseye=self.game.red.bullseye.to_pydcs()
) )
self.mission.coalition["neutrals"] = Coalition( self.mission.coalition["neutrals"] = Coalition(
"neutrals", bullseye=Bullseye(Point(0, 0)).to_pydcs() "neutrals", bullseye=Bullseye(Point(0, 0, self.mission.terrain)).to_pydcs()
) )
p_country = self.game.blue.country_name p_country = self.game.blue.country_name
@ -295,7 +295,7 @@ class MissionGenerator:
logging.warning(f"Destroyed unit has no type: {d}") logging.warning(f"Destroyed unit has no type: {d}")
continue continue
pos = Point(cast(float, d["x"]), cast(float, d["z"])) pos = Point(cast(float, d["x"]), cast(float, d["z"]), self.mission.terrain)
if utype is not None and not self.game.position_culled(pos): if utype is not None and not self.game.position_culled(pos):
self.mission.static_group( self.mission.static_group(
country=self.mission.country(self.game.blue.country_name), country=self.mission.country(self.game.blue.country_name),

View File

@ -537,8 +537,7 @@ class HelipadGenerator:
country = self.m.country(self.game.coalition_for(self.cp.captured).country_name) country = self.m.country(self.game.coalition_for(self.cp.captured).country_name)
name = self.cp.name + "_helipad" name = self.cp.name + "_helipad"
sg = unitgroup.StaticGroup(self.m.next_group_id(), name) sg = unitgroup.StaticGroup(self.m.next_group_id(), name)
sp = StaticPoint() sp = StaticPoint(self.cp.position)
sp.position = self.cp.position
sg.add_point(sp) sg.add_point(sp)
for i, helipad in enumerate(self.cp.helipads): for i, helipad in enumerate(self.cp.helipads):

View File

@ -46,9 +46,8 @@ class NavPoint:
point: ShapelyPoint point: ShapelyPoint
poly: NavMeshPoly poly: NavMeshPoly
@property def world_point(self, theater: ConflictTheater) -> Point:
def world_point(self) -> Point: return Point(self.point.x, self.point.y, theater.terrain)
return Point(self.point.x, self.point.y)
def __hash__(self) -> int: def __hash__(self) -> int:
return hash(self.poly.ident) return hash(self.poly.ident)
@ -90,8 +89,9 @@ class NavFrontier:
class NavMesh: class NavMesh:
def __init__(self, polys: List[NavMeshPoly]) -> None: def __init__(self, polys: List[NavMeshPoly], theater: ConflictTheater) -> None:
self.polys = polys self.polys = polys
self.theater = theater
def localize(self, point: Point) -> Optional[NavMeshPoly]: def localize(self, point: Point) -> Optional[NavMeshPoly]:
# This is a naive implementation but it's O(n). Runs at about 10k # This is a naive implementation but it's O(n). Runs at about 10k
@ -117,8 +117,8 @@ class NavMesh:
def travel_heuristic(self, a: NavPoint, b: NavPoint) -> float: def travel_heuristic(self, a: NavPoint, b: NavPoint) -> float:
return self.travel_cost(a, b) return self.travel_cost(a, b)
@staticmethod
def reconstruct_path( def reconstruct_path(
self,
came_from: Dict[NavPoint, Optional[NavPoint]], came_from: Dict[NavPoint, Optional[NavPoint]],
origin: NavPoint, origin: NavPoint,
destination: NavPoint, destination: NavPoint,
@ -126,14 +126,14 @@ class NavMesh:
current = destination current = destination
path: List[Point] = [] path: List[Point] = []
while current != origin: while current != origin:
path.append(current.world_point) path.append(current.world_point(self.theater))
previous = came_from[current] previous = came_from[current]
if previous is None: if previous is None:
raise NavMeshError( raise NavMeshError(
f"Could not reconstruct path to {destination} from {origin}" f"Could not reconstruct path to {destination} from {origin}"
) )
current = previous current = previous
path.append(origin.world_point) path.append(origin.world_point(self.theater))
path.reverse() path.reverse()
return path return path
@ -270,4 +270,4 @@ class NavMesh:
# Triangulate the safe-region to build the navmesh. # Triangulate the safe-region to build the navmesh.
navpolys = cls.create_navpolys(triangulate(bounds), threat_zones) navpolys = cls.create_navpolys(triangulate(bounds), threat_zones)
cls.associate_neighbors(navpolys) cls.associate_neighbors(navpolys)
return cls(navpolys) return NavMesh(navpolys, theater)

View File

@ -3,21 +3,19 @@ from __future__ import annotations
import math import math
from dcs import Point from dcs import Point
from dcs.terrain import Terrain
from game.utils import Heading from game.utils import Heading
class PointWithHeading(Point): class PointWithHeading(Point):
def __init__(self) -> None: def __init__(self, x: float, y: float, heading: Heading, terrain: Terrain) -> None:
super(PointWithHeading, self).__init__(0, 0) super().__init__(x, y, terrain)
self.heading: Heading = Heading.from_degrees(0) self.heading: Heading = heading
@staticmethod @staticmethod
def from_point(point: Point, heading: Heading) -> PointWithHeading: def from_point(point: Point, heading: Heading) -> PointWithHeading:
p = PointWithHeading() return PointWithHeading(point.x, point.y, heading, point._terrain)
p.x = point.x
p.y = point.y
p.heading = heading
return p
def rotate(self, origin: Point, heading: Heading) -> None: def rotate(self, origin: Point, heading: Heading) -> None:
"""Rotates the Point by a given angle clockwise around the origin""" """Rotates the Point by a given angle clockwise around the origin"""

View File

@ -17,7 +17,8 @@ class ShapelyUtil:
if poly.is_empty: if poly.is_empty:
return [] return []
return [ return [
theater.point_to_ll(Point(x, y)).as_list() for x, y in poly.exterior.coords Point(x, y, theater.terrain).latlng().as_list()
for x, y in poly.exterior.coords
] ]
@classmethod @classmethod
@ -34,7 +35,7 @@ class ShapelyUtil:
def line_to_leaflet( def line_to_leaflet(
line: LineString, theater: ConflictTheater line: LineString, theater: ConflictTheater
) -> list[LeafletLatLon]: ) -> list[LeafletLatLon]:
return [theater.point_to_ll(Point(x, y)).as_list() for x, y in line.coords] return [Point(x, y, theater.terrain).latlng().as_list() for x, y in line.coords]
@classmethod @classmethod
def lines_to_leaflet( def lines_to_leaflet(

View File

@ -1,6 +1,7 @@
from datetime import timedelta from datetime import timedelta
from uuid import UUID from uuid import UUID
from dcs.mapping import LatLng
from fastapi import APIRouter, Depends, HTTPException, status from fastapi import APIRouter, Depends, HTTPException, status
from game import Game from game import Game
@ -8,7 +9,6 @@ from game.ato.flightwaypoint import FlightWaypoint
from game.ato.flightwaypointtype import FlightWaypointType from game.ato.flightwaypointtype import FlightWaypointType
from game.server import GameContext from game.server import GameContext
from game.server.waypoints.models import FlightWaypointJs from game.server.waypoints.models import FlightWaypointJs
from game.theater import LatLon
from game.utils import meters from game.utils import meters
router: APIRouter = APIRouter(prefix="/waypoints") router: APIRouter = APIRouter(prefix="/waypoints")
@ -23,8 +23,7 @@ def all_waypoints_for_flight(
FlightWaypoint( FlightWaypoint(
"TAKEOFF", "TAKEOFF",
FlightWaypointType.TAKEOFF, FlightWaypointType.TAKEOFF,
flight.departure.position.x, flight.departure.position,
flight.departure.position.y,
meters(0), meters(0),
"RADIO", "RADIO",
), ),
@ -40,7 +39,7 @@ def all_waypoints_for_flight(
def set_position( def set_position(
flight_id: UUID, flight_id: UUID,
waypoint_idx: int, waypoint_idx: int,
position: LatLon, position: LatLng,
game: Game = Depends(GameContext.get), game: Game = Depends(GameContext.get),
) -> None: ) -> None:
flight = game.db.flights.get(flight_id) flight = game.db.flights.get(flight_id)
@ -48,9 +47,7 @@ def set_position(
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
waypoint = flight.flight_plan.waypoints[waypoint_idx - 1] waypoint = flight.flight_plan.waypoints[waypoint_idx - 1]
point = game.theater.ll_to_point(position) waypoint.position = game.theater.ll_to_point(position)
waypoint.x = point.x
waypoint.y = point.y
package_model = ( package_model = (
GameContext.get_model() GameContext.get_model()
.ato_model_for(flight.blue) .ato_model_for(flight.blue)

View File

@ -5,10 +5,10 @@ from typing import Dict, TYPE_CHECKING
from dcs import Point from dcs import Point
from game.theater import LatLon from .latlon import LatLon
if TYPE_CHECKING: if TYPE_CHECKING:
from game.theater import ConflictTheater from .conflicttheater import ConflictTheater
@dataclass @dataclass

View File

@ -6,7 +6,7 @@ from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Iterator, List, Optional, TYPE_CHECKING, Tuple from typing import Any, Dict, Iterator, List, Optional, TYPE_CHECKING, Tuple
from dcs.mapping import Point from dcs.mapping import LatLng, Point
from dcs.terrain import ( from dcs.terrain import (
caucasus, caucasus,
marianaislands, marianaislands,
@ -147,8 +147,8 @@ class ConflictTheater:
min_distance = distance min_distance = distance
nearest_point = pt nearest_point = pt
assert isinstance(nearest_point, geometry.Point) assert isinstance(nearest_point, geometry.Point)
point = Point(point.x, point.y) point = Point(point.x, point.y, self.terrain)
nearest_point = Point(nearest_point.x, nearest_point.y) nearest_point = Point(nearest_point.x, nearest_point.y, self.terrain)
new_point = point.point_from_heading( new_point = point.point_from_heading(
point.heading_between_point(nearest_point), point.heading_between_point(nearest_point),
point.distance_to_point(nearest_point) + extend_dist, point.distance_to_point(nearest_point) + extend_dist,
@ -261,9 +261,8 @@ class ConflictTheater:
lat, lon = self.point_to_ll_transformer.transform(point.x, point.y) lat, lon = self.point_to_ll_transformer.transform(point.x, point.y)
return LatLon(lat, lon) return LatLon(lat, lon)
def ll_to_point(self, ll: LatLon) -> Point: def ll_to_point(self, ll: LatLng) -> Point:
x, y = self.ll_to_point_transformer.transform(ll.lat, ll.lng) return Point.from_latlng(ll, self.terrain)
return Point(x, y)
def heading_to_conflict_from(self, position: Point) -> Optional[Heading]: def heading_to_conflict_from(self, position: Point) -> Optional[Heading]:
# Heading for a Group to the enemy. # Heading for a Group to the enemy.
@ -281,9 +280,8 @@ class ConflictTheater:
] ]
last = len(sorted_conflicts) - 1 last = len(sorted_conflicts) - 1
conflict_center = Point( conflict_center = sorted_conflicts[0].position.midpoint(
(sorted_conflicts[0].position.x + sorted_conflicts[last].position.x) / 2, sorted_conflicts[last].position
(sorted_conflicts[0].position.y + sorted_conflicts[last].position.y) / 2,
) )
return Heading.from_degrees(position.heading_between_point(conflict_center)) return Heading.from_degrees(position.heading_between_point(conflict_center))

View File

@ -7,8 +7,8 @@ from dataclasses import dataclass, field
from enum import Enum, auto from enum import Enum, auto
from typing import Dict, Iterator, List, Optional, Set, Tuple from typing import Dict, Iterator, List, Optional, Set, Tuple
from game.theater import ConflictTheater from .conflicttheater import ConflictTheater
from game.theater.controlpoint import ControlPoint from .controlpoint import ControlPoint
class NoPathError(RuntimeError): class NoPathError(RuntimeError):

View File

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from functools import singledispatchmethod from functools import singledispatchmethod
from typing import Optional, TYPE_CHECKING, Union, Iterable from typing import Iterable, Optional, TYPE_CHECKING, Union
from dcs.mapping import Point as DcsPoint from dcs.mapping import Point as DcsPoint
from shapely.geometry import ( from shapely.geometry import (
@ -13,11 +13,16 @@ from shapely.geometry import (
from shapely.geometry.base import BaseGeometry from shapely.geometry.base import BaseGeometry
from shapely.ops import nearest_points, unary_union from shapely.ops import nearest_points, unary_union
from game.data.doctrine import Doctrine
from game.theater import ControlPoint, MissionTarget, TheaterGroundObject
from game.utils import Distance, meters, nautical_miles
from game.ato.closestairfields import ObjectiveDistanceCache
from game.ato import Flight, FlightWaypoint from game.ato import Flight, FlightWaypoint
from game.ato.closestairfields import ObjectiveDistanceCache
from game.data.doctrine import Doctrine
from game.theater import (
ConflictTheater,
ControlPoint,
MissionTarget,
TheaterGroundObject,
)
from game.utils import Distance, meters, nautical_miles
if TYPE_CHECKING: if TYPE_CHECKING:
from game import Game from game import Game
@ -29,10 +34,12 @@ ThreatPoly = Union[MultiPolygon, Polygon]
class ThreatZones: class ThreatZones:
def __init__( def __init__(
self, self,
theater: ConflictTheater,
airbases: ThreatPoly, airbases: ThreatPoly,
air_defenses: ThreatPoly, air_defenses: ThreatPoly,
radar_sam_threats: ThreatPoly, radar_sam_threats: ThreatPoly,
) -> None: ) -> None:
self.theater = theater
self.airbases = airbases self.airbases = airbases
self.air_defenses = air_defenses self.air_defenses = air_defenses
self.radar_sam_threats = radar_sam_threats self.radar_sam_threats = radar_sam_threats
@ -42,7 +49,7 @@ class ThreatZones:
boundary, _ = nearest_points( boundary, _ = nearest_points(
self.all.boundary, self.dcs_to_shapely_point(point) self.all.boundary, self.dcs_to_shapely_point(point)
) )
return DcsPoint(boundary.x, boundary.y) return DcsPoint(boundary.x, boundary.y, self.theater.terrain)
def distance_to_threat(self, point: DcsPoint) -> Distance: def distance_to_threat(self, point: DcsPoint) -> Distance:
boundary = self.closest_boundary(point) boundary = self.closest_boundary(point)
@ -200,12 +207,13 @@ class ThreatZones:
air_defenses.extend(control_point.ground_objects) air_defenses.extend(control_point.ground_objects)
return cls.for_threats( return cls.for_threats(
game.faction_for(player).doctrine, air_threats, air_defenses game.theater, game.faction_for(player).doctrine, air_threats, air_defenses
) )
@classmethod @classmethod
def for_threats( def for_threats(
cls, cls,
theater: ConflictTheater,
doctrine: Doctrine, doctrine: Doctrine,
barcap_locations: Iterable[ControlPoint], barcap_locations: Iterable[ControlPoint],
air_defenses: Iterable[TheaterGroundObject], air_defenses: Iterable[TheaterGroundObject],
@ -213,6 +221,7 @@ class ThreatZones:
"""Generates the threat zones projected by the given locations. """Generates the threat zones projected by the given locations.
Args: Args:
theater: The theater the threat zones are in.
doctrine: The doctrine of the owning coalition. doctrine: The doctrine of the owning coalition.
barcap_locations: The locations that will be considered for BARCAP planning. barcap_locations: The locations that will be considered for BARCAP planning.
air_defenses: TGOs that may have air defenses. air_defenses: TGOs that may have air defenses.
@ -245,7 +254,8 @@ class ThreatZones:
threat_zone = point.buffer(threat_range.meters) threat_zone = point.buffer(threat_range.meters)
radar_sam_threats.append(threat_zone) radar_sam_threats.append(threat_zone)
return cls( return ThreatZones(
theater,
airbases=unary_union(air_threats), airbases=unary_union(air_threats),
air_defenses=unary_union(air_defense_threats), air_defenses=unary_union(air_defense_threats),
radar_sam_threats=unary_union(radar_sam_threats), radar_sam_threats=unary_union(radar_sam_threats),

View File

@ -1,14 +1,14 @@
from PySide2.QtGui import QStandardItem, QStandardItemModel from PySide2.QtGui import QStandardItem, QStandardItemModel
from game import Game from game import Game
from game.theater.controlpoint import ControlPointType from game.ato.flightwaypoint import FlightWaypoint
from game.theater.theatergroundobject import IadsGroundObject, BuildingGroundObject from game.ato.flightwaypointtype import FlightWaypointType
from game.utils import Distance
from game.missiongenerator.frontlineconflictdescription import ( from game.missiongenerator.frontlineconflictdescription import (
FrontLineConflictDescription, FrontLineConflictDescription,
) )
from game.ato.flightwaypointtype import FlightWaypointType from game.theater.controlpoint import ControlPointType
from game.ato.flightwaypoint import FlightWaypoint from game.theater.theatergroundobject import BuildingGroundObject, IadsGroundObject
from game.utils import Distance
from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
@ -72,10 +72,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
front_line, self.game.theater front_line, self.game.theater
)[0] )[0]
wpt = FlightWaypoint( wpt = FlightWaypoint(
FlightWaypointType.CUSTOM, FlightWaypointType.CUSTOM, pos, Distance.from_meters(800)
pos.x,
pos.y,
Distance.from_meters(800),
) )
wpt.name = f"Frontline {front_line.name} [CAS]" wpt.name = f"Frontline {front_line.name} [CAS]"
wpt.alt_type = "RADIO" wpt.alt_type = "RADIO"
@ -94,8 +91,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
): ):
wpt = FlightWaypoint( wpt = FlightWaypoint(
FlightWaypointType.CUSTOM, FlightWaypointType.CUSTOM,
ground_object.position.x, ground_object.position,
ground_object.position.y,
Distance.from_meters(0), Distance.from_meters(0),
) )
wpt.alt_type = "RADIO" wpt.alt_type = "RADIO"
@ -122,8 +118,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
for j, u in enumerate(g.units): for j, u in enumerate(g.units):
wpt = FlightWaypoint( wpt = FlightWaypoint(
FlightWaypointType.CUSTOM, FlightWaypointType.CUSTOM,
u.position.x, u.position,
u.position.y,
Distance.from_meters(0), Distance.from_meters(0),
) )
wpt.alt_type = "RADIO" wpt.alt_type = "RADIO"
@ -151,10 +146,7 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
self.include_friendly and cp.captured self.include_friendly and cp.captured
): ):
wpt = FlightWaypoint( wpt = FlightWaypoint(
FlightWaypointType.CUSTOM, FlightWaypointType.CUSTOM, cp.position, Distance.from_meters(0)
cp.position.x,
cp.position.y,
Distance.from_meters(0),
) )
wpt.alt_type = "RADIO" wpt.alt_type = "RADIO"
wpt.name = cp.name wpt.name = cp.name

View File

@ -4,9 +4,10 @@ from typing import Optional
from PySide2.QtCore import Property, QObject, Signal, Slot from PySide2.QtCore import Property, QObject, Signal, Slot
from dcs import Point from dcs import Point
from dcs.mapping import LatLng
from game.server.leaflet import LeafletLatLon from game.server.leaflet import LeafletLatLon
from game.theater import ConflictTheater, ControlPoint, ControlPointStatus, LatLon from game.theater import ConflictTheater, ControlPoint, ControlPointStatus
from game.utils import meters, nautical_miles from game.utils import meters, nautical_miles
from qt_ui.dialogs import Dialog from qt_ui.dialogs import Dialog
from qt_ui.models import GameModel from qt_ui.models import GameModel
@ -83,7 +84,7 @@ class ControlPointJs(QObject):
@Slot(list, result=bool) @Slot(list, result=bool)
def destinationInRange(self, destination: LeafletLatLon) -> bool: def destinationInRange(self, destination: LeafletLatLon) -> bool:
return self.destination_in_range(self.theater.ll_to_point(LatLon(*destination))) return self.destination_in_range(self.theater.ll_to_point(LatLng(*destination)))
@Slot(list, result=str) @Slot(list, result=str)
def setDestination(self, destination: LeafletLatLon) -> str: def setDestination(self, destination: LeafletLatLon) -> str:
@ -92,7 +93,7 @@ class ControlPointJs(QObject):
if not self.control_point.captured: if not self.control_point.captured:
return f"{self.control_point} is not owned by player" return f"{self.control_point} is not owned by player"
point = self.theater.ll_to_point(LatLon(*destination)) point = self.theater.ll_to_point(LatLng(*destination))
if not self.destination_in_range(point): if not self.destination_in_range(point):
return ( return (
f"Cannot move {self.control_point} more than " f"Cannot move {self.control_point} more than "

View File

@ -32,7 +32,7 @@ pluggy==1.0.0
pre-commit==2.17.0 pre-commit==2.17.0
py==1.11.0 py==1.11.0
pydantic==1.9.0 pydantic==1.9.0
-e git+https://github.com/pydcs/dcs@63863a88e0a43cb0a310dbab3ce2c7800a099dbb#egg=pydcs -e git+https://github.com/DanAlbert/dcs@e652979adefca9f4358244cf9e42985ef58e9343#egg=pydcs
pyinstaller==4.9 pyinstaller==4.9
pyinstaller-hooks-contrib==2022.1 pyinstaller-hooks-contrib==2022.1
pyparsing==3.0.7 pyparsing==3.0.7