Plan waypoint TOTs.

Also fixes the CAP racetracks so the AI actually stays on station.

Waypoint TOT assignment happens at mission generation time for the
sake of the UI. It's a bit messy since we have the late-initialized
field in FlightWaypoint, but on the other hand we don't have to reset
every extant waypoint whenever the player adjusts the mission's TOT.

If we want to clean this up a bit more, we could have two distinct
types for waypoints: one for the planning stage and one with the
resolved TOTs. We already do some thing like this with Flight vs
FlightData.

Future improvements:

* Estimate the group's ground speed so we don't need such wide margins
  of error.
* Delay takeoff to cut loiter fuel cost.
* Plan mission TOT based on the aircraft in the package and their
  travel times to the objective.
* Tune target area time prediction. Flights often don't need to travel
  all the way to the target point, and probably won't be doing it
  slowly, so the current planning causes a lot of extra time spent in
  enemy territory.
* Per-flight TOT offsets from the package to allow a sweep to arrive
  before the rest, etc.
This commit is contained in:
Dan Albert
2020-10-05 23:07:37 -07:00
parent 7abe32be5c
commit b5e5a3b2da
12 changed files with 782 additions and 226 deletions

View File

@@ -1,4 +1,6 @@
"""Qt data models for game objects."""
import datetime
from enum import auto, IntEnum
from typing import Any, Callable, Dict, Iterator, TypeVar, Optional
from PySide2.QtCore import (
@@ -156,6 +158,9 @@ class PackageModel(QAbstractListModel):
"""Returns the flight located at the given index."""
return self.package.flights[index.row()]
def update_tot(self, tot: int) -> None:
self.package.time_over_target = tot
@property
def mission_target(self) -> MissionTarget:
"""Returns the mission target of the package."""
@@ -178,6 +183,8 @@ class PackageModel(QAbstractListModel):
class AtoModel(QAbstractListModel):
"""The model for an AirTaskingOrder."""
PackageRole = Qt.UserRole
def __init__(self, game: Optional[Game], ato: AirTaskingOrder) -> None:
super().__init__()
self.game = game
@@ -190,9 +197,11 @@ class AtoModel(QAbstractListModel):
def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any:
if not index.isValid():
return None
package = self.ato.packages[index.row()]
if role == Qt.DisplayRole:
package = self.ato.packages[index.row()]
return f"{package.package_description} {package.target.name}"
elif role == AtoModel.PackageRole:
return package
return None
def add_package(self, package: Package) -> None: