Dan Albert 96a5a8e2ef
Move FlightPlan ownership from Flight to IBuilder.
The next step in splitting up the layout and scheduling phases. This
facilitates splitting flights into two classes where one has a full
flight plan, but one used in the earlier phases of planning has only a
layout. Layout-only flights won't need TOTs, which will make them much
easier to work with once we've migrated TOTs from timedeltas to
datetimes.

Layout-only flights of course aren't actually usable, but it lets us
avoid dealing with the current sim time until we're certain the Flight
will even survive planning.

I'm not actually sure if we'll be able to split the two phases any more,
but this ends up being a nice cleanup anyway.
2022-09-03 19:13:23 +02:00

83 lines
2.4 KiB
Python

from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Generic, TYPE_CHECKING, TypeVar
from game.navmesh import NavMeshError
from .flightplan import FlightPlan, Layout
from .planningerror import PlanningError
from ..packagewaypoints import PackageWaypoints
if TYPE_CHECKING:
from game.coalition import Coalition
from game.data.doctrine import Doctrine
from game.theater import ConflictTheater
from game.threatzones import ThreatZones
from ..flight import Flight
from ..package import Package
FlightPlanT = TypeVar("FlightPlanT", bound=FlightPlan[Any])
LayoutT = TypeVar("LayoutT", bound=Layout)
class IBuilder(ABC, Generic[FlightPlanT, LayoutT]):
def __init__(self, flight: Flight) -> None:
self.flight = flight
self._flight_plan: FlightPlanT | None = None
def get_or_build(self) -> FlightPlanT:
if self._flight_plan is None:
self.regenerate()
assert self._flight_plan is not None
return self._flight_plan
def regenerate(self) -> None:
try:
self._generate_package_waypoints_if_needed()
self._flight_plan = self.build()
except NavMeshError as ex:
color = "blue" if self.flight.squadron.player else "red"
raise PlanningError(
f"Could not plan {color} {self.flight.flight_type.value} from "
f"{self.flight.departure} to {self.package.target}"
) from ex
def _generate_package_waypoints_if_needed(self) -> None:
if self.package.waypoints is None:
self.package.waypoints = PackageWaypoints.create(
self.package, self.coalition
)
@property
def theater(self) -> ConflictTheater:
return self.flight.departure.theater
@abstractmethod
def layout(self) -> LayoutT:
...
@abstractmethod
def build(self) -> FlightPlanT:
...
@property
def package(self) -> Package:
return self.flight.package
@property
def coalition(self) -> Coalition:
return self.flight.coalition
@property
def is_player(self) -> bool:
return self.coalition.player
@property
def doctrine(self) -> Doctrine:
return self.coalition.doctrine
@property
def threat_zones(self) -> ThreatZones:
return self.coalition.opponent.threat_zone