mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Compare commits
1 Commits
v1.3.1
...
feature/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87b630f8d5 |
@@ -2,7 +2,7 @@
|
||||
|
||||
(Github Readme Banner and Splash screen Artwork by Andriy Dankovych, CC BY-SA 4.0)
|
||||
|
||||
[](https://patreon.com/dcsliberation)
|
||||
[](https://patreon.com/khopa)
|
||||
|
||||
[](https://github.com/dcs-retribution/dcs-retribution/releases)
|
||||
|
||||
|
||||
18
changelog.md
18
changelog.md
@@ -1,11 +1,3 @@
|
||||
# Retribution v1.3.1
|
||||
#### Note: Re-save your missions in DCS' Mission Editor to avoid possible crashes due to datalink (usually the case when F-16C blk50s are used) when hosting missions on a dedicated server.
|
||||
|
||||
## Fixes
|
||||
* **[UX]** Fix save-compatibility issue
|
||||
* **[UX]** Avoid crash on startup due to incompatible save
|
||||
|
||||
|
||||
# Retribution v1.3.0
|
||||
#### Note: Re-save your missions in DCS' Mission Editor to avoid possible crashes due to datalink (usually the case when F-16C blk50s are used) when hosting missions on a dedicated server.
|
||||
|
||||
@@ -23,8 +15,6 @@
|
||||
* **[Modding]** Updated support for F-4B/C Phantom mod to 2.8.7.204
|
||||
* **[Modding]** Updated Community A-4E-C mod version support to 2.2.0 release.
|
||||
* **[Modding]** Added F/A-18E/F Super Hornet AI Tanker mod support (Chiller Juice Studios SuperBug Tanker AI version 1.4)
|
||||
* **[Modding]** Added VSN Super Étendard mod support (v2.5.5)
|
||||
* **[Modding]** Added F9F Panther mod support (version v2.8.7.101)
|
||||
* **[Modding]** Updated Irondome support to IDF Assets Pack V1.1, adding support for the David's Sling
|
||||
* **[Radios]** Added HF-FM band for AN/ARC-222
|
||||
* **[Radios]** Ability to define preset channels for radios on squadron level (for human pilots only)
|
||||
@@ -51,12 +41,7 @@
|
||||
* **[Config]** Preference setting to use custom Liberation payloads instead of prioritizing Retribution's default
|
||||
* **[Config]** Preference setting to configure the server-port on which Retribution's back-end will run
|
||||
* **[Options]** Made AI jettisoning empty fuel tanks optional (disabled by default)
|
||||
* **[Options]** Add option (so it can be disabled when fixed in DCS) to force air-starts (except for the slots that work) at Nevatim due to https://forum.dcs.world/topic/335545-29-nevatim-ramp-starts-still-bugged/
|
||||
* **[Cheat]** Add cheat option to manually manage REDFOR's TGOs
|
||||
* **[UX]** Buy/Replace TGOs for free before the campaign has started
|
||||
* **[Data]** Ability to define "cruise" & "combat" altitudes for airplanes
|
||||
* **[Options]** Option to randomize altitudes for flights with airplanes
|
||||
* **[Options]** Options to configure/override maximum mission distance for airplanes & helicopters
|
||||
* **[Options]** Add option (so it can be disabled when fixed in DCS) to force air-starts (except for the slots that work) at Nevatim due to https://forum.dcs.world/topic/335545-29-nevatim-ramp-starts-still-bugged/.
|
||||
|
||||
## Fixes
|
||||
* **[Mission Generation]** Anti-ship strikes should use "group attack" in their attack-task
|
||||
@@ -282,7 +267,6 @@ BAI/ANTISHIP/DEAD/STRIKE/BARCAP/CAS/OCA/AIR-ASSAULT (main) missions
|
||||
* **[UI]** Fixed flight properties UI to support F-15E S4+ laser codes.
|
||||
* **[UI]** Fixed UI bug where altering an "ahead of package" TOT offset would change the offset back to a "behind pacakge" offset.
|
||||
* **[UI]** Fixed bug where changing TOT offsets could result in flight startup times that are in the past.
|
||||
* **[UI]** Flight plan paths are now drawn behind all other map elements, fixing rare cases where they could prevent other UI elements from being clickable.
|
||||
|
||||
# 8.1.0
|
||||
|
||||
|
||||
16
client/package-lock.json
generated
16
client/package-lock.json
generated
@@ -6885,9 +6885,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001596",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001596.tgz",
|
||||
"integrity": "sha512-zpkZ+kEr6We7w63ORkoJ2pOfBwBkY/bJrG/UZ90qNb45Isblu8wzDgevEOrRL1r9dWayHjYiiyCMEXPn4DweGQ==",
|
||||
"version": "1.0.30001450",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz",
|
||||
"integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -6897,10 +6897,6 @@
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -26058,9 +26054,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001596",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001596.tgz",
|
||||
"integrity": "sha512-zpkZ+kEr6We7w63ORkoJ2pOfBwBkY/bJrG/UZ90qNb45Isblu8wzDgevEOrRL1r9dWayHjYiiyCMEXPn4DweGQ==",
|
||||
"version": "1.0.30001450",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz",
|
||||
"integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==",
|
||||
"dev": true
|
||||
},
|
||||
"case-sensitive-paths-webpack-plugin": {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Flight } from "../../api/liberationApi";
|
||||
import { useGetCommitBoundaryForFlightQuery } from "../../api/liberationApi";
|
||||
import WaypointMarker from "../waypointmarker";
|
||||
import { Polyline as LPolyline } from "leaflet";
|
||||
import { ReactElement, useEffect, useRef } from "react";
|
||||
import { ReactElement } from "react";
|
||||
import { Polyline } from "react-leaflet";
|
||||
|
||||
const BLUE_PATH = "#0084ff";
|
||||
@@ -28,44 +27,16 @@ const pathColor = (props: FlightPlanProps) => {
|
||||
function FlightPlanPath(props: FlightPlanProps) {
|
||||
const color = pathColor(props);
|
||||
const waypoints = props.flight.waypoints;
|
||||
|
||||
const polylineRef = useRef<LPolyline | null>(null);
|
||||
|
||||
// Flight paths should be drawn under everything else. There seems to be an
|
||||
// issue where `interactive: false` doesn't do as its told (there's nuance,
|
||||
// see the bug for details). It looks better if we draw the other elements on
|
||||
// top of the flight plans anyway, so just push the flight plan to the back.
|
||||
//
|
||||
// https://github.com/dcs-liberation/dcs_liberation/issues/3295
|
||||
//
|
||||
// It's not possible to z-index a polyline (and leaflet says it never will be,
|
||||
// because this is a limitation of SVG, not leaflet:
|
||||
// https://github.com/Leaflet/Leaflet/issues/185), so we need to use
|
||||
// bringToBack() to push the flight paths to the back of the drawing once
|
||||
// they've been added to the map. They'll still draw on top of the map, but
|
||||
// behind everything than was added before them. Anything added after always
|
||||
// goes on top.
|
||||
useEffect(() => {
|
||||
if (props.selected) {
|
||||
polylineRef.current?.bringToFront();
|
||||
}
|
||||
else {
|
||||
polylineRef.current?.bringToBack();
|
||||
}
|
||||
});
|
||||
|
||||
if (waypoints == null) {
|
||||
return <></>;
|
||||
}
|
||||
const points = waypoints
|
||||
.filter((waypoint) => waypoint.include_in_path)
|
||||
.map((waypoint) => waypoint.position);
|
||||
|
||||
return (
|
||||
<Polyline
|
||||
positions={points}
|
||||
pathOptions={{ color: color, interactive: false }}
|
||||
ref={polylineRef}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -95,12 +95,8 @@ describe("FlightPlansLayer", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// For some reason passing ref to PolyLine causes it and its group to be
|
||||
// redrawn, so these numbers don't match what you'd expect from the test.
|
||||
// It probably needs to be rewritten without mocks.
|
||||
expect(mockPolyline).toHaveBeenCalledTimes(3);
|
||||
expect(mockLayerGroup).toBeCalledTimes(2);
|
||||
expect(mockPolyline).toHaveBeenCalledTimes(2);
|
||||
expect(mockLayerGroup).toBeCalledTimes(1);
|
||||
});
|
||||
it("are not drawn if wrong coalition", () => {
|
||||
renderWithProviders(<FlightPlansLayer blue={true} />, {
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
project = "DCS Retribution"
|
||||
copyright = "2023, DCS Retribution Team"
|
||||
author = "DCS Retribution Team"
|
||||
release = "1.3.1"
|
||||
project = "DCS Liberation"
|
||||
copyright = "2023, DCS Liberation Team"
|
||||
author = "DCS Liberation Team"
|
||||
release = "7.0.0"
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import uuid
|
||||
from collections.abc import Iterator
|
||||
from datetime import datetime, timedelta
|
||||
@@ -10,7 +9,6 @@ from dcs import Point
|
||||
from dcs.planes import C_101CC, C_101EB, Su_33, FA_18C_hornet
|
||||
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.theater import ControlPoint, MissionTarget
|
||||
from pydcs_extensions.hercules.hercules import Hercules
|
||||
from .flightmembers import FlightMembers
|
||||
from .flightroster import FlightRoster
|
||||
@@ -35,6 +33,7 @@ if TYPE_CHECKING:
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.sim.simulationresults import SimulationResults
|
||||
from game.squadrons import Squadron, Pilot
|
||||
from game.theater import ControlPoint
|
||||
from game.transfers import TransferOrder
|
||||
from game.data.weapons import WeaponType
|
||||
from .flightmember import FlightMember
|
||||
@@ -124,11 +123,6 @@ class Flight(
|
||||
)
|
||||
)
|
||||
|
||||
# altitude offset for planes
|
||||
offset_factor = self.coalition.game.settings.max_plane_altitude_offset
|
||||
offset_factor = random.randint(0, offset_factor)
|
||||
self.plane_altitude_offset = 1000 * offset_factor * random.choice([-1, 1])
|
||||
|
||||
@property
|
||||
def available_callsigns(self) -> List[str]:
|
||||
callsigns = set()
|
||||
@@ -224,13 +218,6 @@ class Flight(
|
||||
def points(self) -> List[FlightWaypoint]:
|
||||
return self.flight_plan.waypoints[1:]
|
||||
|
||||
@property
|
||||
def custom_targets(self) -> List[MissionTarget]:
|
||||
return [
|
||||
MissionTarget(wpt.name, wpt.position)
|
||||
for wpt in self.flight_plan.layout.custom_waypoints
|
||||
]
|
||||
|
||||
def position(self) -> Point:
|
||||
return self.state.estimate_position()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import Type
|
||||
from game.ato.flightplans.ibuilder import IBuilder
|
||||
from game.ato.flightplans.patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
from game.ato.flightplans.waypointbuilder import WaypointBuilder
|
||||
from game.utils import Distance, Heading, Speed, knots, meters, nautical_miles
|
||||
from game.utils import Distance, Heading, Speed, feet, knots, meters, nautical_miles
|
||||
|
||||
|
||||
class AewcFlightPlan(PatrollingFlightPlan[PatrollingLayout]):
|
||||
@@ -70,7 +70,10 @@ class Builder(IBuilder[AewcFlightPlan, PatrollingLayout]):
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
altitude = builder.get_patrol_altitude
|
||||
if self.flight.unit_type.patrol_altitude is not None:
|
||||
altitude = self.flight.unit_type.patrol_altitude
|
||||
else:
|
||||
altitude = feet(25000)
|
||||
|
||||
racetrack = builder.race_track(racetrack_start, racetrack_end, altitude)
|
||||
|
||||
@@ -87,7 +90,6 @@ class Builder(IBuilder[AewcFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> AewcFlightPlan:
|
||||
|
||||
@@ -49,7 +49,6 @@ class AirAssaultLayout(FormationAttackLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class AirAssaultFlightPlan(FormationAttackFlightPlan, UiZoneDisplay):
|
||||
@@ -112,11 +111,12 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
)
|
||||
assert self.package.waypoints is not None
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
altitude = builder.get_cruise_altitude
|
||||
heli_alt = feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
altitude = heli_alt if self.flight.is_helo else self.doctrine.ingress_altitude
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
if self.flight.is_hercules or self.flight.departure.cptype in [
|
||||
ControlPointType.AIRCRAFT_CARRIER_GROUP,
|
||||
ControlPointType.LHA_GROUP,
|
||||
@@ -133,7 +133,7 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
self._generate_ctld_pickup(),
|
||||
)
|
||||
)
|
||||
pickup.alt = altitude
|
||||
pickup.alt = heli_alt
|
||||
pickup_position = pickup.position
|
||||
|
||||
ingress = builder.ingress(
|
||||
@@ -159,6 +159,8 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
drop_pos = tgt.position.point_from_heading(heading, 1200)
|
||||
drop_off_zone = MissionTarget("Dropoff zone", drop_pos)
|
||||
dz = builder.dropoff_zone(drop_off_zone) if self.flight.is_helo else None
|
||||
if dz:
|
||||
dz.alt = heli_alt
|
||||
|
||||
return AirAssaultLayout(
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
@@ -185,7 +187,6 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
join=builder.join(ingress.position),
|
||||
split=builder.split(self.flight.arrival.position),
|
||||
refuel=None,
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> AirAssaultFlightPlan:
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import Optional
|
||||
from typing import TYPE_CHECKING, Type
|
||||
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.utils import Distance
|
||||
from game.utils import feet, Distance
|
||||
from ._common_ctld import generate_random_ctld_point
|
||||
from .ibuilder import IBuilder
|
||||
from .planningerror import PlanningError
|
||||
@@ -92,7 +92,6 @@ class AirliftLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class AirliftFlightPlan(StandardFlightPlan[AirliftLayout]):
|
||||
@@ -133,11 +132,12 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
|
||||
"Cannot plan transport mission for flight with no cargo."
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
altitude = builder.get_cruise_altitude
|
||||
heli_alt = feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
altitude = heli_alt if self.flight.is_helo else self.doctrine.ingress_altitude
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
pickup_ascent = None
|
||||
pickup_descent = None
|
||||
pickup = None
|
||||
@@ -246,7 +246,6 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> AirliftFlightPlan:
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from datetime import timedelta
|
||||
from typing import Type
|
||||
|
||||
from game.theater import FrontLine
|
||||
from game.utils import Distance, Speed
|
||||
from game.utils import Distance, Speed, feet
|
||||
from .capbuilder import CapBuilder
|
||||
from .invalidobjectivelocation import InvalidObjectiveLocation
|
||||
from .patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
@@ -40,9 +41,14 @@ class Builder(CapBuilder[BarCapFlightPlan, PatrollingLayout]):
|
||||
|
||||
start_pos, end_pos = self.cap_racetrack_for_objective(location, barcap=True)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
patrol_alt = builder.get_patrol_altitude
|
||||
preferred_alt = self.flight.unit_type.preferred_patrol_altitude
|
||||
randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000)
|
||||
patrol_alt = max(
|
||||
self.doctrine.min_patrol_altitude,
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
start, end = builder.race_track(start_pos, end_pos, patrol_alt)
|
||||
|
||||
return PatrollingLayout(
|
||||
@@ -58,7 +64,6 @@ class Builder(CapBuilder[BarCapFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> BarCapFlightPlan:
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Type
|
||||
|
||||
from game.theater import FrontLine
|
||||
from game.utils import Distance, Speed, kph, dcs_to_shapely_point
|
||||
from game.utils import nautical_miles
|
||||
from game.utils import feet, nautical_miles
|
||||
from .ibuilder import IBuilder
|
||||
from .invalidobjectivelocation import InvalidObjectiveLocation
|
||||
from .patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
@@ -37,7 +37,6 @@ class CasLayout(PatrollingLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class CasFlightPlan(PatrollingFlightPlan[CasLayout], UiZoneDisplay):
|
||||
@@ -105,7 +104,11 @@ class Builder(IBuilder[CasFlightPlan, CasLayout]):
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
is_helo = self.flight.unit_type.dcs_unit_type.helicopter
|
||||
ingress_egress_altitude = builder.get_combat_altitude
|
||||
ingress_egress_altitude = (
|
||||
self.doctrine.ingress_altitude
|
||||
if not is_helo
|
||||
else feet(self.coalition.game.settings.heli_combat_alt_agl)
|
||||
)
|
||||
use_agl_patrol_altitude = is_helo
|
||||
|
||||
ip_solver = IpSolver(
|
||||
@@ -164,7 +167,6 @@ class Builder(IBuilder[CasFlightPlan, CasLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> CasFlightPlan:
|
||||
|
||||
@@ -17,6 +17,8 @@ if TYPE_CHECKING:
|
||||
|
||||
@dataclass
|
||||
class CustomLayout(Layout):
|
||||
custom_waypoints: list[FlightWaypoint]
|
||||
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield self.departure
|
||||
yield from self.custom_waypoints
|
||||
|
||||
@@ -11,6 +11,7 @@ from .formationattack import (
|
||||
)
|
||||
from .waypointbuilder import WaypointBuilder
|
||||
from .. import FlightType
|
||||
from ...utils import feet
|
||||
|
||||
|
||||
class EscortFlightPlan(FormationAttackFlightPlan):
|
||||
@@ -42,9 +43,12 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
|
||||
split = builder.split(self._get_split())
|
||||
|
||||
ingress_alt = self.doctrine.ingress_altitude
|
||||
is_helo = builder.flight.is_helo
|
||||
heli_alt = feet(self.coalition.game.settings.heli_combat_alt_agl)
|
||||
initial = builder.escort_hold(
|
||||
target.position if is_helo else self.package.waypoints.initial,
|
||||
min(heli_alt, ingress_alt) if is_helo else ingress_alt,
|
||||
)
|
||||
|
||||
pf = self.package.primary_flight
|
||||
@@ -65,6 +69,9 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
if layout.drop_off:
|
||||
initial = builder.escort_hold(
|
||||
layout.drop_off.position,
|
||||
min(feet(200), ingress_alt)
|
||||
if builder.flight.is_helo
|
||||
else ingress_alt,
|
||||
)
|
||||
|
||||
refuel = self._build_refuel(builder)
|
||||
@@ -73,13 +80,13 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
nav_to = builder.nav_path(
|
||||
hold.position if hold else departure.position,
|
||||
join.position,
|
||||
builder.get_cruise_altitude,
|
||||
self.doctrine.ingress_altitude,
|
||||
)
|
||||
|
||||
nav_from = builder.nav_path(
|
||||
refuel.position if refuel else split.position,
|
||||
self.flight.arrival.position,
|
||||
builder.get_cruise_altitude,
|
||||
self.doctrine.ingress_altitude,
|
||||
)
|
||||
|
||||
return FormationAttackLayout(
|
||||
@@ -96,7 +103,6 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> EscortFlightPlan:
|
||||
|
||||
@@ -24,7 +24,6 @@ class FerryLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class FerryFlightPlan(StandardFlightPlan[FerryLayout]):
|
||||
@@ -61,14 +60,14 @@ class Builder(IBuilder[FerryFlightPlan, FerryLayout]):
|
||||
f"{self.flight.departure}"
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
altitude = (
|
||||
feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if altitude_is_agl
|
||||
else builder.get_patrol_altitude
|
||||
else self.flight.unit_type.preferred_patrol_altitude
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
return FerryLayout(
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
nav_to=builder.nav_path(
|
||||
@@ -81,7 +80,6 @@ class Builder(IBuilder[FerryFlightPlan, FerryLayout]):
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
nav_from=[],
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> FerryFlightPlan:
|
||||
|
||||
@@ -34,7 +34,6 @@ if TYPE_CHECKING:
|
||||
@dataclass
|
||||
class Layout(ABC):
|
||||
departure: FlightWaypoint
|
||||
custom_waypoints: list[FlightWaypoint]
|
||||
|
||||
@property
|
||||
def waypoints(self) -> list[FlightWaypoint]:
|
||||
|
||||
@@ -11,7 +11,7 @@ from dcs import Point
|
||||
|
||||
from game.flightplan import HoldZoneGeometry
|
||||
from game.theater import MissionTarget
|
||||
from game.utils import Speed, meters, nautical_miles
|
||||
from game.utils import Speed, meters, nautical_miles, feet
|
||||
from .flightplan import FlightPlan
|
||||
from .formation import FormationFlightPlan, FormationLayout
|
||||
from .ibuilder import IBuilder
|
||||
@@ -157,7 +157,6 @@ class FormationAttackLayout(FormationLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
FlightPlanT = TypeVar("FlightPlanT", bound=FlightPlan[FormationAttackLayout])
|
||||
@@ -210,10 +209,14 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
if self.flight.flight_type == FlightType.STRIKE:
|
||||
hdg = self.package.target.position.heading_between_point(ingress.position)
|
||||
pos = ingress.position.point_from_heading(hdg, nautical_miles(10).meters)
|
||||
lineup = builder.nav(pos, builder.get_combat_altitude)
|
||||
lineup = builder.nav(pos, self.flight.coalition.doctrine.ingress_altitude)
|
||||
|
||||
is_helo = self.flight.is_helo
|
||||
ingress_egress_altitude = builder.get_combat_altitude
|
||||
ingress_egress_altitude = (
|
||||
self.doctrine.ingress_altitude
|
||||
if not is_helo
|
||||
else feet(self.coalition.game.settings.heli_combat_alt_agl)
|
||||
)
|
||||
use_agl_ingress_egress = is_helo
|
||||
|
||||
return FormationAttackLayout(
|
||||
@@ -241,7 +244,6 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def _build_refuel(self, builder: WaypointBuilder) -> Optional[FlightWaypoint]:
|
||||
|
||||
@@ -25,7 +25,6 @@ class IBuilder(ABC, Generic[FlightPlanT, LayoutT]):
|
||||
def __init__(self, flight: Flight) -> None:
|
||||
self.flight = flight
|
||||
self._flight_plan: FlightPlanT | None = None
|
||||
self.settings = self.flight.coalition.game.settings
|
||||
|
||||
def get_or_build(self) -> FlightPlanT:
|
||||
if self._flight_plan is None:
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import Type
|
||||
|
||||
from dcs import Point
|
||||
|
||||
from game.utils import Distance, Heading, meters
|
||||
from game.utils import Distance, Heading, feet, meters
|
||||
from .ibuilder import IBuilder
|
||||
from .patrolling import PatrollingLayout
|
||||
from .refuelingflightplan import RefuelingFlightPlan
|
||||
@@ -98,7 +98,11 @@ class Builder(IBuilder[PackageRefuelingFlightPlan, PatrollingLayout]):
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
altitude = builder.get_patrol_altitude
|
||||
tanker_type = self.flight.unit_type
|
||||
if tanker_type.patrol_altitude is not None:
|
||||
altitude = tanker_type.patrol_altitude
|
||||
else:
|
||||
altitude = feet(21000)
|
||||
|
||||
racetrack = builder.race_track(racetrack_start, racetrack_end, altitude)
|
||||
|
||||
@@ -115,7 +119,6 @@ class Builder(IBuilder[PackageRefuelingFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> PackageRefuelingFlightPlan:
|
||||
|
||||
@@ -31,7 +31,6 @@ class PatrollingLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
LayoutT = TypeVar("LayoutT", bound=PatrollingLayout)
|
||||
|
||||
@@ -27,7 +27,6 @@ class RtbLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class RtbFlightPlan(StandardFlightPlan[RtbLayout]):
|
||||
@@ -66,13 +65,13 @@ class Builder(IBuilder[RtbFlightPlan, RtbLayout]):
|
||||
current_position = self.flight.state.estimate_position()
|
||||
current_altitude, altitude_reference = self.flight.state.estimate_altitude()
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
altitude = (
|
||||
feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if altitude_is_agl
|
||||
else builder.get_patrol_altitude
|
||||
else self.flight.unit_type.preferred_patrol_altitude
|
||||
)
|
||||
builder = WaypointBuilder(self.flight)
|
||||
abort_point = builder.nav(
|
||||
current_position, current_altitude, altitude_reference == "RADIO"
|
||||
)
|
||||
@@ -92,7 +91,6 @@ class Builder(IBuilder[RtbFlightPlan, RtbLayout]):
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
nav_from=[],
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> RtbFlightPlan:
|
||||
|
||||
@@ -70,9 +70,6 @@ class StandardLayout(Layout, ABC):
|
||||
elif waypoint in self.nav_from:
|
||||
self.nav_from.remove(waypoint)
|
||||
return True
|
||||
elif waypoint in self.custom_waypoints:
|
||||
self.custom_waypoints.remove(waypoint)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ from .formationattack import (
|
||||
from .invalidobjectivelocation import InvalidObjectiveLocation
|
||||
from .waypointbuilder import StrikeTarget
|
||||
from ..flightwaypointtype import FlightWaypointType
|
||||
from ...theater.theatergroup import SceneryUnit
|
||||
|
||||
|
||||
class StrikeFlightPlan(FormationAttackFlightPlan):
|
||||
@@ -29,10 +28,7 @@ class Builder(FormationAttackBuilder[StrikeFlightPlan, FormationAttackLayout]):
|
||||
|
||||
targets: list[StrikeTarget] = []
|
||||
for idx, unit in enumerate(location.strike_targets):
|
||||
name = unit.type.id
|
||||
if isinstance(unit, SceneryUnit):
|
||||
name = unit.name
|
||||
targets.append(StrikeTarget(f"{name} #{idx}", unit))
|
||||
targets.append(StrikeTarget(f"{unit.type.id} #{idx}", unit))
|
||||
|
||||
return self._build(FlightWaypointType.INGRESS_STRIKE, targets)
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ class SweepLayout(LoiterLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class SweepFlightPlan(LoiterFlightPlan):
|
||||
@@ -105,27 +104,26 @@ class Builder(IBuilder[SweepFlightPlan, SweepLayout]):
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
altitude = builder.get_patrol_altitude
|
||||
|
||||
start, end = builder.sweep(start_pos, target, altitude)
|
||||
start, end = builder.sweep(start_pos, target, self.doctrine.ingress_altitude)
|
||||
|
||||
hold = builder.hold(self._hold_point())
|
||||
|
||||
return SweepLayout(
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
hold=hold,
|
||||
nav_to=builder.nav_path(hold.position, start.position, altitude),
|
||||
nav_to=builder.nav_path(
|
||||
hold.position, start.position, self.doctrine.ingress_altitude
|
||||
),
|
||||
nav_from=builder.nav_path(
|
||||
end.position,
|
||||
self.flight.arrival.position,
|
||||
altitude,
|
||||
self.doctrine.ingress_altitude,
|
||||
),
|
||||
sweep_start=start,
|
||||
sweep_end=end,
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def _hold_point(self) -> Point:
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Type
|
||||
|
||||
from game.utils import Distance, Speed
|
||||
from game.utils import Distance, Speed, feet
|
||||
from .capbuilder import CapBuilder
|
||||
from .patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
from .waypointbuilder import WaypointBuilder
|
||||
@@ -30,7 +31,6 @@ class TarCapLayout(PatrollingLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
|
||||
if waypoint == self.refuel:
|
||||
@@ -95,9 +95,14 @@ class Builder(CapBuilder[TarCapFlightPlan, TarCapLayout]):
|
||||
def layout(self) -> TarCapLayout:
|
||||
location = self.package.target
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
patrol_alt = builder.get_patrol_altitude
|
||||
preferred_alt = self.flight.unit_type.preferred_patrol_altitude
|
||||
randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000)
|
||||
patrol_alt = max(
|
||||
self.doctrine.min_patrol_altitude,
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
orbit0p, orbit1p = self.cap_racetrack_for_objective(location, barcap=False)
|
||||
|
||||
start, end = builder.race_track(orbit0p, orbit1p, patrol_alt)
|
||||
@@ -123,7 +128,6 @@ class Builder(CapBuilder[TarCapFlightPlan, TarCapLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> TarCapFlightPlan:
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from datetime import timedelta
|
||||
from typing import Type
|
||||
|
||||
from game.utils import Heading, meters, nautical_miles
|
||||
from game.utils import Heading, feet, meters, nautical_miles
|
||||
from .ibuilder import IBuilder
|
||||
from .patrolling import PatrollingLayout
|
||||
from .refuelingflightplan import RefuelingFlightPlan
|
||||
@@ -58,7 +58,11 @@ class Builder(IBuilder[TheaterRefuelingFlightPlan, PatrollingLayout]):
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
altitude = builder.get_patrol_altitude
|
||||
tanker_type = self.flight.unit_type
|
||||
if tanker_type.patrol_altitude is not None:
|
||||
altitude = tanker_type.patrol_altitude
|
||||
else:
|
||||
altitude = feet(21000)
|
||||
|
||||
racetrack = builder.race_track(racetrack_start, racetrack_end, altitude)
|
||||
|
||||
@@ -75,7 +79,6 @@ class Builder(IBuilder[TheaterRefuelingFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> TheaterRefuelingFlightPlan:
|
||||
|
||||
@@ -26,8 +26,6 @@ from game.theater import (
|
||||
)
|
||||
from game.utils import Distance, meters, nautical_miles, feet
|
||||
|
||||
AGL_TRANSITION_ALT = 5000
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.transfers import MultiGroupTransport
|
||||
from game.theater.theatergroup import TheaterGroup
|
||||
@@ -53,34 +51,11 @@ class WaypointBuilder:
|
||||
self.navmesh = coalition.nav_mesh
|
||||
self.targets = targets
|
||||
self._bullseye = coalition.bullseye
|
||||
self.settings = self.flight.coalition.game.settings
|
||||
|
||||
@property
|
||||
def is_helo(self) -> bool:
|
||||
return self.flight.is_helo
|
||||
|
||||
@property
|
||||
def get_patrol_altitude(self) -> Distance:
|
||||
return self.get_altitude(self.flight.unit_type.preferred_patrol_altitude)
|
||||
|
||||
@property
|
||||
def get_cruise_altitude(self) -> Distance:
|
||||
return self.get_altitude(self.flight.unit_type.preferred_cruise_altitude)
|
||||
|
||||
@property
|
||||
def get_combat_altitude(self) -> Distance:
|
||||
return self.get_altitude(self.flight.unit_type.preferred_combat_altitude)
|
||||
|
||||
def get_altitude(self, alt: Distance) -> Distance:
|
||||
randomized_alt = feet(round(alt.feet + self.flight.plane_altitude_offset))
|
||||
altitude = max(
|
||||
self.doctrine.min_combat_altitude,
|
||||
min(self.doctrine.max_combat_altitude, randomized_alt),
|
||||
)
|
||||
return (
|
||||
feet(self.settings.heli_combat_alt_agl) if self.flight.is_helo else altitude
|
||||
)
|
||||
|
||||
def takeoff(self, departure: ControlPoint) -> FlightWaypoint:
|
||||
"""Create takeoff waypoint for the given arrival airfield or carrier.
|
||||
|
||||
@@ -97,7 +72,9 @@ class WaypointBuilder:
|
||||
"NAV",
|
||||
FlightWaypointType.NAV,
|
||||
position,
|
||||
self.get_cruise_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.rendezvous_altitude,
|
||||
description="Enter theater",
|
||||
pretty_name="Enter theater",
|
||||
)
|
||||
@@ -124,7 +101,9 @@ class WaypointBuilder:
|
||||
"NAV",
|
||||
FlightWaypointType.NAV,
|
||||
position,
|
||||
self.get_cruise_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.rendezvous_altitude,
|
||||
description="Exit theater",
|
||||
pretty_name="Exit theater",
|
||||
)
|
||||
@@ -150,10 +129,14 @@ class WaypointBuilder:
|
||||
return None
|
||||
|
||||
position = divert.position
|
||||
altitude_type: AltitudeReference = "BARO"
|
||||
altitude_type: AltitudeReference
|
||||
if isinstance(divert, OffMapSpawn):
|
||||
altitude = self.get_cruise_altitude
|
||||
altitude_type = "RADIO" if self.is_helo else altitude_type
|
||||
altitude = (
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.rendezvous_altitude
|
||||
)
|
||||
altitude_type = "BARO"
|
||||
else:
|
||||
altitude = meters(0)
|
||||
altitude_type = "RADIO"
|
||||
@@ -183,15 +166,16 @@ class WaypointBuilder:
|
||||
|
||||
def hold(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if self.is_helo:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"HOLD",
|
||||
FlightWaypointType.LOITER,
|
||||
position,
|
||||
# TODO: dedicated altitude setting for holding
|
||||
self.get_cruise_altitude if self.is_helo else self.get_combat_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type,
|
||||
description="Wait until push time",
|
||||
pretty_name="Hold",
|
||||
@@ -199,14 +183,16 @@ class WaypointBuilder:
|
||||
|
||||
def join(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.get_cruise_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if self.is_helo:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"JOIN",
|
||||
FlightWaypointType.JOIN,
|
||||
position,
|
||||
self.get_cruise_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type,
|
||||
description="Rendezvous with package",
|
||||
pretty_name="Join",
|
||||
@@ -214,14 +200,16 @@ class WaypointBuilder:
|
||||
|
||||
def refuel(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.get_cruise_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if self.is_helo:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"REFUEL",
|
||||
FlightWaypointType.REFUEL,
|
||||
position,
|
||||
self.get_cruise_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type,
|
||||
description="Refuel from tanker",
|
||||
pretty_name="Refuel",
|
||||
@@ -229,14 +217,16 @@ class WaypointBuilder:
|
||||
|
||||
def split(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if self.is_helo:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"SPLIT",
|
||||
FlightWaypointType.SPLIT,
|
||||
position,
|
||||
self.get_combat_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type,
|
||||
description="Depart from package",
|
||||
pretty_name="Split",
|
||||
@@ -248,7 +238,7 @@ class WaypointBuilder:
|
||||
position: Point,
|
||||
objective: MissionTarget,
|
||||
) -> FlightWaypoint:
|
||||
alt = self.get_combat_altitude
|
||||
alt = self.doctrine.ingress_altitude
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.flight.is_hercules:
|
||||
alt_type = "RADIO"
|
||||
@@ -257,8 +247,6 @@ class WaypointBuilder:
|
||||
if self.is_helo
|
||||
else feet(1000)
|
||||
)
|
||||
elif alt.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
heading = objective.position.heading_between_point(position)
|
||||
|
||||
@@ -277,14 +265,16 @@ class WaypointBuilder:
|
||||
|
||||
def egress(self, position: Point, target: MissionTarget) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if self.is_helo:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"EGRESS",
|
||||
FlightWaypointType.EGRESS,
|
||||
position,
|
||||
self.get_combat_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type,
|
||||
description=f"EGRESS from {target.name}",
|
||||
pretty_name=f"EGRESS from {target.name}",
|
||||
@@ -322,15 +312,11 @@ class WaypointBuilder:
|
||||
return self._target_area(f"STRIKE {target.name}", target)
|
||||
|
||||
def sead_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return self._target_area(
|
||||
f"SEAD on {target.name}",
|
||||
target,
|
||||
altitude=self.get_combat_altitude,
|
||||
alt_type=alt_type,
|
||||
altitude=self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
)
|
||||
|
||||
def dead_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
@@ -401,13 +387,11 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the racetrack.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"RACETRACK START",
|
||||
FlightWaypointType.PATROL_TRACK,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Orbit between this point and the next point",
|
||||
pretty_name="Race-track start",
|
||||
)
|
||||
@@ -420,13 +404,11 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the racetrack.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"RACETRACK END",
|
||||
FlightWaypointType.PATROL,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Orbit between this point and the previous point",
|
||||
pretty_name="Race-track end",
|
||||
)
|
||||
@@ -454,39 +436,42 @@ class WaypointBuilder:
|
||||
start: Position of the waypoint.
|
||||
altitude: Altitude of the racetrack.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"ORBIT",
|
||||
FlightWaypointType.LOITER,
|
||||
start,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Anchor and hold at this point",
|
||||
pretty_name="Orbit",
|
||||
)
|
||||
|
||||
def sead_search(self, target: MissionTarget) -> FlightWaypoint:
|
||||
hold = self._sead_search_point(target)
|
||||
baro: AltitudeReference = "BARO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"SEAD Search",
|
||||
FlightWaypointType.NAV,
|
||||
hold,
|
||||
self.get_combat_altitude,
|
||||
"RADIO" if self.get_combat_altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
description="Anchor and search from this point",
|
||||
pretty_name="SEAD Search",
|
||||
)
|
||||
|
||||
def sead_sweep(self, target: MissionTarget) -> FlightWaypoint:
|
||||
hold = self._sead_search_point(target)
|
||||
baro: AltitudeReference = "BARO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"SEAD Sweep",
|
||||
FlightWaypointType.NAV,
|
||||
hold,
|
||||
self.get_combat_altitude,
|
||||
"RADIO" if self.get_combat_altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
description="Anchor and search from this point",
|
||||
pretty_name="SEAD Sweep",
|
||||
)
|
||||
@@ -514,16 +499,15 @@ class WaypointBuilder:
|
||||
)
|
||||
return hold
|
||||
|
||||
def escort_hold(self, start: Point) -> FlightWaypoint:
|
||||
def escort_hold(self, start: Point, altitude: Distance) -> FlightWaypoint:
|
||||
"""Creates custom waypoint for escort flights that need to hold.
|
||||
|
||||
Args:
|
||||
start: Position of the waypoint.
|
||||
altitude: Altitude of the holding pattern.
|
||||
"""
|
||||
altitude = self.get_combat_altitude
|
||||
|
||||
alt_type: Literal["BARO", "RADIO"] = "BARO"
|
||||
if self.is_helo or altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if self.is_helo:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
@@ -544,13 +528,11 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the sweep in meters.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"SWEEP START",
|
||||
FlightWaypointType.INGRESS_SWEEP,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Proceed to the target and engage enemy aircraft",
|
||||
pretty_name="Sweep start",
|
||||
)
|
||||
@@ -563,13 +545,11 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the sweep in meters.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"SWEEP END",
|
||||
FlightWaypointType.EGRESS,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="End of sweep",
|
||||
pretty_name="Sweep end",
|
||||
)
|
||||
@@ -598,7 +578,7 @@ class WaypointBuilder:
|
||||
target: The mission target.
|
||||
"""
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if self.is_helo:
|
||||
alt_type = "RADIO"
|
||||
|
||||
# This would preferably be no points at all, and instead the Escort task
|
||||
@@ -612,7 +592,9 @@ class WaypointBuilder:
|
||||
"TARGET",
|
||||
FlightWaypointType.TARGET_GROUP_LOC,
|
||||
target.position,
|
||||
self.get_combat_altitude,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type,
|
||||
description="Escort the package",
|
||||
pretty_name="Target area",
|
||||
@@ -634,19 +616,17 @@ class WaypointBuilder:
|
||||
pretty_name="Pick-up zone",
|
||||
)
|
||||
|
||||
def dropoff_zone(self, drop_off: MissionTarget) -> FlightWaypoint:
|
||||
@staticmethod
|
||||
def dropoff_zone(drop_off: MissionTarget) -> FlightWaypoint:
|
||||
"""Creates a dropoff landing zone waypoint
|
||||
This waypoint is used to generate the Trigger Zone used for AirAssault and
|
||||
AirLift using the CTLD plugin (see LogisticsGenerator)
|
||||
"""
|
||||
heli_alt = feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
altitude = heli_alt if self.flight.is_helo else meters(0)
|
||||
|
||||
return FlightWaypoint(
|
||||
"DROPOFFZONE",
|
||||
FlightWaypointType.DROPOFF_ZONE,
|
||||
drop_off.position,
|
||||
altitude,
|
||||
meters(0),
|
||||
"RADIO",
|
||||
description=f"Drop off cargo at {drop_off.name}",
|
||||
pretty_name="Drop-off zone",
|
||||
@@ -680,7 +660,7 @@ class WaypointBuilder:
|
||||
altitude_is_agl: True for altitude is AGL. False if altitude is MSL.
|
||||
"""
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if altitude_is_agl or altitude.feet <= AGL_TRANSITION_ALT:
|
||||
if altitude_is_agl:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
|
||||
@@ -19,6 +19,7 @@ from game.theater.iadsnetwork.iadsnetwork import IadsNetwork
|
||||
from game.theater.theaterloader import TheaterLoader
|
||||
from game.version import CAMPAIGN_FORMAT_VERSION
|
||||
from .campaignairwingconfig import CampaignAirWingConfig
|
||||
from .campaigncarrierconfig import CampaignCarrierConfig
|
||||
from .campaigngroundconfig import TgoConfig
|
||||
from .mizcampaignloader import MizCampaignLoader
|
||||
|
||||
@@ -140,6 +141,13 @@ class Campaign:
|
||||
return CampaignAirWingConfig({})
|
||||
return CampaignAirWingConfig.from_campaign_data(squadron_data, theater)
|
||||
|
||||
def load_carrier_config(self) -> CampaignCarrierConfig:
|
||||
try:
|
||||
carrier_data = self.data["carriers"]
|
||||
except KeyError:
|
||||
return CampaignCarrierConfig({})
|
||||
return CampaignCarrierConfig.from_campaign_data(carrier_data)
|
||||
|
||||
def load_ground_forces_config(self) -> TgoConfig:
|
||||
ground_forces = self.data.get("ground_forces", {})
|
||||
if not ground_forces:
|
||||
|
||||
42
game/campaignloader/campaigncarrierconfig.py
Normal file
42
game/campaignloader/campaigncarrierconfig.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
from game.dcs.shipunittype import ShipUnitType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CarrierConfig:
|
||||
preferred_name: str
|
||||
preferred_type: ShipUnitType
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, data: dict[str, Any]) -> CarrierConfig:
|
||||
return CarrierConfig(
|
||||
str(data["preferred_name"]), ShipUnitType.named(data["preferred_type"])
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CampaignCarrierConfig:
|
||||
by_original_name: dict[str, CarrierConfig]
|
||||
|
||||
@classmethod
|
||||
def from_campaign_data(
|
||||
cls, data: dict[str, Any]
|
||||
) -> CampaignCarrierConfig:
|
||||
by_original_name: dict[str, CarrierConfig] = defaultdict()
|
||||
for original_name, carrier_config_data in data.items():
|
||||
try:
|
||||
carrier_config = CarrierConfig.from_data(carrier_config_data)
|
||||
by_original_name[original_name] = carrier_config
|
||||
except KeyError:
|
||||
logging.warning(f"Skipping invalid carrier config for '{original_name}'")
|
||||
|
||||
return CampaignCarrierConfig(by_original_name)
|
||||
@@ -38,7 +38,7 @@ class PackageBuilder:
|
||||
self.laser_code_registry = laser_code_registry
|
||||
self.start_type = start_type
|
||||
|
||||
def plan_flight(self, plan: ProposedFlight, ignore_range: bool) -> bool:
|
||||
def plan_flight(self, plan: ProposedFlight) -> bool:
|
||||
"""Allocates aircraft for the given flight and adds them to the package.
|
||||
|
||||
If no suitable aircraft are available, False is returned. If the failed
|
||||
@@ -55,7 +55,6 @@ class PackageBuilder:
|
||||
heli,
|
||||
this_turn=True,
|
||||
preferred_type=plan.preferred_type,
|
||||
ignore_range=ignore_range,
|
||||
)
|
||||
if squadron is None:
|
||||
return False
|
||||
|
||||
@@ -81,9 +81,8 @@ class PackageFulfiller:
|
||||
builder: PackageBuilder,
|
||||
missing_types: Set[FlightType],
|
||||
purchase_multiplier: int,
|
||||
ignore_range: bool = False,
|
||||
) -> None:
|
||||
if not builder.plan_flight(flight, ignore_range):
|
||||
if not builder.plan_flight(flight):
|
||||
pf = builder.package.primary_flight
|
||||
heli = pf.is_helo if pf else False
|
||||
missing_types.add(flight.task)
|
||||
@@ -139,7 +138,6 @@ class PackageFulfiller:
|
||||
purchase_multiplier: int,
|
||||
now: datetime,
|
||||
tracer: MultiEventTracer,
|
||||
ignore_range: bool = False,
|
||||
) -> Optional[Package]:
|
||||
"""Allocates aircraft for a proposed mission and adds it to the ATO."""
|
||||
builder = PackageBuilder(
|
||||
@@ -177,7 +175,6 @@ class PackageFulfiller:
|
||||
builder,
|
||||
missing_types,
|
||||
purchase_multiplier,
|
||||
ignore_range,
|
||||
)
|
||||
|
||||
if missing_types:
|
||||
|
||||
@@ -26,6 +26,8 @@ class Doctrine:
|
||||
strike: bool
|
||||
antiship: bool
|
||||
|
||||
rendezvous_altitude: Distance
|
||||
|
||||
#: The minimum distance between the departure airfield and the hold point.
|
||||
hold_distance: Distance
|
||||
|
||||
@@ -44,14 +46,11 @@ class Doctrine:
|
||||
#: target.
|
||||
min_ingress_distance: Distance
|
||||
|
||||
ingress_altitude: Distance
|
||||
|
||||
min_patrol_altitude: Distance
|
||||
max_patrol_altitude: Distance
|
||||
|
||||
min_cruise_altitude: Distance
|
||||
max_cruise_altitude: Distance
|
||||
|
||||
min_combat_altitude: Distance
|
||||
max_combat_altitude: Distance
|
||||
pattern_altitude: Distance
|
||||
|
||||
#: The duration that CAP flights will remain on-station.
|
||||
cap_duration: timedelta
|
||||
@@ -98,17 +97,16 @@ MODERN_DOCTRINE = Doctrine(
|
||||
sead=True,
|
||||
strike=True,
|
||||
antiship=True,
|
||||
rendezvous_altitude=feet(25000),
|
||||
hold_distance=nautical_miles(25),
|
||||
push_distance=nautical_miles(20),
|
||||
join_distance=nautical_miles(20),
|
||||
max_ingress_distance=nautical_miles(45),
|
||||
min_ingress_distance=nautical_miles(10),
|
||||
ingress_altitude=feet(20000),
|
||||
min_patrol_altitude=feet(15000),
|
||||
max_patrol_altitude=feet(33000),
|
||||
min_cruise_altitude=feet(10000),
|
||||
max_cruise_altitude=feet(40000),
|
||||
min_combat_altitude=feet(1000),
|
||||
max_combat_altitude=feet(35000),
|
||||
pattern_altitude=feet(5000),
|
||||
cap_duration=timedelta(minutes=30),
|
||||
cap_min_track_length=nautical_miles(15),
|
||||
cap_max_track_length=nautical_miles(40),
|
||||
@@ -142,17 +140,16 @@ COLDWAR_DOCTRINE = Doctrine(
|
||||
sead=True,
|
||||
strike=True,
|
||||
antiship=True,
|
||||
rendezvous_altitude=feet(22000),
|
||||
hold_distance=nautical_miles(15),
|
||||
push_distance=nautical_miles(10),
|
||||
join_distance=nautical_miles(10),
|
||||
max_ingress_distance=nautical_miles(30),
|
||||
min_ingress_distance=nautical_miles(10),
|
||||
ingress_altitude=feet(18000),
|
||||
min_patrol_altitude=feet(10000),
|
||||
max_patrol_altitude=feet(24000),
|
||||
min_cruise_altitude=feet(10000),
|
||||
max_cruise_altitude=feet(30000),
|
||||
min_combat_altitude=feet(1000),
|
||||
max_combat_altitude=feet(25000),
|
||||
pattern_altitude=feet(5000),
|
||||
cap_duration=timedelta(minutes=30),
|
||||
cap_min_track_length=nautical_miles(12),
|
||||
cap_max_track_length=nautical_miles(24),
|
||||
@@ -189,14 +186,13 @@ WWII_DOCTRINE = Doctrine(
|
||||
hold_distance=nautical_miles(10),
|
||||
push_distance=nautical_miles(5),
|
||||
join_distance=nautical_miles(5),
|
||||
rendezvous_altitude=feet(10000),
|
||||
max_ingress_distance=nautical_miles(7),
|
||||
min_ingress_distance=nautical_miles(5),
|
||||
ingress_altitude=feet(8000),
|
||||
min_patrol_altitude=feet(4000),
|
||||
max_patrol_altitude=feet(15000),
|
||||
min_cruise_altitude=feet(5000),
|
||||
max_cruise_altitude=feet(30000),
|
||||
min_combat_altitude=feet(1000),
|
||||
max_combat_altitude=feet(10000),
|
||||
pattern_altitude=feet(5000),
|
||||
cap_duration=timedelta(minutes=30),
|
||||
cap_min_track_length=nautical_miles(8),
|
||||
cap_max_track_length=nautical_miles(18),
|
||||
|
||||
@@ -132,21 +132,6 @@ class PatrolConfig:
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AltitudesConfig:
|
||||
cruise: Optional[Distance]
|
||||
combat: Optional[Distance]
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, data: dict[str, Any]) -> AltitudesConfig:
|
||||
cruise = data.get("cruise", None)
|
||||
combat = data.get("combat", None)
|
||||
return AltitudesConfig(
|
||||
feet(cruise) if cruise is not None else None,
|
||||
feet(combat) if combat is not None else None,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FuelConsumption:
|
||||
#: The estimated taxi fuel requirement, in pounds.
|
||||
@@ -197,9 +182,6 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
patrol_altitude: Optional[Distance]
|
||||
patrol_speed: Optional[Speed]
|
||||
|
||||
cruise_altitude: Optional[Distance]
|
||||
combat_altitude: Optional[Distance]
|
||||
|
||||
#: The maximum range between the origin airfield and the target for which the auto-
|
||||
#: planner will consider this aircraft usable for a mission.
|
||||
max_mission_range: Distance
|
||||
@@ -263,13 +245,33 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
def max_speed(self) -> Speed:
|
||||
return kph(self.dcs_unit_type.max_speed)
|
||||
|
||||
@cached_property
|
||||
@property
|
||||
def preferred_patrol_altitude(self) -> Distance:
|
||||
if self.patrol_altitude:
|
||||
if self.patrol_altitude is not None:
|
||||
return self.patrol_altitude
|
||||
else:
|
||||
# TODO: somehow make the upper and lower limit configurable
|
||||
return self.preferred_altitude(10, 33, "patrol")
|
||||
# Estimate based on max speed.
|
||||
# Aircaft with max speed 600 kph will prefer patrol at 10 000 ft
|
||||
# Aircraft with max speed 2800 kph will prefer pratrol at 33 000 ft
|
||||
altitude_for_lowest_speed = feet(10 * 1000)
|
||||
altitude_for_highest_speed = feet(33 * 1000)
|
||||
lowest_speed = kph(600)
|
||||
highest_speed = kph(2800)
|
||||
factor = (self.max_speed - lowest_speed).kph / (
|
||||
highest_speed - lowest_speed
|
||||
).kph
|
||||
altitude = (
|
||||
altitude_for_lowest_speed
|
||||
+ (altitude_for_highest_speed - altitude_for_lowest_speed) * factor
|
||||
)
|
||||
logging.debug(
|
||||
f"Preferred patrol altitude for {self.dcs_unit_type.id}: {altitude.feet}"
|
||||
)
|
||||
rounded_altitude = feet(round(1000 * round(altitude.feet / 1000)))
|
||||
return max(
|
||||
altitude_for_lowest_speed,
|
||||
min(altitude_for_highest_speed, rounded_altitude),
|
||||
)
|
||||
|
||||
def preferred_patrol_speed(self, altitude: Distance) -> Speed:
|
||||
"""Preferred true airspeed when patrolling"""
|
||||
@@ -307,46 +309,6 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
)
|
||||
return min(Speed.from_mach(0.35, altitude), max_speed * 0.5)
|
||||
|
||||
@cached_property
|
||||
def preferred_cruise_altitude(self) -> Distance:
|
||||
if self.cruise_altitude:
|
||||
return self.cruise_altitude
|
||||
else:
|
||||
# TODO: somehow make the upper and lower limit configurable
|
||||
return self.preferred_altitude(20, 20, "cruise")
|
||||
|
||||
@cached_property
|
||||
def preferred_combat_altitude(self) -> Distance:
|
||||
if self.combat_altitude:
|
||||
return self.combat_altitude
|
||||
else:
|
||||
# TODO: somehow make the upper and lower limit configurable
|
||||
return self.preferred_altitude(20, 20, "combat")
|
||||
|
||||
def preferred_altitude(self, low: int, high: int, type: str) -> Distance:
|
||||
# Estimate based on max speed.
|
||||
# Aircraft with max speed 600 kph will prefer low
|
||||
# Aircraft with max speed 2800 kph will prefer high
|
||||
altitude_for_lowest_speed = feet(low * 1000)
|
||||
altitude_for_highest_speed = feet(high * 1000)
|
||||
lowest_speed = kph(600)
|
||||
highest_speed = kph(2800)
|
||||
factor = (self.max_speed - lowest_speed).kph / (
|
||||
highest_speed - lowest_speed
|
||||
).kph
|
||||
altitude = (
|
||||
altitude_for_lowest_speed
|
||||
+ (altitude_for_highest_speed - altitude_for_lowest_speed) * factor
|
||||
)
|
||||
logging.debug(
|
||||
f"Preferred {type} altitude for {self.dcs_unit_type.id}: {altitude.feet}"
|
||||
)
|
||||
rounded_altitude = feet(round(1000 * round(altitude.feet / 1000)))
|
||||
return max(
|
||||
altitude_for_lowest_speed,
|
||||
min(altitude_for_highest_speed, rounded_altitude),
|
||||
)
|
||||
|
||||
def alloc_flight_radio(self, radio_registry: RadioRegistry) -> RadioFrequency:
|
||||
from game.radio.radios import ChannelInUseError, kHz
|
||||
|
||||
@@ -480,7 +442,6 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
|
||||
radio_config = RadioConfig.from_data(data.get("radios", {}))
|
||||
patrol_config = PatrolConfig.from_data(data.get("patrol", {}))
|
||||
altitudes_config = AltitudesConfig.from_data(data.get("altitudes", {}))
|
||||
|
||||
try:
|
||||
mission_range = nautical_miles(int(data["max_range"]))
|
||||
@@ -549,8 +510,6 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
max_group_size=data.get("max_group_size", aircraft.group_size_max),
|
||||
patrol_altitude=patrol_config.altitude,
|
||||
patrol_speed=patrol_config.speed,
|
||||
cruise_altitude=altitudes_config.cruise,
|
||||
combat_altitude=altitudes_config.combat,
|
||||
max_mission_range=mission_range,
|
||||
fuel_consumption=fuel_consumption,
|
||||
default_livery=data.get("default_livery"),
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from functools import cached_property
|
||||
from typing import Optional, Dict, Type, List, Any, Iterator, TYPE_CHECKING, Set
|
||||
@@ -93,8 +94,8 @@ class Faction:
|
||||
# Required mods or asset packs
|
||||
requirements: Dict[str, str] = field(default_factory=dict)
|
||||
|
||||
# Possible carrier names
|
||||
carrier_names: Set[str] = field(default_factory=set)
|
||||
# Possible aircraft carrier units
|
||||
carriers: Dict[ShipUnitType, Set[str]] = field(default_factory=dict)
|
||||
|
||||
# Possible helicopter carrier names
|
||||
helicopter_carrier_names: Set[str] = field(default_factory=set)
|
||||
@@ -241,8 +242,29 @@ class Faction:
|
||||
|
||||
faction.requirements = json.get("requirements", {})
|
||||
|
||||
faction.carrier_names = json.get("carrier_names", [])
|
||||
faction.helicopter_carrier_names = json.get("helicopter_carrier_names", [])
|
||||
# First try to load the carriers in the new format which
|
||||
# specifies different names for different carrier types
|
||||
loaded_carriers = load_carriers(json)
|
||||
|
||||
carriers: List[ShipUnitType] = [
|
||||
unit
|
||||
for unit in faction.naval_units
|
||||
if unit.unit_class
|
||||
in [
|
||||
UnitClass.AIRCRAFT_CARRIER,
|
||||
UnitClass.HELICOPTER_CARRIER,
|
||||
]
|
||||
]
|
||||
carrier_names = json.get("carrier_names", [])
|
||||
for c in carriers:
|
||||
if c.variant_id not in loaded_carriers:
|
||||
if c.unit_class == UnitClass.AIRCRAFT_CARRIER:
|
||||
loaded_carriers[c] = carrier_names
|
||||
elif c.unit_class == UnitClass.HELICOPTER_CARRIER:
|
||||
loaded_carriers[c] = faction.helicopter_carrier_names
|
||||
|
||||
faction.carriers = loaded_carriers
|
||||
faction.naval_units.union(faction.carriers.keys())
|
||||
|
||||
faction.has_jtac = json.get("has_jtac", False)
|
||||
jtac_name = json.get("jtac_unit", None)
|
||||
@@ -340,8 +362,6 @@ class Faction:
|
||||
if not mod_settings.f4bc_phantom:
|
||||
self.remove_aircraft("VSN_F4B")
|
||||
self.remove_aircraft("VSN_F4C")
|
||||
if not mod_settings.f9f_panther:
|
||||
self.remove_aircraft("VSN_F9F")
|
||||
if not mod_settings.f15d_baz:
|
||||
self.remove_aircraft("F-15D")
|
||||
if not mod_settings.f_15_idf:
|
||||
@@ -383,8 +403,6 @@ class Faction:
|
||||
self.remove_aircraft("JAS39Gripen")
|
||||
self.remove_aircraft("JAS39Gripen_BVR")
|
||||
self.remove_aircraft("JAS39Gripen_AG")
|
||||
if not mod_settings.super_etendard:
|
||||
self.remove_aircraft("VSN_SEM")
|
||||
if not mod_settings.su30_flanker_h:
|
||||
self.remove_aircraft("Su-30MKA")
|
||||
self.remove_aircraft("Su-30MKI")
|
||||
@@ -596,3 +614,14 @@ def load_all_ships(data: list[str]) -> List[Type[ShipType]]:
|
||||
if item is not None:
|
||||
items.append(item)
|
||||
return items
|
||||
|
||||
|
||||
def load_carriers(json: Dict[str, Any]) -> Dict[ShipUnitType, Set[str]]:
|
||||
# Load carriers
|
||||
items: Dict[ShipUnitType, Set[str]] = defaultdict(Set[str])
|
||||
carriers = json.get("carriers", {})
|
||||
for carrier_shiptype, shipnames in carriers.items():
|
||||
shiptype = ShipUnitType.named(carrier_shiptype)
|
||||
if shiptype is not None:
|
||||
items[shiptype] = shipnames
|
||||
return items
|
||||
|
||||
@@ -52,7 +52,7 @@ class Migrator:
|
||||
continue
|
||||
found = False
|
||||
for d in doctrines:
|
||||
if c.faction.doctrine.max_patrol_altitude == d.max_patrol_altitude:
|
||||
if c.faction.doctrine.rendezvous_altitude == d.rendezvous_altitude:
|
||||
c.faction.doctrine = d
|
||||
found = True
|
||||
break
|
||||
@@ -78,7 +78,6 @@ class Migrator:
|
||||
def _update_control_points(self) -> None:
|
||||
is_sinai = self.game.theater.terrain.name == "SinaiMap"
|
||||
for cp in self.game.theater.controlpoints:
|
||||
cp.release_parking_slots()
|
||||
is_carrier = cp.is_carrier
|
||||
is_lha = cp.is_lha
|
||||
is_fob = cp.category == "fob"
|
||||
@@ -108,7 +107,6 @@ class Migrator:
|
||||
layout = f.flight_plan.layout
|
||||
try_set_attr(layout, "nav_to", [])
|
||||
try_set_attr(layout, "nav_from", [])
|
||||
try_set_attr(layout, "custom_waypoints", [])
|
||||
if f.flight_type == FlightType.CAS:
|
||||
try_set_attr(layout, "ingress", None)
|
||||
if isinstance(layout, FormationLayout):
|
||||
@@ -123,7 +121,6 @@ class Migrator:
|
||||
try_set_attr(f, "tacan")
|
||||
try_set_attr(f, "tcn_name")
|
||||
try_set_attr(f, "fuel", f.unit_type.max_fuel)
|
||||
try_set_attr(f, "plane_altitude_offset", 0)
|
||||
if f.package in f.squadron.coalition.ato.packages:
|
||||
self._update_flight_plan(f)
|
||||
else:
|
||||
@@ -204,8 +201,6 @@ class Migrator:
|
||||
c.faction.air_defense_units = set(c.faction.air_defense_units)
|
||||
if isinstance(c.faction.missiles, list):
|
||||
c.faction.missiles = set(c.faction.missiles)
|
||||
if isinstance(c.faction.carrier_names, list):
|
||||
c.faction.carrier_names = set(c.faction.carrier_names)
|
||||
if isinstance(c.faction.helicopter_carrier_names, list):
|
||||
c.faction.helicopter_carrier_names = set(
|
||||
c.faction.helicopter_carrier_names
|
||||
|
||||
@@ -44,16 +44,7 @@ class DeadIngressBuilder(PydcsWaypointBuilder):
|
||||
|
||||
task = AttackGroup(
|
||||
miz_group.id,
|
||||
weapon_type=WeaponType.ASM,
|
||||
expend=Expend.All,
|
||||
altitude=waypoint.alt,
|
||||
group_attack=True,
|
||||
)
|
||||
waypoint.tasks.append(task)
|
||||
|
||||
task = AttackGroup(
|
||||
miz_group.id,
|
||||
weapon_type=WeaponType.GuidedBombs,
|
||||
weapon_type=WeaponType.Guided,
|
||||
altitude=waypoint.alt,
|
||||
)
|
||||
waypoint.tasks.append(task)
|
||||
|
||||
@@ -40,4 +40,4 @@ class HoldPointBuilder(PydcsWaypointBuilder):
|
||||
if self.flight.is_helo:
|
||||
waypoint.add_task(OptFormation.rotary_column())
|
||||
else:
|
||||
waypoint.add_task(OptFormation.finger_four_open())
|
||||
waypoint.add_task(OptFormation.finger_four_close())
|
||||
|
||||
@@ -8,7 +8,9 @@ class LandingPointBuilder(PydcsWaypointBuilder):
|
||||
def build(self) -> MovingPoint:
|
||||
waypoint = super().build()
|
||||
if self.ai_despawn(waypoint):
|
||||
waypoint.alt = round(self.flight.unit_type.preferred_patrol_altitude.meters)
|
||||
waypoint.alt = round(
|
||||
self.flight.coalition.doctrine.max_patrol_altitude.meters
|
||||
)
|
||||
waypoint.alt_type = "BARO"
|
||||
else:
|
||||
waypoint.type = "Land"
|
||||
|
||||
@@ -124,9 +124,7 @@ class PydcsWaypointBuilder:
|
||||
return False
|
||||
|
||||
def register_special_strike_points(
|
||||
self,
|
||||
targets: Iterable[Union[MissionTarget, TheaterUnit]],
|
||||
start: int = 1,
|
||||
self, targets: Iterable[Union[MissionTarget, TheaterUnit]]
|
||||
) -> None:
|
||||
"""Create special strike waypoints for various aircraft"""
|
||||
for i, t in enumerate(targets):
|
||||
@@ -137,7 +135,7 @@ class PydcsWaypointBuilder:
|
||||
# Add F-15E mission target points as mission 1 (for JDAM for instance)
|
||||
if self.group.units[0].unit_type == F_15ESE:
|
||||
self.group.add_nav_target_point(
|
||||
t.position, f"M{(i//8)+start}.{i%8+1}\nH-1\nA0\nV0"
|
||||
t.position, f"M{(i//8)+1}.{i%8+1}" f"\nH-1" f"\nA0" f"\nV0"
|
||||
)
|
||||
|
||||
def register_special_ingress_points(self) -> None:
|
||||
|
||||
@@ -29,7 +29,7 @@ class SplitPointBuilder(PydcsWaypointBuilder):
|
||||
if self.flight.is_helo:
|
||||
waypoint.tasks.append(OptFormation.rotary_wedge())
|
||||
else:
|
||||
waypoint.tasks.append(OptFormation.finger_four_open())
|
||||
waypoint.tasks.append(OptFormation.finger_four_close())
|
||||
waypoint.speed_locked = True
|
||||
waypoint.ETA_locked = False
|
||||
if self.flight.is_helo:
|
||||
|
||||
@@ -2,7 +2,7 @@ import copy
|
||||
from typing import Union
|
||||
|
||||
from dcs import Point
|
||||
from dcs.planes import B_17G, B_52H, Tu_22M3, B_1B, F_15ESE
|
||||
from dcs.planes import B_17G, B_52H, Tu_22M3, B_1B
|
||||
from dcs.point import MovingPoint
|
||||
from dcs.task import Bombing, Expend, OptFormation, WeaponType, CarpetBombing
|
||||
|
||||
@@ -67,6 +67,8 @@ class StrikeIngressBuilder(PydcsWaypointBuilder):
|
||||
# If there is only one target, drop all ordnance in one pass.
|
||||
if len(self.waypoint.targets) == 1:
|
||||
bombing.params["expend"] = Expend.All.value
|
||||
elif target.is_static:
|
||||
bombing.params["expend"] = Expend.Half.value
|
||||
waypoint.tasks.append(bombing)
|
||||
|
||||
waypoint.speed = mach(0.85, meters(waypoint.alt)).meters_per_second
|
||||
@@ -74,6 +76,4 @@ class StrikeIngressBuilder(PydcsWaypointBuilder):
|
||||
# Register special waypoints
|
||||
if not self._special_wpts_injected:
|
||||
self.register_special_strike_points(self.waypoint.targets)
|
||||
if self.flight.unit_type.dcs_unit_type == F_15ESE:
|
||||
self.register_special_strike_points(self.flight.custom_targets, 2)
|
||||
self._special_wpts_injected = True
|
||||
|
||||
@@ -39,13 +39,7 @@ from dcs.task import (
|
||||
OptAlarmState,
|
||||
)
|
||||
from dcs.translation import String
|
||||
from dcs.triggers import (
|
||||
Event,
|
||||
TriggerOnce,
|
||||
TriggerStart,
|
||||
TriggerZone,
|
||||
TriggerZoneQuadPoint,
|
||||
)
|
||||
from dcs.triggers import Event, TriggerOnce, TriggerStart, TriggerZone
|
||||
from dcs.unit import Unit, InvisibleFARP, BaseFARP, SingleHeliPad, FARP
|
||||
from dcs.unitgroup import MovingGroup, ShipGroup, StaticGroup, VehicleGroup
|
||||
from dcs.unittype import ShipType, VehicleType
|
||||
@@ -411,24 +405,14 @@ class GroundObjectGenerator:
|
||||
# is minimized. As long as the triggerzone is over the scenery object, we're ok.
|
||||
smallest_valid_radius = feet(16).meters
|
||||
|
||||
if isinstance(scenery.zone, TriggerZoneQuadPoint):
|
||||
trigger_zone: TriggerZone = self.m.triggers.add_triggerzone_quad(
|
||||
scenery.zone.position,
|
||||
scenery.zone.verticies,
|
||||
scenery.zone.hidden,
|
||||
scenery.zone.name,
|
||||
color,
|
||||
scenery.zone.properties,
|
||||
)
|
||||
else:
|
||||
trigger_zone = self.m.triggers.add_triggerzone(
|
||||
scenery.zone.position,
|
||||
smallest_valid_radius,
|
||||
scenery.zone.hidden,
|
||||
scenery.zone.name,
|
||||
color,
|
||||
scenery.zone.properties,
|
||||
)
|
||||
trigger_zone = self.m.triggers.add_triggerzone(
|
||||
scenery.zone.position,
|
||||
smallest_valid_radius,
|
||||
scenery.zone.hidden,
|
||||
scenery.zone.name,
|
||||
color,
|
||||
scenery.zone.properties,
|
||||
)
|
||||
# DCS only visually shows a scenery object is dead when
|
||||
# this trigger rule is applied. Otherwise you can kill a
|
||||
# structure twice.
|
||||
|
||||
@@ -297,18 +297,8 @@ class Settings:
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
default=False,
|
||||
detail="AI will jettison their fuel tanks as soon as they're empty.",
|
||||
detail=("AI will jettison their fuel tanks as soon as they're empty."),
|
||||
)
|
||||
max_plane_altitude_offset: int = bounded_int_option(
|
||||
"Maximum randomized altitude offset (x1000 ft) for airplanes.",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
min=0,
|
||||
max=5,
|
||||
default=2,
|
||||
detail="Creates a randomized altitude offset for airplanes.",
|
||||
)
|
||||
# Doctrine Distances Section
|
||||
airbase_threat_range: int = bounded_int_option(
|
||||
"Airbase threat range (nmi)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
@@ -381,32 +371,6 @@ class Settings:
|
||||
"planned to known threat zones."
|
||||
),
|
||||
)
|
||||
max_mission_range_planes: int = bounded_int_option(
|
||||
"Auto-planner maximum mission range for airplanes (NM)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=DOCTRINE_DISTANCES_SECTION,
|
||||
default=150,
|
||||
min=150,
|
||||
max=1000,
|
||||
detail=(
|
||||
"The maximum mission distance that's used by the auto-planner for airplanes. "
|
||||
"This setting won't take effect when a larger "
|
||||
"range is defined in the airplane's yaml specification."
|
||||
),
|
||||
)
|
||||
max_mission_range_helicopters: int = bounded_int_option(
|
||||
"Auto-planner maximum mission range for helicopters (NM)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=DOCTRINE_DISTANCES_SECTION,
|
||||
default=100,
|
||||
min=50,
|
||||
max=1000,
|
||||
detail=(
|
||||
"The maximum mission distance that's used by the auto-planner for helicopters. "
|
||||
"This setting won't take effect when a larger "
|
||||
"range is defined in the helicopter's yaml specification."
|
||||
),
|
||||
)
|
||||
# Pilots and Squadrons
|
||||
ai_pilot_levelling: bool = boolean_option(
|
||||
"Allow AI pilot leveling",
|
||||
@@ -1034,7 +998,6 @@ class Settings:
|
||||
enable_transfer_cheat: bool = False
|
||||
enable_runway_state_cheat: bool = False
|
||||
enable_air_wing_adjustments: bool = False
|
||||
enable_enemy_buy_sell: bool = False
|
||||
|
||||
# LUA Plugins system
|
||||
plugins: Dict[str, bool] = field(default_factory=dict)
|
||||
|
||||
@@ -52,7 +52,6 @@ class AirWing:
|
||||
heli: bool,
|
||||
this_turn: bool,
|
||||
preferred_type: Optional[AircraftType] = None,
|
||||
ignore_range: bool = False,
|
||||
) -> list[Squadron]:
|
||||
airfield_cache = ObjectiveDistanceCache.get_closest_airfields(location)
|
||||
best_aircraft = AircraftType.priority_list_for_task(task)
|
||||
@@ -69,7 +68,7 @@ class AirWing:
|
||||
]
|
||||
for squadron in squadrons:
|
||||
if squadron.can_auto_assign_mission(
|
||||
location, task, size, heli, this_turn, ignore_range
|
||||
location, task, size, heli, this_turn
|
||||
):
|
||||
capable_at_base.append(squadron)
|
||||
if squadron.aircraft not in best_aircraft:
|
||||
@@ -101,10 +100,9 @@ class AirWing:
|
||||
heli: bool,
|
||||
this_turn: bool,
|
||||
preferred_type: Optional[AircraftType] = None,
|
||||
ignore_range: bool = False,
|
||||
) -> Optional[Squadron]:
|
||||
for squadron in self.best_squadrons_for(
|
||||
location, task, size, heli, this_turn, preferred_type, ignore_range
|
||||
location, task, size, heli, this_turn, preferred_type
|
||||
):
|
||||
return squadron
|
||||
return None
|
||||
|
||||
@@ -18,7 +18,7 @@ from game.theater import ParkingType
|
||||
from .pilot import Pilot, PilotStatus
|
||||
from ..db.database import Database
|
||||
from ..radio.radios import RadioFrequency
|
||||
from ..utils import meters, nautical_miles
|
||||
from ..utils import meters
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
@@ -281,7 +281,6 @@ class Squadron:
|
||||
size: int,
|
||||
heli: bool,
|
||||
this_turn: bool,
|
||||
ignore_range: bool = False,
|
||||
) -> bool:
|
||||
if (
|
||||
self.location.cptype.name in ["FOB", "FARP"]
|
||||
@@ -305,23 +304,8 @@ class Squadron:
|
||||
if heli and task == FlightType.REFUELING:
|
||||
return False
|
||||
|
||||
if ignore_range:
|
||||
return True
|
||||
|
||||
distance_to_target = meters(location.distance_to(self.location))
|
||||
max_plane_dist = nautical_miles(
|
||||
self.coalition.game.settings.max_mission_range_planes
|
||||
)
|
||||
max_heli_dist = nautical_miles(
|
||||
self.coalition.game.settings.max_mission_range_helicopters
|
||||
)
|
||||
if self.aircraft.helicopter:
|
||||
return distance_to_target <= max(
|
||||
self.aircraft.max_mission_range, max_heli_dist
|
||||
)
|
||||
return distance_to_target <= max(
|
||||
self.aircraft.max_mission_range, max_plane_dist
|
||||
)
|
||||
return distance_to_target <= self.aircraft.max_mission_range
|
||||
|
||||
def operates_from(self, control_point: ControlPoint) -> bool:
|
||||
if not control_point.can_operate(self.aircraft):
|
||||
|
||||
@@ -1021,8 +1021,6 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
# clear the ATO and replan the airlifts with the correct time.
|
||||
self.ground_unit_orders.process(game, game.conditions.start_time)
|
||||
|
||||
self.release_parking_slots()
|
||||
|
||||
runway_status = self.runway_status
|
||||
if runway_status is not None:
|
||||
runway_status.process_turn()
|
||||
|
||||
@@ -12,7 +12,7 @@ from game import Game
|
||||
from game.factions.faction import Faction
|
||||
from game.naming import namegen
|
||||
from game.scenery_group import SceneryGroup
|
||||
from game.theater import PointWithHeading, PresetLocation
|
||||
from game.theater import PointWithHeading, PresetLocation, NavalControlPoint
|
||||
from game.theater.theatergroundobject import (
|
||||
BuildingGroundObject,
|
||||
IadsBuildingGroundObject,
|
||||
@@ -30,8 +30,10 @@ from .theatergroup import IadsGroundGroup, IadsRole, SceneryUnit, TheaterGroup
|
||||
from ..armedforces.armedforces import ArmedForces
|
||||
from ..armedforces.forcegroup import ForceGroup
|
||||
from ..campaignloader.campaignairwingconfig import CampaignAirWingConfig
|
||||
from ..campaignloader.campaigncarrierconfig import CampaignCarrierConfig
|
||||
from ..campaignloader.campaigngroundconfig import TgoConfig
|
||||
from ..data.groups import GroupTask
|
||||
from ..dcs.shipunittype import ShipUnitType
|
||||
from ..profiling import logged_duration
|
||||
from ..settings import Settings
|
||||
|
||||
@@ -49,6 +51,7 @@ class GeneratorSettings:
|
||||
no_player_navy: bool
|
||||
no_enemy_navy: bool
|
||||
tgo_config: TgoConfig
|
||||
carrier_config: CampaignCarrierConfig
|
||||
squadrons_start_full: bool
|
||||
|
||||
|
||||
@@ -58,7 +61,6 @@ class ModSettings:
|
||||
a6a_intruder: bool = False
|
||||
a7e_corsair2: bool = False
|
||||
f4bc_phantom: bool = False
|
||||
f9f_panther: bool = False
|
||||
f15d_baz: bool = False
|
||||
f_15_idf: bool = False
|
||||
f_16_idf: bool = False
|
||||
@@ -73,7 +75,6 @@ class ModSettings:
|
||||
irondome: bool = False
|
||||
uh_60l: bool = False
|
||||
jas39_gripen: bool = False
|
||||
super_etendard: bool = False
|
||||
su30_flanker_h: bool = False
|
||||
su57_felon: bool = False
|
||||
frenchpack: bool = False
|
||||
@@ -127,7 +128,7 @@ class GameGenerator:
|
||||
|
||||
def should_remove_carrier(self, player: bool) -> bool:
|
||||
faction = self.player if player else self.enemy
|
||||
return self.generator_settings.no_carrier or not faction.carrier_names
|
||||
return self.generator_settings.no_carrier or not faction.carriers
|
||||
|
||||
def should_remove_lha(self, player: bool) -> bool:
|
||||
faction = self.player if player else self.enemy
|
||||
@@ -223,14 +224,49 @@ class GenericCarrierGroundObjectGenerator(ControlPointGroundObjectGenerator):
|
||||
carrier = next(self.control_point.ground_objects[-1].units)
|
||||
carrier.name = carrier_name
|
||||
|
||||
def apply_carrier_config(self) -> None:
|
||||
assert isinstance(self.control_point, NavalControlPoint)
|
||||
# If the campaign designer has specified a preferred name, use that
|
||||
# Note that the preferred name needs to exist in the faction, so we
|
||||
# don't end up with Kuznetsov carriers called CV-59 Forrestal
|
||||
preferred_name = None
|
||||
preferred_type = None
|
||||
carrier_map = self.generator_settings.carrier_config.by_original_name
|
||||
if ccfg := carrier_map.get(self.control_point.name):
|
||||
preferred_name = ccfg.preferred_name
|
||||
preferred_type = ccfg.preferred_type
|
||||
carrier_unit = self.control_point.ground_objects[0].groups[0].units[0]
|
||||
carrier_type = preferred_type if preferred_type else carrier_unit.unit_type
|
||||
assert isinstance(carrier_type, ShipUnitType)
|
||||
if preferred_type and self.faction.has_access_to_dcs_type(preferred_type.dcs_unit_type):
|
||||
carrier_unit.type = carrier_type.dcs_unit_type
|
||||
if (
|
||||
preferred_name
|
||||
):
|
||||
self.control_point.name = preferred_name
|
||||
else:
|
||||
# Otherwise pick randomly from the names specified for that particular carrier type
|
||||
carrier_names = self.faction.carriers.get(carrier_type)
|
||||
if carrier_names:
|
||||
self.control_point.name = random.choice(list(carrier_names))
|
||||
else:
|
||||
self.control_point.name = carrier_type.display_name
|
||||
# Prevents duplicate carrier or LHA names in campaigns with more that one of either.
|
||||
for carrier_type_key in self.faction.carriers:
|
||||
for carrier_name in self.faction.carriers[carrier_type_key]:
|
||||
if carrier_name == self.control_point.name:
|
||||
self.faction.carriers[carrier_type_key].remove(
|
||||
self.control_point.name
|
||||
)
|
||||
|
||||
|
||||
class CarrierGroundObjectGenerator(GenericCarrierGroundObjectGenerator):
|
||||
def generate(self) -> bool:
|
||||
if not super().generate():
|
||||
return False
|
||||
|
||||
carrier_names = self.faction.carrier_names
|
||||
if not carrier_names:
|
||||
carriers = self.faction.carriers
|
||||
if not carriers:
|
||||
logging.info(
|
||||
f"Skipping generation of {self.control_point.name} because "
|
||||
f"{self.faction_name} has no carriers"
|
||||
@@ -241,6 +277,7 @@ class CarrierGroundObjectGenerator(GenericCarrierGroundObjectGenerator):
|
||||
if not unit_group:
|
||||
logging.error(f"{self.faction_name} has no access to AircraftCarrier")
|
||||
return False
|
||||
|
||||
self.generate_ground_object_from_group(
|
||||
unit_group,
|
||||
PresetLocation(
|
||||
@@ -250,7 +287,7 @@ class CarrierGroundObjectGenerator(GenericCarrierGroundObjectGenerator):
|
||||
),
|
||||
GroupTask.AIRCRAFT_CARRIER,
|
||||
)
|
||||
self.update_carrier_name(random.choice(list(carrier_names)))
|
||||
self.apply_carrier_config()
|
||||
return True
|
||||
|
||||
|
||||
@@ -282,7 +319,7 @@ class LhaGroundObjectGenerator(GenericCarrierGroundObjectGenerator):
|
||||
),
|
||||
GroupTask.HELICOPTER_CARRIER,
|
||||
)
|
||||
self.update_carrier_name(random.choice(list(lha_names)))
|
||||
self.apply_carrier_config()
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
|
||||
MAJOR_VERSION = 1
|
||||
MINOR_VERSION = 3
|
||||
MICRO_VERSION = 1
|
||||
MICRO_VERSION = 0
|
||||
|
||||
|
||||
def _optional_build_id_component(path: Path) -> str | None:
|
||||
|
||||
@@ -2,7 +2,6 @@ from .SWPack import *
|
||||
from .a4ec import *
|
||||
from .a7e import *
|
||||
from .a6a import *
|
||||
from .f9f import *
|
||||
from .f100 import *
|
||||
from .f104 import *
|
||||
from .f105 import *
|
||||
@@ -21,7 +20,6 @@ from .irondome import *
|
||||
from .jas39 import *
|
||||
from .ov10a import *
|
||||
from .spanishnavypack import *
|
||||
from .super_etendard import *
|
||||
from .su30 import *
|
||||
from .su57 import *
|
||||
from .swedishmilitaryassetspack import *
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from .f9f import *
|
||||
@@ -1,699 +0,0 @@
|
||||
from typing import Set
|
||||
|
||||
from dcs import task
|
||||
from dcs.planes import PlaneType
|
||||
from dcs.weapons_data import Weapons
|
||||
|
||||
from game.modsupport import planemod
|
||||
|
||||
|
||||
@planemod
|
||||
class VSN_F9F(PlaneType):
|
||||
id = "VSN_F9F"
|
||||
flyable = True
|
||||
height = 3.73
|
||||
width = 11.58
|
||||
length = 11.84
|
||||
fuel_max = 2310
|
||||
max_speed = 961.2
|
||||
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
|
||||
radio_frequency = 127.5
|
||||
|
||||
livery_name = "VSN_F9F" # from type
|
||||
|
||||
class Pylon1:
|
||||
Smoke_Generator___red_ = (1, Weapons.Smoke_Generator___red_)
|
||||
Smoke_Generator___green_ = (1, Weapons.Smoke_Generator___green_)
|
||||
Smoke_Generator___blue_ = (1, Weapons.Smoke_Generator___blue_)
|
||||
Smoke_Generator___white_ = (1, Weapons.Smoke_Generator___white_)
|
||||
Smoke_Generator___yellow_ = (1, Weapons.Smoke_Generator___yellow_)
|
||||
Smoke_Generator___orange_ = (1, Weapons.Smoke_Generator___orange_)
|
||||
|
||||
class Pylon2:
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
2,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
2,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (2, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (2, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (2, Weapons.HVAR__UnGd_Rkt)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = (
|
||||
2,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE,
|
||||
)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = (
|
||||
2,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon3:
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
3,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
3,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (3, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (3, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (3, Weapons.HVAR__UnGd_Rkt)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = (
|
||||
3,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE,
|
||||
)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = (
|
||||
3,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon4:
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
4,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
4,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (4, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (4, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (4, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (4, Weapons.HVAR__UnGd_Rkt)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = (
|
||||
4,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE,
|
||||
)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = (
|
||||
4,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon5:
|
||||
AIM_9B_Sidewinder_IR_AAM = (5, Weapons.AIM_9B_Sidewinder_IR_AAM)
|
||||
Mk_83___1000lb_GP_Bomb_LD = (5, Weapons.Mk_83___1000lb_GP_Bomb_LD)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
5,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
5,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
M117___750lb_GP_Bomb_LD = (5, Weapons.M117___750lb_GP_Bomb_LD)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (5, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (5, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (5, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (5, Weapons.HVAR__UnGd_Rkt)
|
||||
# ERRR <CLEAN>
|
||||
Smoke_Generator___red_ = (5, Weapons.Smoke_Generator___red_)
|
||||
Smoke_Generator___green_ = (5, Weapons.Smoke_Generator___green_)
|
||||
Smoke_Generator___blue_ = (5, Weapons.Smoke_Generator___blue_)
|
||||
Smoke_Generator___white_ = (5, Weapons.Smoke_Generator___white_)
|
||||
Smoke_Generator___yellow_ = (5, Weapons.Smoke_Generator___yellow_)
|
||||
Smoke_Generator___orange_ = (5, Weapons.Smoke_Generator___orange_)
|
||||
|
||||
class Pylon6:
|
||||
Smoke_Generator___red_ = (6, Weapons.Smoke_Generator___red_)
|
||||
Smoke_Generator___green_ = (6, Weapons.Smoke_Generator___green_)
|
||||
Smoke_Generator___blue_ = (6, Weapons.Smoke_Generator___blue_)
|
||||
Smoke_Generator___white_ = (6, Weapons.Smoke_Generator___white_)
|
||||
Smoke_Generator___yellow_ = (6, Weapons.Smoke_Generator___yellow_)
|
||||
Smoke_Generator___orange_ = (6, Weapons.Smoke_Generator___orange_)
|
||||
|
||||
class Pylon7:
|
||||
AIM_9B_Sidewinder_IR_AAM = (7, Weapons.AIM_9B_Sidewinder_IR_AAM)
|
||||
Mk_83___1000lb_GP_Bomb_LD = (7, Weapons.Mk_83___1000lb_GP_Bomb_LD)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
7,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
7,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
M117___750lb_GP_Bomb_LD = (7, Weapons.M117___750lb_GP_Bomb_LD)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (7, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (7, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (7, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (7, Weapons.HVAR__UnGd_Rkt)
|
||||
# ERRR <CLEAN>
|
||||
Smoke_Generator___red_ = (7, Weapons.Smoke_Generator___red_)
|
||||
Smoke_Generator___green_ = (7, Weapons.Smoke_Generator___green_)
|
||||
Smoke_Generator___blue_ = (7, Weapons.Smoke_Generator___blue_)
|
||||
Smoke_Generator___white_ = (7, Weapons.Smoke_Generator___white_)
|
||||
Smoke_Generator___yellow_ = (7, Weapons.Smoke_Generator___yellow_)
|
||||
Smoke_Generator___orange_ = (7, Weapons.Smoke_Generator___orange_)
|
||||
|
||||
class Pylon8:
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
8,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
8,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (8, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (8, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (8, Weapons.HVAR__UnGd_Rkt)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = (
|
||||
8,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE,
|
||||
)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = (
|
||||
8,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon9:
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
9,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
9,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (9, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (9, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (9, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (9, Weapons.HVAR__UnGd_Rkt)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = (
|
||||
9,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE,
|
||||
)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = (
|
||||
9,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon10:
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
10,
|
||||
Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum,
|
||||
)
|
||||
LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = (
|
||||
10,
|
||||
Weapons.LAU_131_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk,
|
||||
)
|
||||
AN_M64___500lb_GP_Bomb_LD_ = (10, Weapons.AN_M64___500lb_GP_Bomb_LD_)
|
||||
Mk_82___500lb_GP_Bomb_LD = (10, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Mk_81___250lb_GP_Bomb_LD = (10, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
HVAR__UnGd_Rkt = (10, Weapons.HVAR__UnGd_Rkt)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = (
|
||||
10,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE,
|
||||
)
|
||||
LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = (
|
||||
10,
|
||||
Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon11:
|
||||
Smoke_Generator___red_ = (11, Weapons.Smoke_Generator___red_)
|
||||
Smoke_Generator___green_ = (11, Weapons.Smoke_Generator___green_)
|
||||
Smoke_Generator___blue_ = (11, Weapons.Smoke_Generator___blue_)
|
||||
Smoke_Generator___white_ = (11, Weapons.Smoke_Generator___white_)
|
||||
Smoke_Generator___yellow_ = (11, Weapons.Smoke_Generator___yellow_)
|
||||
Smoke_Generator___orange_ = (11, Weapons.Smoke_Generator___orange_)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
|
||||
|
||||
tasks = [
|
||||
task.CAP,
|
||||
task.CAS,
|
||||
task.Escort,
|
||||
task.FighterSweep,
|
||||
task.GroundAttack,
|
||||
task.Intercept,
|
||||
task.AntishipStrike,
|
||||
]
|
||||
task_default = task.GroundAttack
|
||||
@@ -1 +0,0 @@
|
||||
from .super_etendard import *
|
||||
@@ -1,144 +0,0 @@
|
||||
from dcs import task
|
||||
from dcs.planes import PlaneType
|
||||
from dcs.weapons_data import Weapons
|
||||
|
||||
|
||||
from game.modsupport import planemod
|
||||
from pydcs_extensions.weapon_injector import inject_weapons
|
||||
|
||||
|
||||
class WeaponsSEM:
|
||||
Fuel_Tank_1100_Liter = {
|
||||
"clsid": "{SEM1100_PTB}",
|
||||
"name": "Fuel Tank 1100 Liter",
|
||||
"weight": 1150,
|
||||
}
|
||||
Fuel_Tank_625_Liter = {
|
||||
"clsid": "{SEM625_PTB}",
|
||||
"name": "Fuel Tank 625 Liter",
|
||||
"weight": 1150,
|
||||
}
|
||||
|
||||
|
||||
inject_weapons(WeaponsSEM)
|
||||
|
||||
|
||||
@planemod
|
||||
class VSN_SEM(PlaneType):
|
||||
id = "VSN_SEM"
|
||||
flyable = True
|
||||
height = 4
|
||||
width = 13.05
|
||||
length = 18
|
||||
fuel_max = 6103
|
||||
max_speed = 2649.996
|
||||
chaff = 90
|
||||
flare = 45
|
||||
charge_total = 180
|
||||
chaff_charge_size = 1
|
||||
flare_charge_size = 2
|
||||
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
|
||||
radio_frequency = 127.5
|
||||
|
||||
livery_name = "VSN_SEM" # from type
|
||||
|
||||
class Pylon1:
|
||||
Smokewinder___red = (1, Weapons.Smokewinder___red)
|
||||
Smokewinder___green = (1, Weapons.Smokewinder___green)
|
||||
Smokewinder___blue = (1, Weapons.Smokewinder___blue)
|
||||
Smokewinder___white = (1, Weapons.Smokewinder___white)
|
||||
Smokewinder___yellow = (1, Weapons.Smokewinder___yellow)
|
||||
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
|
||||
Mk_81___250lb_GP_Bomb_LD = (1, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
Mk_82___500lb_GP_Bomb_LD = (1, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
R550_Magic_2_IR_AAM = (1, Weapons.R550_Magic_2_IR_AAM)
|
||||
LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
1,
|
||||
Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
ALQ_131___ECM_Pod = (1, Weapons.ALQ_131___ECM_Pod)
|
||||
AIM_9M_Sidewinder_IR_AAM = (1, Weapons.AIM_9M_Sidewinder_IR_AAM)
|
||||
AIM_9P_Sidewinder_IR_AAM = (1, Weapons.AIM_9P_Sidewinder_IR_AAM)
|
||||
|
||||
class Pylon2:
|
||||
AGM_65K___Maverick_K__CCD_Imp_ASM_ = (
|
||||
2,
|
||||
Weapons.AGM_65K___Maverick_K__CCD_Imp_ASM_,
|
||||
)
|
||||
GBU_12___500lb_Laser_Guided_Bomb = (2, Weapons.GBU_12___500lb_Laser_Guided_Bomb)
|
||||
LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
2,
|
||||
Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
Mk_81___250lb_GP_Bomb_LD = (2, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Fuel_Tank_1100_Liter = (2, WeaponsSEM.Fuel_Tank_1100_Liter)
|
||||
Fuel_Tank_625_Liter = (2, WeaponsSEM.Fuel_Tank_625_Liter)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon5:
|
||||
L_081_Fantasmagoria_ELINT_pod = (5, Weapons.L_081_Fantasmagoria_ELINT_pod)
|
||||
|
||||
class Pylon6:
|
||||
MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD = (
|
||||
6,
|
||||
Weapons.MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD,
|
||||
)
|
||||
AGM_65K___Maverick_K__CCD_Imp_ASM_ = (
|
||||
6,
|
||||
Weapons.AGM_65K___Maverick_K__CCD_Imp_ASM_,
|
||||
)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon10:
|
||||
AGM_65K___Maverick_K__CCD_Imp_ASM_ = (
|
||||
10,
|
||||
Weapons.AGM_65K___Maverick_K__CCD_Imp_ASM_,
|
||||
)
|
||||
GBU_12___500lb_Laser_Guided_Bomb = (
|
||||
10,
|
||||
Weapons.GBU_12___500lb_Laser_Guided_Bomb,
|
||||
)
|
||||
LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
10,
|
||||
Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
Mk_81___250lb_GP_Bomb_LD = (10, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
Mk_82___500lb_GP_Bomb_LD = (10, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
Fuel_Tank_1100_Liter = (10, WeaponsSEM.Fuel_Tank_1100_Liter)
|
||||
Fuel_Tank_625_Liter = (10, WeaponsSEM.Fuel_Tank_625_Liter)
|
||||
|
||||
class Pylon11:
|
||||
Smokewinder___red = (11, Weapons.Smokewinder___red)
|
||||
Smokewinder___green = (11, Weapons.Smokewinder___green)
|
||||
Smokewinder___blue = (11, Weapons.Smokewinder___blue)
|
||||
Smokewinder___white = (11, Weapons.Smokewinder___white)
|
||||
Smokewinder___yellow = (11, Weapons.Smokewinder___yellow)
|
||||
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (11, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
|
||||
Mk_81___250lb_GP_Bomb_LD = (11, Weapons.Mk_81___250lb_GP_Bomb_LD)
|
||||
Mk_82___500lb_GP_Bomb_LD = (11, Weapons.Mk_82___500lb_GP_Bomb_LD)
|
||||
R550_Magic_2_IR_AAM = (11, Weapons.R550_Magic_2_IR_AAM)
|
||||
LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = (
|
||||
11,
|
||||
Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE,
|
||||
)
|
||||
ALQ_131___ECM_Pod = (11, Weapons.ALQ_131___ECM_Pod)
|
||||
AIM_9M_Sidewinder_IR_AAM = (11, Weapons.AIM_9M_Sidewinder_IR_AAM)
|
||||
AIM_9P_Sidewinder_IR_AAM = (11, Weapons.AIM_9P_Sidewinder_IR_AAM)
|
||||
|
||||
pylons = {1, 2, 3, 5, 6, 9, 10, 11}
|
||||
|
||||
tasks = [
|
||||
task.CAP,
|
||||
task.Escort,
|
||||
task.FighterSweep,
|
||||
task.Intercept,
|
||||
task.Reconnaissance,
|
||||
task.GroundAttack,
|
||||
task.CAS,
|
||||
task.AFAC,
|
||||
task.RunwayAttack,
|
||||
]
|
||||
task_default = task.FighterSweep
|
||||
@@ -317,6 +317,7 @@ def create_game(
|
||||
no_player_navy=False,
|
||||
no_enemy_navy=False,
|
||||
tgo_config=campaign.load_ground_forces_config(),
|
||||
carrier_config=campaign.load_carrier_config(),
|
||||
),
|
||||
ModSettings(
|
||||
a4_skyhawk=False,
|
||||
@@ -325,7 +326,6 @@ def create_game(
|
||||
fa_18efg=False,
|
||||
fa18ef_tanker=False,
|
||||
f4bc_phantom=False,
|
||||
f9f_panther=False,
|
||||
f22_raptor=False,
|
||||
f84g_thunderjet=False,
|
||||
f100_supersabre=False,
|
||||
|
||||
@@ -141,7 +141,6 @@ class QFlightList(QListView):
|
||||
)
|
||||
return
|
||||
self.package_model.add_flight(clone)
|
||||
EventStream.put_nowait(GameUpdateEvents().new_flight(clone))
|
||||
|
||||
def cancel_or_abort_flight(self, index: QModelIndex) -> None:
|
||||
self.package_model.cancel_or_abort_flight_at_index(index)
|
||||
@@ -339,10 +338,6 @@ class QPackageList(QListView):
|
||||
)
|
||||
return
|
||||
self.ato_model.add_package(clone)
|
||||
events = GameUpdateEvents()
|
||||
for f in clone.flights:
|
||||
events.new_flight(f)
|
||||
EventStream.put_nowait(events)
|
||||
|
||||
def delete_package(self, index: QModelIndex) -> None:
|
||||
self.ato_model.cancel_or_abort_package_at_index(index)
|
||||
|
||||
@@ -97,7 +97,6 @@ class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
|
||||
wpt.description = f"Friendly unit: {target.name}"
|
||||
else:
|
||||
wpt.description = f"Enemy unit: {target.name}"
|
||||
wpt.waypoint_type = FlightWaypointType.TARGET_POINT
|
||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||
|
||||
if self.include_airbases:
|
||||
|
||||
@@ -108,7 +108,7 @@ class QLiberationWindow(QMainWindow):
|
||||
if last_save_file:
|
||||
logging.info("Loading last saved game : " + str(last_save_file))
|
||||
game = persistency.load_game(last_save_file)
|
||||
game = self.migrate_game(game, last_save_file)
|
||||
self.migrate_game(game, last_save_file)
|
||||
self.onGameGenerated(game)
|
||||
self.updateWindowTitle(last_save_file if game else None)
|
||||
else:
|
||||
@@ -316,7 +316,7 @@ class QLiberationWindow(QMainWindow):
|
||||
)
|
||||
if file is not None and file[0] != "":
|
||||
game = persistency.load_game(file[0])
|
||||
game = self.migrate_game(game, file[0])
|
||||
self.migrate_game(game, file[0])
|
||||
GameUpdateSignal.get_instance().game_loaded.emit(game)
|
||||
|
||||
self.updateWindowTitle(file[0])
|
||||
@@ -324,23 +324,15 @@ class QLiberationWindow(QMainWindow):
|
||||
def migrate_game(self, game, path):
|
||||
if game:
|
||||
is_liberation = ".liberation" in path
|
||||
try:
|
||||
Migrator(game, is_liberation)
|
||||
return game
|
||||
except Exception:
|
||||
self.incompatible_save_popup(path)
|
||||
Migrator(game, is_liberation)
|
||||
else:
|
||||
self.incompatible_save_popup(path)
|
||||
return None
|
||||
|
||||
def incompatible_save_popup(self, path):
|
||||
relative_path = Path(path)
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
"Incompatible save",
|
||||
"Incompatible save file detected, please report the issue on GitHub or Discord.\n"
|
||||
f"Make sure to include the campaign that fails to load, i.e.:\n\n{relative_path}",
|
||||
)
|
||||
relative_path = Path(path)
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
"Incompatible save",
|
||||
"Incompatible save file detected, please report the issue on GitHub or Discord.\n"
|
||||
f"Make sure to include the campaign that fails to load, i.e.:\n\n{relative_path}",
|
||||
)
|
||||
|
||||
def saveGame(self):
|
||||
logging.info("Saving game")
|
||||
|
||||
@@ -239,7 +239,5 @@ class QWaitingForMissionResultWindow(QDialog):
|
||||
self.sim_controller.set_game(self.game)
|
||||
for _, f in self.game.db.flights.objects.items():
|
||||
f.state.reinitialize(self.game.conditions.start_time)
|
||||
for cp in self.game.theater.controlpoints:
|
||||
cp.release_parking_slots()
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
self.close()
|
||||
|
||||
@@ -188,8 +188,7 @@ class QGroundObjectTemplateLayout(QGroupBox):
|
||||
|
||||
@property
|
||||
def affordable(self) -> bool:
|
||||
coalition = self.ground_object.coalition
|
||||
return self.cost <= coalition.budget or self.game.turn == 0
|
||||
return self.cost <= self.game.blue.budget
|
||||
|
||||
def add_theater_group(
|
||||
self, group_name: str, force_group: ForceGroup, groups: list[TgoLayoutUnitGroup]
|
||||
@@ -227,8 +226,7 @@ class QGroundObjectTemplateLayout(QGroupBox):
|
||||
self.game.theater.heading_to_conflict_from(self.ground_object.position)
|
||||
or self.ground_object.heading
|
||||
)
|
||||
coalition = self.ground_object.coalition
|
||||
coalition.budget -= self.cost if self.game.turn else 0
|
||||
self.game.blue.budget -= self.cost
|
||||
self.ground_object.groups = []
|
||||
for group_name, groups in self.layout_model.groups.items():
|
||||
for group in groups:
|
||||
@@ -284,8 +282,7 @@ class QGroundObjectBuyMenu(QDialog):
|
||||
if not tasks:
|
||||
tasks = role.tasks
|
||||
|
||||
coalition = ground_object.coalition
|
||||
for group in coalition.armed_forces.groups_for_tasks(tasks):
|
||||
for group in game.blue.armed_forces.groups_for_tasks(tasks):
|
||||
self.force_group_selector.addItem(group.name, userData=group)
|
||||
self.force_group_selector.setEnabled(self.force_group_selector.count() > 1)
|
||||
self.force_group_selector.adjustSize()
|
||||
|
||||
@@ -109,16 +109,10 @@ class QGroundObjectMenu(QDialog):
|
||||
self.actionLayout.addWidget(self.sell_all_button)
|
||||
self.actionLayout.addWidget(self.buy_replace)
|
||||
|
||||
if self.show_buy_sell_actions and self.ground_object.purchasable:
|
||||
if self.cp.captured and self.ground_object.purchasable:
|
||||
self.mainLayout.addLayout(self.actionLayout)
|
||||
self.setLayout(self.mainLayout)
|
||||
|
||||
@property
|
||||
def show_buy_sell_actions(self) -> bool:
|
||||
buysell_allowed = self.game.settings.enable_enemy_buy_sell
|
||||
buysell_allowed |= self.cp.captured
|
||||
return buysell_allowed
|
||||
|
||||
def doLayout(self):
|
||||
self.update_total_value()
|
||||
self.intelBox = QGroupBox("Units :")
|
||||
@@ -246,7 +240,7 @@ class QGroundObjectMenu(QDialog):
|
||||
self.actionLayout.addWidget(self.sell_all_button)
|
||||
self.actionLayout.addWidget(self.buy_replace)
|
||||
|
||||
if self.show_buy_sell_actions and self.ground_object.purchasable:
|
||||
if self.cp.captured and self.ground_object.purchasable:
|
||||
self.mainLayout.addLayout(self.actionLayout)
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
@@ -282,8 +276,7 @@ class QGroundObjectMenu(QDialog):
|
||||
|
||||
def sell_all(self):
|
||||
self.update_total_value()
|
||||
coalition = self.ground_object.coalition
|
||||
coalition.budget += self.total_value
|
||||
self.game.blue.budget += self.total_value
|
||||
self.ground_object.groups = []
|
||||
self.update_game()
|
||||
|
||||
@@ -303,10 +296,7 @@ class QGroundObjectMenu(QDialog):
|
||||
for package in self.game.ato_for(player=False).packages
|
||||
):
|
||||
# Replan if the tgo was a target of the redfor
|
||||
coalition = self.ground_object.coalition
|
||||
self.game.initialize_turn(
|
||||
events, for_red=coalition.player, for_blue=not coalition.player
|
||||
)
|
||||
self.game.initialize_turn(events, for_red=True, for_blue=False)
|
||||
EventStream.put_nowait(events)
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
# Refresh the dialog
|
||||
|
||||
@@ -223,7 +223,7 @@ class QAutoCreateDialog(QDialog):
|
||||
self.game.settings,
|
||||
)
|
||||
now = self.package_model.game_model.sim_controller.current_time_in_sim
|
||||
package = pff.plan_mission(pm, 1, now, tracer, ignore_range=True)
|
||||
package = pff.plan_mission(pm, 1, now, tracer)
|
||||
if package:
|
||||
package.set_tot_asap(now)
|
||||
self.package = package
|
||||
|
||||
@@ -86,7 +86,7 @@ class QFlightWaypointList(QTableView):
|
||||
|
||||
self.model.setItem(row, 0, QWaypointItem(waypoint, row))
|
||||
|
||||
altitude = round(waypoint.alt.feet)
|
||||
altitude = int(waypoint.alt.feet)
|
||||
altitude_item = QStandardItem(f"{altitude}")
|
||||
altitude_item.setEditable(True)
|
||||
self.model.setItem(row, 1, altitude_item)
|
||||
|
||||
@@ -162,9 +162,9 @@ class QFlightWaypointTab(QFrame):
|
||||
assert isinstance(self.flight.flight_plan, CustomFlightPlan)
|
||||
self.flight.flight_plan.layout.custom_waypoints.remove(waypoint)
|
||||
|
||||
def confirm_degrade(self, parent: Optional[QWidget] = None) -> bool:
|
||||
def confirm_degrade(self) -> bool:
|
||||
result = QMessageBox.warning(
|
||||
parent if parent else self,
|
||||
self,
|
||||
"Degrade flight-plan?",
|
||||
"Deleting the selected waypoint(s) will require degradation to a custom flight-plan. "
|
||||
"A custom flight-plan will no longer respect the TOTs of the package.<br><br>"
|
||||
@@ -184,6 +184,12 @@ class QFlightWaypointTab(QFrame):
|
||||
def on_waypoints_added(self, waypoints: Iterable[FlightWaypoint]) -> None:
|
||||
if not waypoints:
|
||||
return
|
||||
if not self.flight.flight_plan.is_custom:
|
||||
confirmed = self.confirm_degrade()
|
||||
if not confirmed:
|
||||
return
|
||||
self.degrade_to_custom_flight_plan()
|
||||
assert isinstance(self.flight.flight_plan, CustomFlightPlan)
|
||||
self.flight.flight_plan.layout.custom_waypoints.extend(waypoints)
|
||||
self.add_rows(len(list(waypoints)))
|
||||
|
||||
|
||||
@@ -84,10 +84,10 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
no_player_navy=self.field("no_player_navy"),
|
||||
no_enemy_navy=self.field("no_enemy_navy"),
|
||||
tgo_config=campaign.load_ground_forces_config(),
|
||||
carrier_config=campaign.load_carrier_config(),
|
||||
squadrons_start_full=self.field("squadrons_start_full"),
|
||||
)
|
||||
mod_settings = ModSettings(
|
||||
f9f_panther=self.field("f9f_panther"),
|
||||
a4_skyhawk=self.field("a4_skyhawk"),
|
||||
a6a_intruder=self.field("a6a_intruder"),
|
||||
a7e_corsair2=self.field("a7e_corsair2"),
|
||||
@@ -106,7 +106,6 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
irondome=self.field("irondome"),
|
||||
uh_60l=self.field("uh_60l"),
|
||||
jas39_gripen=self.field("jas39_gripen"),
|
||||
super_etendard=self.field("super_etendard"),
|
||||
su30_flanker_h=self.field("su30_flanker_h"),
|
||||
su57_felon=self.field("su57_felon"),
|
||||
ov10a_bronco=self.field("ov10a_bronco"),
|
||||
|
||||
@@ -100,8 +100,6 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
self.registerField("uh_60l", self.uh_60l)
|
||||
self.f4bc_phantom = QtWidgets.QCheckBox()
|
||||
self.registerField("f4bc_phantom", self.f4bc_phantom)
|
||||
self.f9f_panther = QtWidgets.QCheckBox()
|
||||
self.registerField("f9f_panther", self.f9f_panther)
|
||||
self.f15d_baz = QtWidgets.QCheckBox()
|
||||
self.registerField("f15d_baz", self.f15d_baz)
|
||||
self.f_15_idf = QtWidgets.QCheckBox()
|
||||
@@ -124,8 +122,6 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
self.registerField("f105_thunderchief", self.f105_thunderchief)
|
||||
self.jas39_gripen = QtWidgets.QCheckBox()
|
||||
self.registerField("jas39_gripen", self.jas39_gripen)
|
||||
self.super_etendard = QtWidgets.QCheckBox()
|
||||
self.registerField("super_etendard", self.super_etendard)
|
||||
self.su30_flanker_h = QtWidgets.QCheckBox()
|
||||
self.registerField("su30_flanker_h", self.su30_flanker_h)
|
||||
self.su57_felon = QtWidgets.QCheckBox()
|
||||
@@ -154,7 +150,6 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
modLayout_row = 1
|
||||
|
||||
mod_pairs = [
|
||||
("F9F Panther (v2.8.7.101)", self.f9f_panther),
|
||||
("A-4E Skyhawk (v2.2.0)", self.a4_skyhawk),
|
||||
("A-6A Intruder (v2.7.5.01)", self.a6a_intruder),
|
||||
("A-7E Corsair II", self.a7e_corsair2),
|
||||
@@ -175,7 +170,6 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
("Swedish Military Assets pack (1.10)", self.swedishmilitaryassetspack),
|
||||
("JAS 39 Gripen (v1.8.5-beta)", self.jas39_gripen),
|
||||
("OV-10A Bronco", self.ov10a_bronco),
|
||||
("Super Étendard (v2.5.5)", self.super_etendard),
|
||||
("Su-30 Flanker-H (V2.7.3 beta)", self.su30_flanker_h),
|
||||
("Su-57 Felon (build-04)", self.su57_felon),
|
||||
("UH-60L Black Hawk (v1.3.1)", self.uh_60l),
|
||||
@@ -218,7 +212,6 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
self.no_enemy_navy.setChecked(s.get("no_enemy_navy", False))
|
||||
self.squadrons_start_full.setChecked(s.get("squadron_start_full", False))
|
||||
|
||||
self.f9f_panther.setChecked(s.get("f9f_panther", False))
|
||||
self.a4_skyhawk.setChecked(s.get("a4_skyhawk", False))
|
||||
self.a6a_intruder.setChecked(s.get("a6a_intruder", False))
|
||||
self.a7e_corsair2.setChecked(s.get("a7e_corsair2", False))
|
||||
@@ -235,7 +228,6 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
self.f104_starfighter.setChecked(s.get("f104_starfighter", False))
|
||||
self.f105_thunderchief.setChecked(s.get("f105_thunderchief", False))
|
||||
self.jas39_gripen.setChecked(s.get("jas39_gripen", False))
|
||||
self.super_etendard.setChecked(s.get("super_etendard", False))
|
||||
self.su30_flanker_h.setChecked(s.get("su30_flanker_h", False))
|
||||
self.su57_felon.setChecked(s.get("su57_felon", False))
|
||||
self.ov10a_bronco.setChecked(s.get("ov10a_bronco", False))
|
||||
|
||||
@@ -113,15 +113,6 @@ class CheatSettingsBox(QGroupBox):
|
||||
)
|
||||
self.main_layout.addLayout(self.air_wing_cheat)
|
||||
|
||||
# Buy/Sell actions for OPFOR
|
||||
self.opfor_buysell_checkbox = QCheckBox()
|
||||
self.opfor_buysell_checkbox.setChecked(sc.settings.enable_enemy_buy_sell)
|
||||
self.opfor_buysell_checkbox.toggled.connect(apply_settings)
|
||||
self.redfor_buysell_cheat = QLabeledWidget(
|
||||
"Enable OPFOR Buy/Sell actions Cheat:", self.opfor_buysell_checkbox
|
||||
)
|
||||
self.main_layout.addLayout(self.redfor_buysell_cheat)
|
||||
|
||||
@property
|
||||
def show_red_ato(self) -> bool:
|
||||
return self.red_ato_checkbox.isChecked()
|
||||
@@ -146,10 +137,6 @@ class CheatSettingsBox(QGroupBox):
|
||||
def enable_air_wing_cheats(self) -> bool:
|
||||
return self.air_wing_adjustments_checkbox.isChecked()
|
||||
|
||||
@property
|
||||
def enable_redfor_buysell(self) -> bool:
|
||||
return self.opfor_buysell_checkbox.isChecked()
|
||||
|
||||
|
||||
class AutoSettingsLayout(QGridLayout):
|
||||
def __init__(
|
||||
@@ -508,7 +495,6 @@ class QSettingsWidget(QtWidgets.QWizardPage, SettingsContainer):
|
||||
self.settings.enable_air_wing_adjustments = (
|
||||
self.cheat_options.enable_air_wing_cheats
|
||||
)
|
||||
self.settings.enable_enemy_buy_sell = self.cheat_options.enable_redfor_buysell
|
||||
|
||||
if self.game:
|
||||
events = GameUpdateEvents()
|
||||
@@ -535,15 +521,6 @@ class QSettingsWidget(QtWidgets.QWizardPage, SettingsContainer):
|
||||
self.cheat_options.transfer_cheat_checkbox.setChecked(
|
||||
self.settings.enable_transfer_cheat
|
||||
)
|
||||
self.cheat_options.base_runway_state_cheat_checkbox.setChecked(
|
||||
self.settings.enable_runway_state_cheat
|
||||
)
|
||||
self.cheat_options.air_wing_adjustments_checkbox.setChecked(
|
||||
self.settings.enable_air_wing_adjustments
|
||||
)
|
||||
self.cheat_options.opfor_buysell_checkbox.setChecked(
|
||||
self.settings.enable_enemy_buy_sell
|
||||
)
|
||||
|
||||
self.pluginsPage.update_from_settings()
|
||||
self.pluginsOptionsPage.update_from_settings()
|
||||
|
||||
@@ -81,6 +81,14 @@ settings:
|
||||
#default="Full"
|
||||
|
||||
|
||||
carriers:
|
||||
Naval-1:
|
||||
preferred_name: CVN-74
|
||||
preferred_type: CVN-74 John C. Stennis
|
||||
Naval-2:
|
||||
preferred_name: The Harry
|
||||
preferred_type: CVN-75 Harry S. Truman
|
||||
|
||||
|
||||
#Squadrons and order of battle settings
|
||||
squadrons:
|
||||
@@ -156,7 +164,7 @@ squadrons:
|
||||
aircraft:
|
||||
- CH-53E
|
||||
size: 2
|
||||
#CV-59 Forrestal
|
||||
#CV-59 Forrestal
|
||||
Naval-2:
|
||||
- primary: AEW&C
|
||||
aircraft:
|
||||
|
||||
@@ -38,12 +38,12 @@ squadrons:
|
||||
#Port Stanley
|
||||
1:
|
||||
- primary: DEAD
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 6
|
||||
- primary: BAI
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 6
|
||||
@@ -56,15 +56,14 @@ squadrons:
|
||||
#San Carlos FOB
|
||||
3:
|
||||
- primary: BAI
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Mi-24P Hind-F
|
||||
size: 6
|
||||
#Goose Green
|
||||
24:
|
||||
- primary: DEAD
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Ka-50 Hokum III
|
||||
- Ka-50 Hokum (Blackshark 3)
|
||||
size: 6
|
||||
@@ -95,11 +95,6 @@ squadrons:
|
||||
aircraft:
|
||||
- CH-47D
|
||||
size: 20
|
||||
- primary: BAI
|
||||
secondary: any
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 8
|
||||
- primary: Air Assault
|
||||
secondary: any
|
||||
aircraft:
|
||||
@@ -120,9 +115,8 @@ squadrons:
|
||||
# Melez (30)
|
||||
5:
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Ka-50 Hokum III
|
||||
- Ka-50 Hokum (Blackshark 3)
|
||||
size: 4
|
||||
- primary: BAI
|
||||
|
||||
@@ -53,7 +53,7 @@ squadrons:
|
||||
- A-10C Thunderbolt II (Suite 7)
|
||||
size: 8
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 10
|
||||
@@ -88,13 +88,12 @@ squadrons:
|
||||
# Creech
|
||||
1:
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Ka-50 Hokum III
|
||||
- Ka-50 Hokum (Blackshark 3)
|
||||
size: 8
|
||||
- primary: Air Assault
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Mi-24P Hind-F
|
||||
size: 4
|
||||
|
||||
Binary file not shown.
@@ -35,11 +35,6 @@ squadrons:
|
||||
aircraft:
|
||||
- F-15C Eagle
|
||||
size: 8
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 8
|
||||
- primary: Refueling
|
||||
aircraft:
|
||||
- KC-135 Stratotanker
|
||||
@@ -147,15 +142,14 @@ squadrons:
|
||||
#Ushuaia
|
||||
7:
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Ka-50 Hokum III
|
||||
- Ka-50 Hokum (Blackshark 3)
|
||||
size: 8
|
||||
#Ushuaia Helo Port
|
||||
8:
|
||||
- primary: Air Assault
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Mi-24P Hind-F
|
||||
size: 8
|
||||
size: 8
|
||||
@@ -48,7 +48,7 @@ squadrons:
|
||||
#Tarawa Class LHA
|
||||
Blue-LHA:
|
||||
- primary: DEAD
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 12
|
||||
@@ -72,7 +72,7 @@ squadrons:
|
||||
#Akrotiri
|
||||
44:
|
||||
- primary: BAI
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-1W SuperCobra
|
||||
size: 4
|
||||
@@ -81,8 +81,8 @@ squadrons:
|
||||
aircraft:
|
||||
- OH-58D Kiowa Warrior
|
||||
size: 4
|
||||
- primary: Transport
|
||||
secondary: any
|
||||
- primary: Air Assault
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- UH-60A
|
||||
size: 4
|
||||
@@ -95,7 +95,6 @@ squadrons:
|
||||
#Ercan
|
||||
49:
|
||||
- primary: Transport
|
||||
secondary: any
|
||||
aircraft:
|
||||
- CH-47D
|
||||
size: 6
|
||||
|
||||
@@ -100,7 +100,7 @@ squadrons:
|
||||
#Qeshm Island (12)
|
||||
13:
|
||||
- primary: Air Assault
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Mi-24P Hind-F
|
||||
size: 12
|
||||
|
||||
@@ -80,7 +80,7 @@ squadrons:
|
||||
- F-16CM Fighting Falcon (Block 50)
|
||||
size: 28
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 4
|
||||
@@ -93,13 +93,13 @@ squadrons:
|
||||
- H-6J Badger
|
||||
size: 16
|
||||
- primary: BAI
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-1W SuperCobra
|
||||
- Su-25 Frogfoot
|
||||
size: 16
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- OH-58D Kiowa Warrior
|
||||
- Mi-24P Hind-F
|
||||
|
||||
@@ -57,7 +57,7 @@ squadrons:
|
||||
size: 20
|
||||
Squadrons from Incirlik:
|
||||
- primary: CAS
|
||||
secondary: any
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-64D Apache Longbow
|
||||
size: 4
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "VSN_F9F",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 10,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{AIM-9B}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{AIM-9B}",
|
||||
["num"] = 7,
|
||||
},
|
||||
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{319293F2-392C-4617-8315-7C88C22AF7C4}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{319293F2-392C-4617-8315-7C88C22AF7C4}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{LAU3_FFAR_MK5HEAT}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{319293F2-392C-4617-8315-7C88C22AF7C4}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{319293F2-392C-4617-8315-7C88C22AF7C4}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{LAU3_FFAR_MK5HEAT}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{319293F2-392C-4617-8315-7C88C22AF7C4}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{319293F2-392C-4617-8315-7C88C22AF7C4}",
|
||||
["num"] = 10,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "SEAD",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
[6] = {
|
||||
["displayName"] = "BAI",
|
||||
["name"] = "BAI",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 7,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{HVAR}",
|
||||
["num"] = 10,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 31,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "VSN_F9F",
|
||||
}
|
||||
return unitPayloads
|
||||
@@ -1,146 +0,0 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "VSN_SEM",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["name"] = "CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
|
||||
["num"] = 11,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 6,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
[2] = 31,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["name"] = "CAP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{SEM1100_PTB}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
|
||||
["num"] = 11,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{SEM1100_PTB}",
|
||||
["num"] = 10,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 11,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["name"] = "ANTISHIP",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}",
|
||||
["num"] = 11,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 6,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 30,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
["name"] = "STRIKE",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{SEM1100_PTB}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
|
||||
["num"] = 11,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{SEM1100_PTB}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{D5D51E24-348C-4702-96AF-97A714E72697}",
|
||||
["num"] = 6,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
["name"] = "DEAD",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{6D21ECEA-F85B-4E8D-9D51-31DC9B8AA4EF}",
|
||||
["num"] = 1,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{6D21ECEA-F85B-4E8D-9D51-31DC9B8AA4EF}",
|
||||
["num"] = 11,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}",
|
||||
["num"] = 6,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 32,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
},
|
||||
["unitType"] = "VSN_SEM",
|
||||
}
|
||||
return unitPayloads
|
||||
File diff suppressed because it is too large
Load Diff
@@ -90,13 +90,6 @@
|
||||
"hertz": 343000,
|
||||
"channel": null
|
||||
},
|
||||
"world_13": {
|
||||
"name": "GHI",
|
||||
"callsign": "GHI",
|
||||
"beacon_type": 5,
|
||||
"hertz": 113800000,
|
||||
"channel": 85
|
||||
},
|
||||
"airfield2_0": {
|
||||
"name": "",
|
||||
"callsign": "IADA",
|
||||
@@ -153,20 +146,6 @@
|
||||
"hertz": 365000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield67_0": {
|
||||
"name": "",
|
||||
"callsign": "IAMN",
|
||||
"beacon_type": 13,
|
||||
"hertz": 109500000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield67_1": {
|
||||
"name": "",
|
||||
"callsign": "IAMN",
|
||||
"beacon_type": 14,
|
||||
"hertz": 109500000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield6_0": {
|
||||
"name": "KALDE",
|
||||
"callsign": "KAD",
|
||||
@@ -254,8 +233,8 @@
|
||||
"airfield7_4": {
|
||||
"name": "DAMASCUS",
|
||||
"callsign": "DAL",
|
||||
"beacon_type": 9,
|
||||
"hertz": 342000,
|
||||
"beacon_type": 10,
|
||||
"hertz": 342000000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield7_5": {
|
||||
@@ -338,8 +317,8 @@
|
||||
"airfield41_1": {
|
||||
"name": "ALANYA/GAZIPASA",
|
||||
"callsign": "GZP",
|
||||
"beacon_type": 3,
|
||||
"hertz": 114200000,
|
||||
"beacon_type": 2,
|
||||
"hertz": 0,
|
||||
"channel": 89
|
||||
},
|
||||
"airfield41_2": {
|
||||
@@ -426,20 +405,6 @@
|
||||
"hertz": 111700000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield65_0": {
|
||||
"name": "",
|
||||
"callsign": "",
|
||||
"beacon_type": 14,
|
||||
"hertz": 109100000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield65_1": {
|
||||
"name": "",
|
||||
"callsign": "",
|
||||
"beacon_type": 13,
|
||||
"hertz": 109100000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield47_0": {
|
||||
"name": "",
|
||||
"callsign": "ILC",
|
||||
@@ -503,34 +468,6 @@
|
||||
"hertz": 358000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield68_0": {
|
||||
"name": "",
|
||||
"callsign": "",
|
||||
"beacon_type": 13,
|
||||
"hertz": 112910000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield68_1": {
|
||||
"name": "",
|
||||
"callsign": "",
|
||||
"beacon_type": 13,
|
||||
"hertz": 112900000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield68_2": {
|
||||
"name": "",
|
||||
"callsign": "",
|
||||
"beacon_type": 14,
|
||||
"hertz": 112910000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield68_3": {
|
||||
"name": "",
|
||||
"callsign": "",
|
||||
"beacon_type": 14,
|
||||
"hertz": 112900000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield27_0": {
|
||||
"name": "ALEPPO",
|
||||
"callsign": "ALE",
|
||||
@@ -608,27 +545,6 @@
|
||||
"hertz": null,
|
||||
"channel": 79
|
||||
},
|
||||
"airfield64_0": {
|
||||
"name": "PrinceHussein",
|
||||
"callsign": "ABC",
|
||||
"beacon_type": 4,
|
||||
"hertz": 0,
|
||||
"channel": 106
|
||||
},
|
||||
"airfield64_1": {
|
||||
"name": "",
|
||||
"callsign": "ABC",
|
||||
"beacon_type": 13,
|
||||
"hertz": 111400000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield64_2": {
|
||||
"name": "",
|
||||
"callsign": "ABC",
|
||||
"beacon_type": 14,
|
||||
"hertz": 111400000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield30_0": {
|
||||
"name": "RAMATDAVID",
|
||||
"callsign": "RMD",
|
||||
@@ -664,20 +580,6 @@
|
||||
"hertz": 115300000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield58_0": {
|
||||
"name": "Sanliurfa",
|
||||
"callsign": "GAP",
|
||||
"beacon_type": 3,
|
||||
"hertz": 113200000,
|
||||
"channel": 79
|
||||
},
|
||||
"airfield58_1": {
|
||||
"name": "Sanliurfa",
|
||||
"callsign": "GAP",
|
||||
"beacon_type": 9,
|
||||
"hertz": 391000,
|
||||
"channel": null
|
||||
},
|
||||
"airfield40_0": {
|
||||
"name": "Cheka",
|
||||
"callsign": "CAK",
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
"Mirage-F1B",
|
||||
"Mirage-F1CE",
|
||||
"Mirage-F1C-200",
|
||||
"Super Étendard",
|
||||
"SA 342L Gazelle",
|
||||
"SA 342M Gazelle",
|
||||
"SA 342M Gazelle Mistral"
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
"Mirage-F1CE",
|
||||
"Mirage-F1C-200",
|
||||
"Mirage-F1CT",
|
||||
"Super Étendard",
|
||||
"SA 342L Gazelle",
|
||||
"SA 342M Gazelle",
|
||||
"SA 342M Gazelle Mistral"
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
"Mirage-F1CE",
|
||||
"Mirage-F1C-200",
|
||||
"Mirage-F1CT",
|
||||
"Super Étendard",
|
||||
"SA 342L Gazelle",
|
||||
"SA 342M Gazelle",
|
||||
"SA 342M Gazelle Mistral"
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
{
|
||||
"country": "Russia",
|
||||
"name": "Private Military Company - Russian (Hard)",
|
||||
"authors": "Starfire",
|
||||
"description": "<p>A well-equipped private military company using a mix of modern and older Russian hardware.</p>",
|
||||
"locales": [
|
||||
"ru_RU"
|
||||
],
|
||||
"aircrafts": [
|
||||
"Ka-50 Hokum",
|
||||
"Ka-50 Hokum (Blackshark 3)",
|
||||
"L-39ZA Albatros",
|
||||
"Mi-24V Hind-E",
|
||||
"Mi-24P Hind-F",
|
||||
"Mi-8MTV2 Hip"
|
||||
],
|
||||
"frontline_units": [
|
||||
"BMP-1",
|
||||
"BRDM-2",
|
||||
"BTR-80",
|
||||
"BTR-D",
|
||||
"Cobra",
|
||||
"MT-LB",
|
||||
"PT-76",
|
||||
"T-55A",
|
||||
"ZSU-57-2 'Sparka'"
|
||||
],
|
||||
"artillery_units": [
|
||||
"2S1 Gvozdika",
|
||||
"2S19 Msta-S",
|
||||
"BM-27 Uragan"
|
||||
],
|
||||
"logistics_units": [
|
||||
"LUV UAZ-469 Jeep",
|
||||
"Truck Ural-375"
|
||||
],
|
||||
"infantry_units": [
|
||||
"Infantry AK-74 Rus",
|
||||
"MANPADS SA-18 Igla-S \"Grouse\"",
|
||||
"Mortar 2B11 120mm",
|
||||
"Paratrooper AKS",
|
||||
"Paratrooper RPG-16"
|
||||
],
|
||||
"air_defense_units": [
|
||||
"SA-9 Strela",
|
||||
"SA-13 Gopher (9K35 Strela-10M3)",
|
||||
"ZSU-57-2 'Sparka'",
|
||||
"ZSU-23-4 Shilka"
|
||||
],
|
||||
"preset_groups": [],
|
||||
"naval_units": [],
|
||||
"missiles": []
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"country": "USA",
|
||||
"name": "USA 1955",
|
||||
"authors": "Khopa",
|
||||
"description": "<p>US armed forces in the 50s, circa Korean War.</p>",
|
||||
"description": "<p>US army in the 50s, circa Korean War.</p>",
|
||||
"locales": [
|
||||
"en_US"
|
||||
],
|
||||
@@ -13,8 +13,7 @@
|
||||
"F-86F Sabre",
|
||||
"F-100 Super Sabre",
|
||||
"P-51D-25-NA Mustang",
|
||||
"P-51D-30-NA Mustang",
|
||||
"F9F Panther"
|
||||
"P-51D-30-NA Mustang"
|
||||
],
|
||||
"frontline_units": [
|
||||
"Bofors 40 mm Gun",
|
||||
|
||||
@@ -46,14 +46,14 @@
|
||||
],
|
||||
"preset_groups": [
|
||||
"Hawk",
|
||||
"Patriot"
|
||||
"Patriot",
|
||||
"Carrier Strike Group 8"
|
||||
],
|
||||
"naval_units": [
|
||||
"FFG Oliver Hazard Perry",
|
||||
"DDG Arleigh Burke IIa",
|
||||
"CG Ticonderoga",
|
||||
"LHA-1 Tarawa",
|
||||
"CVN-74 John C. Stennis"
|
||||
"LHA-1 Tarawa"
|
||||
],
|
||||
"missiles": [],
|
||||
"air_defense_units": [
|
||||
|
||||
@@ -2,7 +2,11 @@ name: Carrier Strike Group 8
|
||||
tasks:
|
||||
- Navy
|
||||
units:
|
||||
- CVN-71 Theodore Roosevelt
|
||||
- CVN-72 Abraham Lincoln
|
||||
- CVN-73 George Washington
|
||||
- CVN-74 John C. Stennis
|
||||
- CVN-75 Harry S. Truman
|
||||
- DDG Arleigh Burke IIa
|
||||
- CG Ticonderoga
|
||||
layouts:
|
||||
|
||||
@@ -80,14 +80,6 @@ def beacons_from_terrain(dcs_path: Path, path: Path) -> Iterable[tuple[str, Beac
|
||||
)
|
||||
)
|
||||
|
||||
lua.execute(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
function math.pow(x,y) return x^y end
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
bind_gettext = lua.eval(
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 150 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.1 KiB |
@@ -1,28 +0,0 @@
|
||||
carrier_capable: true
|
||||
description:
|
||||
The Grumman F9F Panther is an early carrier-based jet fighter designed and produced
|
||||
by the American aircraft manufacturer Grumman. It was the first jet-powered fighter
|
||||
aircraft operated by the United States Navy as well as being Grumman’s first jet fighter.
|
||||
The F9F is a single-engined, straight-winged day fighter, armed with four 20 mm (0.79 in)
|
||||
cannons and could also carry a wide assortment of air-to-ground munitions.
|
||||
The Panther was used extensively by the U.S. Navy and Marine Corps in the Korean War.
|
||||
introduced: 1947
|
||||
manufacturer: Grumman
|
||||
origin: USA
|
||||
price: 6
|
||||
role: Carrier-based Attack/Light Fighter
|
||||
gunfighter: true
|
||||
variants:
|
||||
F9F Panther: {}
|
||||
tasks:
|
||||
BAI: 650
|
||||
BARCAP: 150
|
||||
CAS: 650
|
||||
DEAD: 370
|
||||
Escort: 150
|
||||
Fighter sweep: 150
|
||||
Intercept: 150
|
||||
OCA/Aircraft: 650
|
||||
OCA/Runway: 350
|
||||
Strike: 350
|
||||
TARCAP: 150
|
||||
@@ -1,25 +0,0 @@
|
||||
description:
|
||||
The Dassault-Breguet Super Étendard is a French carrier-borne strike fighter aircraft
|
||||
designed for service with the French Navy aircraft carriers.
|
||||
|
||||
The aircraft is an advanced development of the Étendard IVM, which it replaced.
|
||||
Super Étendards have seen combat in Kosovo, Afghanistan, Libya, Falklands and
|
||||
in the Iraq-Iran war.
|
||||
introduced: 1978
|
||||
manufacturer: Dassault-Breguet
|
||||
origin: France
|
||||
price: 10
|
||||
role: Carrier-based Strike Fighter
|
||||
carrier_capable: true
|
||||
gunfighter: true
|
||||
max_range: 200
|
||||
variants:
|
||||
Super Étendard: {}
|
||||
tasks:
|
||||
Anti-ship: 150
|
||||
BAI: 250
|
||||
CAS: 250
|
||||
DEAD: 250
|
||||
OCA/Aircraft: 250
|
||||
OCA/Runway: 230
|
||||
Strike: 230
|
||||
4
resources/units/ships/CVN_71.yaml
Normal file
4
resources/units/ships/CVN_71.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
class: AircraftCarrier
|
||||
price: 0
|
||||
variants:
|
||||
CVN-71 Theodore Roosevelt: null
|
||||
4
resources/units/ships/CVN_72.yaml
Normal file
4
resources/units/ships/CVN_72.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
class: AircraftCarrier
|
||||
price: 0
|
||||
variants:
|
||||
CVN-72 Abraham Lincoln: null
|
||||
4
resources/units/ships/CVN_73.yaml
Normal file
4
resources/units/ships/CVN_73.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
class: AircraftCarrier
|
||||
price: 0
|
||||
variants:
|
||||
CVN-73 George Washington: null
|
||||
4
resources/units/ships/CVN_75.yaml
Normal file
4
resources/units/ships/CVN_75.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
class: AircraftCarrier
|
||||
price: 0
|
||||
variants:
|
||||
CVN-75 Harry S. Truman: null
|
||||
4
resources/units/ships/CV_1143_5.yaml
Normal file
4
resources/units/ships/CV_1143_5.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
class: AircraftCarrier
|
||||
price: 0
|
||||
variants:
|
||||
CV 1143.5 Admiral Kuznetsov(2017): null
|
||||
@@ -92,12 +92,13 @@ class TestFactionLoader(unittest.TestCase):
|
||||
self.assertIn(Infantry.Soldier_M249, faction.infantry_units)
|
||||
|
||||
self.assertIn(Stennis.name, faction.naval_units)
|
||||
self.assertIn(Stennis, faction.carriers.keys())
|
||||
self.assertIn(LHA_Tarawa.name, faction.naval_units)
|
||||
|
||||
self.assertIn("mod", faction.requirements.keys())
|
||||
self.assertIn("Some mod is required", faction.requirements.values())
|
||||
|
||||
self.assertEqual(4, len(faction.carrier_names))
|
||||
self.assertEqual(4, len(faction.carriers))
|
||||
self.assertEqual(5, len(faction.helicopter_carrier_names))
|
||||
|
||||
@pytest.mark.skip(reason="Faction unit names in the json files are outdated")
|
||||
|
||||
Reference in New Issue
Block a user