Merge branch 'dev' into pr/204
@ -8,6 +8,7 @@
|
||||
* **[Squadrons]** Ability to define a livery-set for each squadron from which Retribution will randomly choose during mission generation
|
||||
* **[Modding]** Updated support for F/A-18E/F/G mod version 2.2.5
|
||||
* **[Modding]** Added VSN F-106 Delta Dart mod support (v2.9.4.101)
|
||||
* **[Modding]** Added OH-6 Cayuse (v1.2) mod support, including the Vietnam Asset Pack v1.0
|
||||
* **[Modding]** Added VSN EA-6B Prowler mod support (v2.9.4.102)
|
||||
* **[Modding]** Added tripod3 Cold War assets mod support (v1.0)
|
||||
* **[Campaign Setup]** Allow adjustments to naval TGOs (except carriers) on turn 0
|
||||
@ -25,6 +26,9 @@
|
||||
* **[Modding]** Added support for Su-15 Flagon mod (v1.0)
|
||||
* **[Plugins]** Support for Carsten's Arty Spotter script
|
||||
* **[Modding]** Added support for SK-60 mod (v1.2.1)
|
||||
* **[Mission Generation]** Introducing the Armed Recon flight plan, i.e. CAS against any Theater Ground Object
|
||||
* **[Doctrine]** Ability to customize the startup time allocated to the player
|
||||
* **[Mission Generation]** Ability to choose whether player flights can spawn on the sixpack or not
|
||||
|
||||
## Fixes
|
||||
* **[UI/UX]** A-10A flights can be edited again
|
||||
|
||||
@ -275,8 +275,6 @@ class Flight(
|
||||
self.fuel = unit_type.fuel_max * 0.5
|
||||
elif unit_type == Hercules:
|
||||
self.fuel = unit_type.fuel_max * 0.75
|
||||
elif self.departure.cptype.name in ["FARP", "FOB"] and not self.is_helo:
|
||||
self.fuel = unit_type.fuel_max * 0.75
|
||||
|
||||
def any_member_has_weapon_of_type(self, weapon_type: WeaponType) -> bool:
|
||||
return any(
|
||||
|
||||
@ -75,13 +75,6 @@ class AirAssaultFlightPlan(FormationAttackFlightPlan, UiZoneDisplay):
|
||||
)
|
||||
return tot - travel_time
|
||||
|
||||
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None:
|
||||
if waypoint is self.tot_waypoint:
|
||||
return self.tot
|
||||
elif waypoint is self.layout.ingress:
|
||||
return self.ingress_time
|
||||
return None
|
||||
|
||||
def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None:
|
||||
return None
|
||||
|
||||
@ -89,10 +82,6 @@ class AirAssaultFlightPlan(FormationAttackFlightPlan, UiZoneDisplay):
|
||||
def ctld_target_zone_radius(self) -> Distance:
|
||||
return meters(2500)
|
||||
|
||||
@property
|
||||
def mission_begin_on_station_time(self) -> datetime | None:
|
||||
return None
|
||||
|
||||
@property
|
||||
def mission_departure_time(self) -> datetime:
|
||||
return self.package.time_over_target
|
||||
|
||||
34
game/ato/flightplans/armedrecon.py
Normal file
@ -0,0 +1,34 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Type
|
||||
|
||||
from .formationattack import (
|
||||
FormationAttackBuilder,
|
||||
FormationAttackFlightPlan,
|
||||
FormationAttackLayout,
|
||||
)
|
||||
from .uizonedisplay import UiZone, UiZoneDisplay
|
||||
from ..flightwaypointtype import FlightWaypointType
|
||||
from ...utils import nautical_miles
|
||||
|
||||
|
||||
class ArmedReconFlightPlan(FormationAttackFlightPlan, UiZoneDisplay):
|
||||
@staticmethod
|
||||
def builder_type() -> Type[Builder]:
|
||||
return Builder
|
||||
|
||||
def ui_zone(self) -> UiZone:
|
||||
return UiZone(
|
||||
[self.tot_waypoint.position],
|
||||
nautical_miles(
|
||||
self.flight.coalition.game.settings.armed_recon_engagement_range_distance
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class Builder(FormationAttackBuilder[ArmedReconFlightPlan, FormationAttackLayout]):
|
||||
def layout(self) -> FormationAttackLayout:
|
||||
return self._build(FlightWaypointType.INGRESS_ARMED_RECON)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> ArmedReconFlightPlan:
|
||||
return ArmedReconFlightPlan(self.flight, self.layout())
|
||||
@ -125,16 +125,12 @@ class Builder(IBuilder[CasFlightPlan, CasLayout]):
|
||||
ingress_point_shapely.x, ingress_point_shapely.y
|
||||
)
|
||||
|
||||
patrol_start_waypoint = builder.nav(
|
||||
patrol_start, ingress_egress_altitude, use_agl_patrol_altitude
|
||||
)
|
||||
patrol_start_waypoint = builder.cas(patrol_start, ingress_egress_altitude)
|
||||
patrol_start_waypoint.name = "FLOT START"
|
||||
patrol_start_waypoint.pretty_name = "FLOT start"
|
||||
patrol_start_waypoint.description = "FLOT boundary"
|
||||
|
||||
patrol_end_waypoint = builder.nav(
|
||||
patrol_end, ingress_egress_altitude, use_agl_patrol_altitude
|
||||
)
|
||||
patrol_end_waypoint = builder.cas(patrol_end, ingress_egress_altitude)
|
||||
patrol_end_waypoint.name = "FLOT END"
|
||||
patrol_end_waypoint.pretty_name = "FLOT end"
|
||||
patrol_end_waypoint.description = "FLOT boundary"
|
||||
|
||||
@ -11,6 +11,7 @@ from .formationattack import (
|
||||
)
|
||||
from .waypointbuilder import WaypointBuilder
|
||||
from .. import FlightType
|
||||
from ...utils import feet
|
||||
|
||||
|
||||
class EscortFlightPlan(FormationAttackFlightPlan):
|
||||
@ -34,7 +35,7 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
hold = builder.hold(self._hold_point())
|
||||
|
||||
join_pos = (
|
||||
self.package.waypoints.ingress
|
||||
WaypointBuilder.perturb(self.package.waypoints.ingress, feet(500))
|
||||
if self.flight.is_helo
|
||||
else self.package.waypoints.join
|
||||
)
|
||||
@ -59,8 +60,6 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
join = builder.join(ascent.position)
|
||||
if layout.pickup and layout.drop_off_ascent:
|
||||
join = builder.join(layout.drop_off_ascent.position)
|
||||
elif layout.pickup:
|
||||
join = builder.join(layout.pickup.position)
|
||||
split = builder.split(layout.arrival.position)
|
||||
if layout.drop_off:
|
||||
initial = builder.escort_hold(
|
||||
|
||||
@ -105,19 +105,6 @@ class FlightPlan(ABC, Generic[LayoutT]):
|
||||
#
|
||||
# Plus, it's a loiter point so there's no reason to hurry.
|
||||
factor = 0.75
|
||||
elif (
|
||||
self.flight.is_helo
|
||||
and (
|
||||
a.waypoint_type == FlightWaypointType.JOIN
|
||||
or "INGRESS" in a.waypoint_type.name
|
||||
or a.waypoint_type == FlightWaypointType.CUSTOM
|
||||
)
|
||||
and self.package.primary_flight
|
||||
and not self.package.primary_flight.flight_plan.is_airassault
|
||||
):
|
||||
# Helicopter flights should be slowed down between JOIN & INGRESS
|
||||
# to allow the escort to keep up while engaging targets along the way.
|
||||
factor = 0.50
|
||||
# TODO: Adjust if AGL.
|
||||
# We don't have an exact heightmap, but we should probably be performing
|
||||
# *some* adjustment for NTTR since the minimum altitude of the map is
|
||||
@ -268,7 +255,9 @@ class FlightPlan(ABC, Generic[LayoutT]):
|
||||
def estimate_startup(self) -> timedelta:
|
||||
if self.flight.start_type is StartType.COLD:
|
||||
if self.flight.client_count:
|
||||
return timedelta(minutes=10)
|
||||
return timedelta(
|
||||
minutes=self.flight.coalition.game.settings.player_startup_time
|
||||
)
|
||||
else:
|
||||
# The AI doesn't seem to have a real startup procedure.
|
||||
return timedelta(minutes=2)
|
||||
|
||||
@ -7,6 +7,7 @@ from .aewc import AewcFlightPlan
|
||||
from .airassault import AirAssaultFlightPlan
|
||||
from .airlift import AirliftFlightPlan
|
||||
from .antiship import AntiShipFlightPlan
|
||||
from .armedrecon import ArmedReconFlightPlan
|
||||
from .bai import BaiFlightPlan
|
||||
from .barcap import BarCapFlightPlan
|
||||
from .cas import CasFlightPlan
|
||||
@ -62,6 +63,7 @@ class FlightPlanBuilderTypes:
|
||||
FlightType.FERRY: FerryFlightPlan.builder_type(),
|
||||
FlightType.AIR_ASSAULT: AirAssaultFlightPlan.builder_type(),
|
||||
FlightType.PRETENSE_CARGO: PretenseCargoFlightPlan.builder_type(),
|
||||
FlightType.ARMED_RECON: ArmedReconFlightPlan.builder_type(),
|
||||
}
|
||||
try:
|
||||
return builder_dict[flight.flight_type]
|
||||
|
||||
@ -64,8 +64,10 @@ class FormationFlightPlan(LoiterFlightPlan, ABC):
|
||||
return min(speeds)
|
||||
|
||||
def speed_between_waypoints(self, a: FlightWaypoint, b: FlightWaypoint) -> Speed:
|
||||
if self.package.formation_speed and b in self.package_speed_waypoints:
|
||||
return self.package.formation_speed
|
||||
if (
|
||||
speed := self.package.formation_speed(self.flight.is_helo)
|
||||
) and b in self.package_speed_waypoints:
|
||||
return speed
|
||||
return super().speed_between_waypoints(a, b)
|
||||
|
||||
@property
|
||||
|
||||
@ -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 nautical_miles, Speed, feet
|
||||
from .flightplan import FlightPlan
|
||||
from .formation import FormationFlightPlan, FormationLayout
|
||||
from .ibuilder import IBuilder
|
||||
@ -39,8 +39,9 @@ class FormationAttackFlightPlan(FormationFlightPlan, ABC):
|
||||
if b.waypoint_type == FlightWaypointType.TARGET_GROUP_LOC:
|
||||
# Should be impossible, as any package with at least one
|
||||
# FormationFlightPlan flight needs a formation speed.
|
||||
assert self.package.formation_speed is not None
|
||||
return self.package.formation_speed
|
||||
speed = self.package.formation_speed(self.flight.is_helo)
|
||||
assert speed is not None
|
||||
return speed
|
||||
return super().speed_between_waypoints(a, b)
|
||||
|
||||
@property
|
||||
@ -53,7 +54,7 @@ class FormationAttackFlightPlan(FormationFlightPlan, ABC):
|
||||
"TARGET AREA",
|
||||
FlightWaypointType.TARGET_GROUP_LOC,
|
||||
self.package.target.position,
|
||||
meters(0),
|
||||
feet(0),
|
||||
"RADIO",
|
||||
)
|
||||
|
||||
@ -192,6 +193,7 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
join_pos = self.package.waypoints.join
|
||||
if self.flight.is_helo:
|
||||
join_pos = self.package.waypoints.ingress
|
||||
join_pos = WaypointBuilder.perturb(join_pos, feet(500))
|
||||
join = builder.join(join_pos)
|
||||
split = builder.split(self._get_split())
|
||||
refuel = self._build_refuel(builder)
|
||||
@ -286,6 +288,8 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
return builder.sead_area(location)
|
||||
elif flight.flight_type == FlightType.OCA_AIRCRAFT:
|
||||
return builder.oca_strike_area(location)
|
||||
elif flight.flight_type == FlightType.ARMED_RECON:
|
||||
return builder.armed_recon_area(location)
|
||||
else:
|
||||
return builder.strike_area(location)
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
from typing import (
|
||||
@ -252,18 +253,9 @@ class WaypointBuilder:
|
||||
if ingress_type in [
|
||||
FlightWaypointType.INGRESS_CAS,
|
||||
FlightWaypointType.INGRESS_OCA_AIRCRAFT,
|
||||
FlightWaypointType.INGRESS_ARMED_RECON,
|
||||
]:
|
||||
weather = self.flight.coalition.game.conditions.weather
|
||||
max_alt = feet(30000)
|
||||
if weather.clouds and (
|
||||
weather.clouds.preset
|
||||
and "overcast" in weather.clouds.preset.description.lower()
|
||||
or weather.clouds.density > 5
|
||||
):
|
||||
max_alt = meters(
|
||||
max(feet(500).meters, weather.clouds.base - feet(500).meters)
|
||||
)
|
||||
alt = min(alt, max_alt)
|
||||
alt = self._adjust_altitude_for_clouds(alt)
|
||||
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.flight.is_hercules:
|
||||
@ -291,6 +283,19 @@ class WaypointBuilder:
|
||||
targets=objective.strike_targets,
|
||||
)
|
||||
|
||||
def _adjust_altitude_for_clouds(self, alt: Distance) -> Distance:
|
||||
weather = self.flight.coalition.game.conditions.weather
|
||||
max_alt = feet(math.inf)
|
||||
if weather.clouds and (
|
||||
weather.clouds.preset
|
||||
and "overcast" in weather.clouds.preset.description.lower()
|
||||
or weather.clouds.density > 5
|
||||
):
|
||||
max_alt = meters(
|
||||
max(feet(500).meters, weather.clouds.base - feet(500).meters)
|
||||
)
|
||||
return min(alt, max_alt)
|
||||
|
||||
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:
|
||||
@ -354,6 +359,21 @@ class WaypointBuilder:
|
||||
def dead_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
return self._target_area(f"DEAD on {target.name}", target)
|
||||
|
||||
def armed_recon_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
# Force AI aircraft to fly towards target area
|
||||
alt = self.get_combat_altitude
|
||||
alt = self._adjust_altitude_for_clouds(alt)
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or alt.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
return self._target_area(
|
||||
f"ARMED RECON {target.name}",
|
||||
target,
|
||||
altitude=alt,
|
||||
alt_type=alt_type,
|
||||
flyover=True,
|
||||
)
|
||||
|
||||
def oca_strike_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
return self._target_area(f"ATTACK {target.name}", target, flyover=True)
|
||||
|
||||
@ -398,15 +418,14 @@ class WaypointBuilder:
|
||||
waypoint.only_for_player = True
|
||||
return waypoint
|
||||
|
||||
def cas(self, position: Point) -> FlightWaypoint:
|
||||
def cas(self, position: Point, altitude: Distance) -> FlightWaypoint:
|
||||
weather = self.flight.coalition.game.conditions.weather
|
||||
max_alt = feet(30000)
|
||||
if weather.clouds and (
|
||||
weather.clouds.preset
|
||||
and "overcast" in weather.clouds.preset.description.lower()
|
||||
or weather.clouds.density > 5
|
||||
):
|
||||
max_alt = meters(
|
||||
altitude = meters(
|
||||
max(feet(500).meters, weather.clouds.base - feet(500).meters)
|
||||
)
|
||||
return FlightWaypoint(
|
||||
@ -415,7 +434,7 @@ class WaypointBuilder:
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else min(meters(1000), max_alt),
|
||||
else max(meters(1000), altitude),
|
||||
"RADIO",
|
||||
description="Provide CAS",
|
||||
pretty_name="CAS",
|
||||
@ -667,14 +686,13 @@ class WaypointBuilder:
|
||||
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)
|
||||
alt = self.get_combat_altitude if self.flight.is_helo else meters(0)
|
||||
|
||||
return FlightWaypoint(
|
||||
"DROPOFFZONE",
|
||||
FlightWaypointType.DROPOFF_ZONE,
|
||||
drop_off.position,
|
||||
altitude,
|
||||
alt,
|
||||
"RADIO",
|
||||
description=f"Drop off cargo at {drop_off.name}",
|
||||
pretty_name="Drop-off zone",
|
||||
@ -772,8 +790,7 @@ class WaypointBuilder:
|
||||
return previous_threatened and next_threatened
|
||||
|
||||
@staticmethod
|
||||
def perturb(point: Point) -> Point:
|
||||
deviation = nautical_miles(1)
|
||||
def perturb(point: Point, deviation: Distance = nautical_miles(1)) -> Point:
|
||||
x_adj = random.randint(int(-deviation.meters), int(deviation.meters))
|
||||
y_adj = random.randint(int(-deviation.meters), int(deviation.meters))
|
||||
return point + Vector2(x_adj, y_adj)
|
||||
|
||||
@ -58,9 +58,8 @@ class FlightType(Enum):
|
||||
FERRY = "Ferry"
|
||||
AIR_ASSAULT = "Air Assault"
|
||||
SEAD_SWEEP = "SEAD Sweep" # Reintroduce legacy "engage-whatever-you-can-find" SEAD
|
||||
PRETENSE_CARGO = (
|
||||
"Cargo Transport" # Flight type for Pretense campaign AI cargo planes
|
||||
)
|
||||
PRETENSE_CARGO = "Cargo Transport" # For Pretense campaign AI cargo planes
|
||||
ARMED_RECON = "Armed Recon"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
@ -96,6 +95,7 @@ class FlightType(Enum):
|
||||
FlightType.SEAD_ESCORT,
|
||||
FlightType.AIR_ASSAULT,
|
||||
FlightType.SEAD_SWEEP,
|
||||
FlightType.ARMED_RECON,
|
||||
}
|
||||
|
||||
@property
|
||||
@ -107,6 +107,7 @@ class FlightType(Enum):
|
||||
return {
|
||||
FlightType.AEWC: AirEntity.AIRBORNE_EARLY_WARNING,
|
||||
FlightType.ANTISHIP: AirEntity.ANTISURFACE_WARFARE,
|
||||
FlightType.ARMED_RECON: AirEntity.ATTACK_STRIKE,
|
||||
FlightType.BAI: AirEntity.ATTACK_STRIKE,
|
||||
FlightType.BARCAP: AirEntity.FIGHTER,
|
||||
FlightType.CAS: AirEntity.ATTACK_STRIKE,
|
||||
|
||||
@ -51,3 +51,4 @@ class FlightWaypointType(IntEnum):
|
||||
INGRESS_AIR_ASSAULT = 31
|
||||
INGRESS_ANTI_SHIP = 32
|
||||
INGRESS_SEAD_SWEEP = 33
|
||||
INGRESS_ARMED_RECON = 34
|
||||
|
||||
@ -208,6 +208,7 @@ class Loadout:
|
||||
loadout_names[FlightType.INTERCEPTION].extend(loadout_names[FlightType.BARCAP])
|
||||
# OCA/Aircraft falls back to BAI, which falls back to CAS.
|
||||
loadout_names[FlightType.BAI].extend(loadout_names[FlightType.CAS])
|
||||
loadout_names[FlightType.ARMED_RECON].extend(loadout_names[FlightType.CAS])
|
||||
loadout_names[FlightType.OCA_AIRCRAFT].extend(loadout_names[FlightType.BAI])
|
||||
# DEAD also falls back to BAI.
|
||||
loadout_names[FlightType.DEAD].extend(loadout_names[FlightType.BAI])
|
||||
|
||||
@ -54,8 +54,7 @@ class Package(RadioFrequencyContainer):
|
||||
def has_players(self) -> bool:
|
||||
return any(flight.client_count for flight in self.flights)
|
||||
|
||||
@property
|
||||
def formation_speed(self) -> Optional[Speed]:
|
||||
def formation_speed(self, is_helo: bool) -> Optional[Speed]:
|
||||
"""The speed of the package when in formation.
|
||||
|
||||
If none of the flights in the package will join a formation, this
|
||||
@ -66,7 +65,10 @@ class Package(RadioFrequencyContainer):
|
||||
"""
|
||||
speeds = []
|
||||
for flight in self.flights:
|
||||
if isinstance(flight.flight_plan, FormationFlightPlan):
|
||||
if (
|
||||
isinstance(flight.flight_plan, FormationFlightPlan)
|
||||
and flight.is_helo == is_helo
|
||||
):
|
||||
speeds.append(flight.flight_plan.best_flight_formation_speed)
|
||||
if not speeds:
|
||||
return None
|
||||
@ -183,6 +185,7 @@ class Package(RadioFrequencyContainer):
|
||||
FlightType.SEAD_SWEEP,
|
||||
FlightType.TARCAP,
|
||||
FlightType.BARCAP,
|
||||
FlightType.ARMED_RECON,
|
||||
FlightType.AEWC,
|
||||
FlightType.FERRY,
|
||||
FlightType.REFUELING,
|
||||
|
||||
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from game.utils import Distance, SPEED_OF_SOUND_AT_SEA_LEVEL, Speed, mach, meters
|
||||
from game.utils import Distance, SPEED_OF_SOUND_AT_SEA_LEVEL, Speed, mach
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .flight import Flight
|
||||
@ -30,8 +30,8 @@ class GroundSpeed:
|
||||
# as it can at sea level. This probably isn't great assumption, but
|
||||
# might. be sufficient given the wiggle room. We can come up with
|
||||
# another heuristic if needed.
|
||||
cruise_mach = max_speed.mach() * (0.60 if flight.is_helo else 0.85)
|
||||
return mach(cruise_mach, altitude if not flight.is_helo else meters(0))
|
||||
cruise_mach = max_speed.mach() * (0.7 if flight.is_helo else 0.85)
|
||||
return mach(cruise_mach, altitude)
|
||||
|
||||
|
||||
# TODO: Most if not all of this should move into FlightPlan.
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import random
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from game.squadrons import Squadron
|
||||
@ -101,9 +102,10 @@ class DefaultSquadronAssigner:
|
||||
if aircraft not in self.coalition.faction.all_aircrafts:
|
||||
return None
|
||||
|
||||
lo = self.coalition.faction.liveries_overrides
|
||||
squadron_def = self.find_squadron_for_airframe(aircraft, task, control_point)
|
||||
if squadron_def is not None and lo.get(aircraft) is None:
|
||||
if squadron_def is not None and (
|
||||
squadron_def.livery is not None or squadron_def.livery_set is not None
|
||||
):
|
||||
return squadron_def
|
||||
|
||||
# No premade squadron available for this aircraft that meets the requirements,
|
||||
@ -124,11 +126,14 @@ class DefaultSquadronAssigner:
|
||||
def find_squadron_for_airframe(
|
||||
self, aircraft: AircraftType, task: FlightType, control_point: ControlPoint
|
||||
) -> Optional[SquadronDef]:
|
||||
choices = []
|
||||
for squadron in self.air_wing.squadron_defs[aircraft]:
|
||||
if not squadron.claimed and self.squadron_compatible_with(
|
||||
squadron, task, control_point
|
||||
):
|
||||
return squadron
|
||||
choices.append(squadron)
|
||||
if choices:
|
||||
return random.choice(choices)
|
||||
return None
|
||||
|
||||
def find_squadron_by_name(
|
||||
|
||||
@ -167,24 +167,6 @@ class ObjectiveFinder:
|
||||
yield cp
|
||||
break
|
||||
|
||||
def vulnerable_enemy_control_points(self) -> Iterator[ControlPoint]:
|
||||
"""Iterates over enemy CPs that are vulnerable to Air Assault.
|
||||
Vulnerability is defined as any unit being alive in the CP's "blocking_capture" groups.
|
||||
"""
|
||||
for cp in self.enemy_control_points():
|
||||
include = True
|
||||
for tgo in cp.connected_objectives:
|
||||
if tgo.distance_to(cp) > cp.CAPTURE_DISTANCE.meters:
|
||||
continue
|
||||
for u in tgo.units:
|
||||
if u.is_vehicle and u.alive:
|
||||
include = False
|
||||
break
|
||||
if not include:
|
||||
break
|
||||
if include:
|
||||
yield cp
|
||||
|
||||
def oca_targets(self, min_aircraft: int) -> Iterator[ControlPoint]:
|
||||
parking_type = ParkingType()
|
||||
parking_type.include_rotary_wing = True
|
||||
|
||||
@ -6,7 +6,7 @@ import math
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional, TYPE_CHECKING, Union
|
||||
from typing import Optional, TYPE_CHECKING, Union, Dict
|
||||
|
||||
from game.commander.battlepositions import BattlePositions
|
||||
from game.commander.objectivefinder import ObjectiveFinder
|
||||
@ -163,6 +163,15 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
barcap_duration = coalition.doctrine.cap_duration.total_seconds()
|
||||
barcap_rounds = math.ceil(mission_duration / barcap_duration)
|
||||
|
||||
battle_postitions: Dict[ControlPoint, BattlePositions] = {
|
||||
cp: BattlePositions.for_control_point(cp)
|
||||
for cp in ordered_capturable_points
|
||||
}
|
||||
|
||||
vulnerable_control_points = [
|
||||
cp for cp, bp in battle_postitions.items() if not bp.blocking_capture
|
||||
]
|
||||
|
||||
return TheaterState(
|
||||
context=context,
|
||||
barcaps_needed={
|
||||
@ -179,10 +188,7 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
enemy_convoys=list(finder.convoys()),
|
||||
enemy_shipping=list(finder.cargo_ships()),
|
||||
enemy_ships=list(finder.enemy_ships()),
|
||||
enemy_battle_positions={
|
||||
cp: BattlePositions.for_control_point(cp)
|
||||
for cp in ordered_capturable_points
|
||||
},
|
||||
enemy_battle_positions=battle_postitions,
|
||||
oca_targets=list(
|
||||
finder.oca_targets(
|
||||
min_aircraft=game.settings.oca_target_autoplanner_min_aircraft_count
|
||||
@ -191,5 +197,5 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
strike_targets=list(finder.strike_targets()),
|
||||
enemy_barcaps=list(game.theater.control_points_for(not player)),
|
||||
threat_zones=game.threat_zone_for(not player),
|
||||
vulnerable_control_points=list(finder.vulnerable_enemy_control_points()),
|
||||
vulnerable_control_points=vulnerable_control_points,
|
||||
)
|
||||
|
||||
@ -241,9 +241,18 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
enrich = {}
|
||||
for t in self.task_priorities:
|
||||
if t == FlightType.SEAD:
|
||||
enrich[FlightType.SEAD_SWEEP] = self.task_priorities[t]
|
||||
if FlightType.SEAD_SWEEP not in self.task_priorities:
|
||||
if (value := self.task_priorities.get(FlightType.SEAD)) or (
|
||||
value := self.task_priorities.get(FlightType.SEAD_ESCORT)
|
||||
):
|
||||
enrich[FlightType.SEAD_SWEEP] = value
|
||||
|
||||
if FlightType.ARMED_RECON not in self.task_priorities:
|
||||
if (value := self.task_priorities.get(FlightType.CAS)) or (
|
||||
value := self.task_priorities.get(FlightType.BAI)
|
||||
):
|
||||
enrich[FlightType.ARMED_RECON] = value
|
||||
|
||||
self.task_priorities.update(enrich)
|
||||
|
||||
@classmethod
|
||||
@ -299,17 +308,24 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
elif max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL * 0.7:
|
||||
# Semi-fast like airliners or similar
|
||||
return (
|
||||
Speed.from_mach(0.5, altitude)
|
||||
Speed.from_mach(0.6, altitude)
|
||||
if altitude.feet > 20000
|
||||
else Speed.from_mach(0.4, altitude)
|
||||
else Speed.from_mach(0.5, altitude)
|
||||
)
|
||||
elif self.helicopter:
|
||||
return max_speed * 0.4
|
||||
else:
|
||||
# Slow like warbirds or helicopters
|
||||
# Use whichever is slowest - mach 0.35 or 50% of max speed
|
||||
logging.debug(
|
||||
f"{self.display_name} max_speed * 0.5 is {max_speed * 0.5}"
|
||||
# Slow like warbirds or attack planes
|
||||
# return 50% of max speed + 5% per 2k above 10k to maintain momentum
|
||||
return max_speed * min(
|
||||
1.0,
|
||||
0.5
|
||||
+ (
|
||||
(((altitude.feet - 10000) / 2000) * 0.05)
|
||||
if altitude.feet > 10000
|
||||
else 0
|
||||
),
|
||||
)
|
||||
return min(Speed.from_mach(0.35, altitude), max_speed * 0.5)
|
||||
|
||||
@cached_property
|
||||
def preferred_cruise_altitude(self) -> Distance:
|
||||
@ -526,17 +542,7 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
if prop_overrides is not None:
|
||||
cls._set_props_overrides(prop_overrides, aircraft)
|
||||
|
||||
from game.ato.flighttype import FlightType
|
||||
|
||||
task_priorities: dict[FlightType, int] = {}
|
||||
for task_name, priority in data.get("tasks", {}).items():
|
||||
task_priorities[FlightType(task_name)] = priority
|
||||
|
||||
if (
|
||||
FlightType.SEAD_SWEEP not in task_priorities
|
||||
and FlightType.SEAD in task_priorities
|
||||
):
|
||||
task_priorities[FlightType.SEAD_SWEEP] = task_priorities[FlightType.SEAD]
|
||||
task_priorities = cls.get_task_priorities(data)
|
||||
|
||||
cls._custom_weapon_injections(aircraft, data)
|
||||
cls._user_weapon_injections(aircraft)
|
||||
@ -583,6 +589,27 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
use_f15e_waypoint_names=data.get("use_f15e_waypoint_names", False),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_task_priorities(cls, data: dict[str, Any]) -> dict[FlightType, int]:
|
||||
task_priorities: dict[FlightType, int] = {}
|
||||
for task_name, priority in data.get("tasks", {}).items():
|
||||
task_priorities[FlightType(task_name)] = priority
|
||||
if (
|
||||
FlightType.SEAD_SWEEP not in task_priorities
|
||||
and FlightType.SEAD in task_priorities
|
||||
):
|
||||
task_priorities[FlightType.SEAD_SWEEP] = task_priorities[FlightType.SEAD]
|
||||
if FlightType.ARMED_RECON not in task_priorities:
|
||||
if FlightType.CAS in task_priorities:
|
||||
task_priorities[FlightType.ARMED_RECON] = task_priorities[
|
||||
FlightType.CAS
|
||||
]
|
||||
elif FlightType.BAI in task_priorities:
|
||||
task_priorities[FlightType.ARMED_RECON] = task_priorities[
|
||||
FlightType.BAI
|
||||
]
|
||||
return task_priorities
|
||||
|
||||
@staticmethod
|
||||
def _custom_weapon_injections(
|
||||
aircraft: Type[FlyingType], data: Dict[str, Any]
|
||||
|
||||
@ -352,6 +352,45 @@ class Faction:
|
||||
self.remove_aircraft("A-4E-C")
|
||||
if not mod_settings.hercules:
|
||||
self.remove_aircraft("Hercules")
|
||||
if not mod_settings.oh_6:
|
||||
self.remove_aircraft("OH-6A")
|
||||
if not mod_settings.oh_6_vietnamassetpack:
|
||||
self.remove_vehicle("vap_mutt_gun")
|
||||
self.remove_vehicle("vap_type63_mlrs")
|
||||
self.remove_vehicle("vap_vc_bicycle_mortar")
|
||||
self.remove_vehicle("vap_zis_150_aa")
|
||||
self.remove_vehicle("vap_us_hooch_LP")
|
||||
self.remove_vehicle("vap_ammo_50cal_line")
|
||||
self.remove_vehicle("vap_ammo_50cal_pack")
|
||||
self.remove_vehicle("vap_barrels_line")
|
||||
self.remove_vehicle("vap_barrels")
|
||||
self.remove_vehicle("vap_ammo_box_pile")
|
||||
self.remove_vehicle("vap_ammo_box_wood_long")
|
||||
self.remove_vehicle("vap_ammo_box_wood_small")
|
||||
self.remove_vehicle("vap_barrel_red")
|
||||
self.remove_vehicle("vap_barrel_green")
|
||||
self.remove_vehicle("vap_mre_boxes")
|
||||
self.remove_vehicle("vap_mixed_cargo_1")
|
||||
self.remove_vehicle("vap_mixed_cargo_2")
|
||||
self.remove_vehicle("vap_watchtower")
|
||||
self.remove_vehicle("vap_house_high")
|
||||
self.remove_vehicle("vap_house_long")
|
||||
self.remove_vehicle("vap_house_small")
|
||||
self.remove_vehicle("vap_house_T")
|
||||
self.remove_vehicle("vap_house_tiny")
|
||||
self.remove_vehicle("vap_house1")
|
||||
self.remove_vehicle("vap_us_hooch_radio")
|
||||
self.remove_vehicle("vap_us_hooch_closed")
|
||||
self.remove_vehicle("vap_vc_bunker_single")
|
||||
self.remove_vehicle("vap_vc_mg_nest")
|
||||
self.remove_vehicle("vap_mule")
|
||||
self.remove_vehicle("vap_mutt")
|
||||
self.remove_vehicle("vap_m35_truck")
|
||||
self.remove_vehicle("vap_vc_zis")
|
||||
self.remove_vehicle("vap_vc_bicycle")
|
||||
self.remove_vehicle("vap_vc_zil")
|
||||
self.remove_vehicle("vap_vc_bicycle_ak")
|
||||
self.remove_ship("vap_us_seafloat")
|
||||
if not mod_settings.uh_60l:
|
||||
self.remove_aircraft("UH-60L")
|
||||
self.remove_aircraft("KC130J")
|
||||
|
||||
@ -11,6 +11,7 @@ from game.ato.flightplans.formation import FormationLayout
|
||||
from game.ato.flightplans.waypointbuilder import WaypointBuilder
|
||||
from game.ato.packagewaypoints import PackageWaypoints
|
||||
from game.data.doctrine import MODERN_DOCTRINE, COLDWAR_DOCTRINE, WWII_DOCTRINE
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.theater import ParkingType, SeasonalConditions
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -164,6 +165,7 @@ class Migrator:
|
||||
try_set_attr(s, "max_size", 12)
|
||||
try_set_attr(s, "radio_presets", {})
|
||||
try_set_attr(s, "livery_set", [])
|
||||
s.aircraft = AircraftType.named(s.aircraft.variant_id)
|
||||
if isinstance(s.country, str):
|
||||
c = country_dict.get(s.country, s.country)
|
||||
s.country = countries_by_name[c]()
|
||||
|
||||
@ -57,6 +57,8 @@ class AircraftBehavior:
|
||||
self.configure_refueling(group, flight)
|
||||
elif self.task in [FlightType.CAS, FlightType.BAI]:
|
||||
self.configure_cas(group, flight)
|
||||
elif self.task == FlightType.ARMED_RECON:
|
||||
self.configure_armed_recon(group, flight)
|
||||
elif self.task == FlightType.DEAD:
|
||||
self.configure_dead(group, flight)
|
||||
elif self.task in [FlightType.SEAD, FlightType.SEAD_SWEEP]:
|
||||
@ -183,6 +185,17 @@ class AircraftBehavior:
|
||||
restrict_jettison=True,
|
||||
)
|
||||
|
||||
def configure_armed_recon(self, group: FlyingGroup[Any], flight: Flight) -> None:
|
||||
self.configure_task(flight, group, CAS, [AFAC, AntishipStrike])
|
||||
self.configure_behavior(
|
||||
flight,
|
||||
group,
|
||||
react_on_threat=OptReactOnThreat.Values.EvadeFire,
|
||||
roe=OptROE.Values.OpenFire,
|
||||
rtb_winchester=OptRTBOnOutOfAmmo.Values.All,
|
||||
restrict_jettison=True,
|
||||
)
|
||||
|
||||
def configure_dead(self, group: FlyingGroup[Any], flight: Flight) -> None:
|
||||
# Only CAS and SEAD are capable of the Attack Group task. SEAD is arguably more
|
||||
# appropriate but it has an extremely limited list of capable aircraft, whereas
|
||||
@ -379,23 +392,35 @@ class AircraftBehavior:
|
||||
|
||||
if preferred_task in flight.unit_type.dcs_unit_type.tasks:
|
||||
group.task = preferred_task.name
|
||||
elif fallback_tasks:
|
||||
return
|
||||
if fallback_tasks:
|
||||
for task in fallback_tasks:
|
||||
if task in flight.unit_type.dcs_unit_type.tasks:
|
||||
group.task = task.name
|
||||
return
|
||||
elif flight.unit_type.dcs_unit_type.task_default and preferred_task == Nothing:
|
||||
if flight.unit_type.dcs_unit_type.task_default and preferred_task == Nothing:
|
||||
group.task = flight.unit_type.dcs_unit_type.task_default.name
|
||||
logging.warning(
|
||||
f"{ac_type} is not capable of 'Nothing', using default task '{group.task}'"
|
||||
)
|
||||
else:
|
||||
fallback_part = (
|
||||
f" nor any of the following fall-back tasks: {[task.name for task in fallback_tasks]}"
|
||||
if fallback_tasks
|
||||
else ""
|
||||
return
|
||||
if flight.roster.members and flight.roster.members[0].is_player:
|
||||
group.task = (
|
||||
flight.unit_type.dcs_unit_type.task_default.name
|
||||
if flight.unit_type.dcs_unit_type.task_default
|
||||
else group.task # even if this is incompatible, if it's a client we don't really care...
|
||||
)
|
||||
raise RuntimeError(
|
||||
f"{ac_type} is neither capable of {preferred_task.name}"
|
||||
f"{fallback_part}. Can't generate {flight.flight_type} flight."
|
||||
logging.warning(
|
||||
f"Client override: {ac_type} is not capable of '{preferred_task}', using default task '{group.task}'"
|
||||
)
|
||||
return
|
||||
|
||||
fallback_part = (
|
||||
f" nor any of the following fall-back tasks: {[task.name for task in fallback_tasks]}"
|
||||
if fallback_tasks
|
||||
else ""
|
||||
)
|
||||
raise RuntimeError(
|
||||
f"{ac_type} is neither capable of {preferred_task.name}"
|
||||
f"{fallback_part}. Can't generate {flight.flight_type} flight."
|
||||
)
|
||||
|
||||
@ -497,21 +497,20 @@ class FlightGroupSpawner:
|
||||
) -> Optional[FlyingGroup[Any]]:
|
||||
is_airbase = False
|
||||
is_roadbase = False
|
||||
ground_spawn = None
|
||||
|
||||
try:
|
||||
if is_large:
|
||||
if len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
is_airbase = True
|
||||
else:
|
||||
if len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
is_roadbase = True
|
||||
if len(self.ground_spawns[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
is_airbase = True
|
||||
except IndexError as ex:
|
||||
logging.warning("Not enough ground spawn slots available at " + str(ex))
|
||||
if not is_large and len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
is_roadbase = True
|
||||
elif not is_large and len(self.ground_spawns[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
is_airbase = True
|
||||
elif len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
is_airbase = True
|
||||
|
||||
if ground_spawn is None:
|
||||
logging.warning("Not enough ground spawn slots available at " + cp.name)
|
||||
return None
|
||||
|
||||
group = self._generate_at_group(name, ground_spawn[0])
|
||||
@ -581,14 +580,12 @@ class FlightGroupSpawner:
|
||||
for i in range(self.flight.count - 1):
|
||||
try:
|
||||
terrain = cp.coalition.game.theater.terrain
|
||||
if is_large:
|
||||
if len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
else:
|
||||
if len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
else:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
if not is_large and len(self.ground_spawns_roadbase[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_roadbase[cp].pop()
|
||||
elif not is_large and len(self.ground_spawns[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns[cp].pop()
|
||||
elif len(self.ground_spawns_large[cp]) > 0:
|
||||
ground_spawn = self.ground_spawns_large[cp].pop()
|
||||
group.units[1 + i].position = Point(
|
||||
ground_spawn[0].x, ground_spawn[0].y, terrain=terrain
|
||||
)
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
from dcs.point import MovingPoint
|
||||
from dcs.task import (
|
||||
OptECMUsing,
|
||||
ControlledTask,
|
||||
Targets,
|
||||
EngageTargetsInZone,
|
||||
)
|
||||
|
||||
from game.utils import nautical_miles
|
||||
from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||
|
||||
|
||||
class ArmedReconIngressBuilder(PydcsWaypointBuilder):
|
||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||
self.register_special_ingress_points()
|
||||
# Preemptively use ECM to better avoid getting swatted.
|
||||
ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar)
|
||||
waypoint.tasks.append(ecm_option)
|
||||
|
||||
waypoint.add_task(
|
||||
ControlledTask(
|
||||
EngageTargetsInZone(
|
||||
position=self.flight.flight_plan.tot_waypoint.position,
|
||||
radius=int(
|
||||
nautical_miles(
|
||||
self.flight.coalition.game.settings.armed_recon_engagement_range_distance
|
||||
).meters
|
||||
),
|
||||
targets=[
|
||||
Targets.All.GroundUnits,
|
||||
Targets.All.Air.Helicopters,
|
||||
],
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -17,7 +17,7 @@ class HoldPointBuilder(PydcsWaypointBuilder):
|
||||
loiter = ControlledTask(
|
||||
OrbitAction(
|
||||
altitude=waypoint.alt,
|
||||
speed=speed.meters_per_second,
|
||||
speed=speed.kph,
|
||||
pattern=OrbitAction.OrbitPattern.Circle,
|
||||
)
|
||||
)
|
||||
|
||||
@ -8,7 +8,6 @@ from dcs.task import (
|
||||
OptECMUsing,
|
||||
OptFormation,
|
||||
Targets,
|
||||
OptROE,
|
||||
SetUnlimitedFuelCommand,
|
||||
)
|
||||
|
||||
@ -94,12 +93,6 @@ class JoinPointBuilder(PydcsWaypointBuilder):
|
||||
max_dist: float = 30.0,
|
||||
vertical_spacing: float = 2000.0,
|
||||
) -> None:
|
||||
if self.flight.is_helo:
|
||||
# Make helicopters a bit more aggressive
|
||||
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFireWeaponFree))
|
||||
else:
|
||||
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFire))
|
||||
|
||||
rx = (random.random() + 0.1) * 333
|
||||
ry = feet(vertical_spacing).meters
|
||||
rz = (random.random() + 0.1) * 166 * random.choice([-1, 1])
|
||||
|
||||
@ -3,7 +3,7 @@ import logging
|
||||
from dcs.point import MovingPoint
|
||||
from dcs.task import EngageTargetsInZone, Targets
|
||||
|
||||
from game.theater import Airfield
|
||||
from game.theater import Airfield, Fob
|
||||
from game.utils import nautical_miles
|
||||
from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||
|
||||
@ -12,7 +12,7 @@ class OcaAircraftIngressBuilder(PydcsWaypointBuilder):
|
||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||
target = self.package.target
|
||||
self.register_special_ingress_points()
|
||||
if not isinstance(target, Airfield):
|
||||
if not (isinstance(target, Airfield) or isinstance(target, Fob)):
|
||||
logging.error(
|
||||
"Unexpected target type for OCA Strike mission: %s",
|
||||
target.__class__.__name__,
|
||||
|
||||
@ -2,9 +2,8 @@ from dcs.point import MovingPoint
|
||||
from dcs.task import (
|
||||
OptECMUsing,
|
||||
ControlledTask,
|
||||
EngageTargets,
|
||||
Targets,
|
||||
OptROE,
|
||||
EngageTargetsInZone,
|
||||
)
|
||||
|
||||
from game.utils import nautical_miles
|
||||
@ -14,16 +13,15 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||
class SeadSweepIngressBuilder(PydcsWaypointBuilder):
|
||||
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||
self.register_special_ingress_points()
|
||||
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFireWeaponFree))
|
||||
# Preemptively use ECM to better avoid getting swatted.
|
||||
ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar)
|
||||
waypoint.tasks.append(ecm_option)
|
||||
|
||||
waypoint.add_task(
|
||||
ControlledTask(
|
||||
EngageTargets(
|
||||
# TODO: From doctrine.
|
||||
max_distance=int(
|
||||
EngageTargetsInZone(
|
||||
position=self.flight.flight_plan.tot_waypoint.position,
|
||||
radius=int(
|
||||
nautical_miles(
|
||||
self.flight.coalition.game.settings.sead_sweep_engagement_range_distance
|
||||
).meters
|
||||
|
||||
@ -22,6 +22,7 @@ from game.settings import Settings
|
||||
from game.utils import pairwise
|
||||
from .airassaultingress import AirAssaultIngressBuilder
|
||||
from .antishipingress import AntiShipIngressBuilder
|
||||
from .armedreconingress import ArmedReconIngressBuilder
|
||||
from .baiingress import BaiIngressBuilder
|
||||
from .casingress import CasIngressBuilder
|
||||
from .deadingress import DeadIngressBuilder
|
||||
@ -136,6 +137,7 @@ class WaypointGenerator:
|
||||
FlightWaypointType.DROPOFF_ZONE: LandingZoneBuilder,
|
||||
FlightWaypointType.INGRESS_AIR_ASSAULT: AirAssaultIngressBuilder,
|
||||
FlightWaypointType.INGRESS_ANTI_SHIP: AntiShipIngressBuilder,
|
||||
FlightWaypointType.INGRESS_ARMED_RECON: ArmedReconIngressBuilder,
|
||||
FlightWaypointType.INGRESS_BAI: BaiIngressBuilder,
|
||||
FlightWaypointType.INGRESS_CAS: CasIngressBuilder,
|
||||
FlightWaypointType.INGRESS_DEAD: DeadIngressBuilder,
|
||||
@ -203,7 +205,10 @@ class WaypointGenerator:
|
||||
not self.flight.state.in_flight
|
||||
and self.flight.state.spawn_type is not StartType.RUNWAY
|
||||
and self.flight.departure.is_fleet
|
||||
and not self.flight.client_count
|
||||
and not (
|
||||
self.flight.client_count
|
||||
and self.flight.coalition.game.settings.player_flights_sixpack
|
||||
)
|
||||
):
|
||||
# https://github.com/dcs-liberation/dcs_liberation/issues/1309
|
||||
# Without a delay, AI aircraft will be spawned on the sixpack, which other
|
||||
|
||||
@ -325,6 +325,20 @@ class Settings:
|
||||
default=2,
|
||||
detail="Creates a randomized altitude offset for airplanes.",
|
||||
)
|
||||
|
||||
player_startup_time: int = bounded_int_option(
|
||||
"Player startup time",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=GENERAL_SECTION,
|
||||
default=10,
|
||||
min=0,
|
||||
max=100,
|
||||
detail=(
|
||||
"The startup time allocated to player flights (default : 10 minutes, AI is 2 minutes). "
|
||||
"Packages have to be planned again for this to take effect. "
|
||||
),
|
||||
)
|
||||
|
||||
# Doctrine Distances Section
|
||||
airbase_threat_range: int = bounded_int_option(
|
||||
"Airbase threat range (NM)",
|
||||
@ -346,6 +360,14 @@ class Settings:
|
||||
min=0,
|
||||
max=100,
|
||||
)
|
||||
armed_recon_engagement_range_distance: int = bounded_int_option(
|
||||
"Armed Recon engagement range (NM)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
section=DOCTRINE_DISTANCES_SECTION,
|
||||
default=5,
|
||||
min=0,
|
||||
max=25,
|
||||
)
|
||||
sead_sweep_engagement_range_distance: int = bounded_int_option(
|
||||
"SEAD Sweep engagement range (NM)",
|
||||
page=CAMPAIGN_DOCTRINE_PAGE,
|
||||
@ -424,6 +446,7 @@ class Settings:
|
||||
"range is defined in the helicopter's yaml specification."
|
||||
),
|
||||
)
|
||||
|
||||
# Pilots and Squadrons
|
||||
ai_pilot_levelling: bool = boolean_option(
|
||||
"Allow AI pilot leveling",
|
||||
@ -944,6 +967,12 @@ class Settings:
|
||||
default=True,
|
||||
detail=("Enables dynamic cargo for airfields, ships, FARPs & warehouses."),
|
||||
)
|
||||
player_flights_sixpack: bool = boolean_option(
|
||||
"Player flights can spawn on the sixpack",
|
||||
MISSION_GENERATOR_PAGE,
|
||||
GAMEPLAY_SECTION,
|
||||
default=True,
|
||||
)
|
||||
|
||||
# Performance
|
||||
perf_smoke_gen: bool = boolean_option(
|
||||
|
||||
@ -1388,6 +1388,11 @@ class NavalControlPoint(
|
||||
FlightType.SEAD_ESCORT,
|
||||
]
|
||||
yield from super().mission_types(for_player)
|
||||
if self.is_friendly(for_player):
|
||||
yield from [
|
||||
FlightType.AEWC,
|
||||
FlightType.REFUELING,
|
||||
]
|
||||
|
||||
@property
|
||||
def heading(self) -> Heading:
|
||||
@ -1486,16 +1491,6 @@ class Carrier(NavalControlPoint):
|
||||
def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]:
|
||||
return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.CARRIER
|
||||
|
||||
def mission_types(self, for_player: bool) -> Iterator[FlightType]:
|
||||
from game.ato.flighttype import FlightType
|
||||
|
||||
yield from super().mission_types(for_player)
|
||||
if self.is_friendly(for_player):
|
||||
yield from [
|
||||
FlightType.AEWC,
|
||||
FlightType.REFUELING,
|
||||
]
|
||||
|
||||
def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None:
|
||||
raise RuntimeError("Carriers cannot be captured")
|
||||
|
||||
@ -1661,7 +1656,6 @@ class Fob(ControlPoint, RadioFrequencyContainer, CTLD):
|
||||
from game.ato import FlightType
|
||||
|
||||
if not self.is_friendly(for_player):
|
||||
yield FlightType.STRIKE
|
||||
yield FlightType.AIR_ASSAULT
|
||||
if self.total_aircraft_parking(ParkingType(True, True, True)):
|
||||
yield FlightType.OCA_AIRCRAFT
|
||||
|
||||
@ -39,6 +39,7 @@ class MissionTarget:
|
||||
FlightType.TARCAP,
|
||||
FlightType.SEAD_ESCORT,
|
||||
FlightType.SEAD_SWEEP,
|
||||
FlightType.ARMED_RECON,
|
||||
FlightType.SWEEP,
|
||||
# TODO: FlightType.ELINT,
|
||||
# TODO: FlightType.EWAR,
|
||||
|
||||
@ -84,6 +84,8 @@ class ModSettings:
|
||||
f106_deltadart: bool = False
|
||||
hercules: bool = False
|
||||
irondome: bool = False
|
||||
oh_6: bool = False
|
||||
oh_6_vietnamassetpack: bool = False
|
||||
uh_60l: bool = False
|
||||
jas39_gripen: bool = False
|
||||
sk_60: bool = False
|
||||
|
||||
@ -21,6 +21,8 @@ from .hercules import *
|
||||
from .highdigitsams import *
|
||||
from .irondome import *
|
||||
from .jas39 import *
|
||||
from .oh6 import *
|
||||
from .oh6_vietnamassetpack import *
|
||||
from .ov10a import *
|
||||
from .spanishnavypack import *
|
||||
from .super_etendard import *
|
||||
|
||||
1
pydcs_extensions/oh6/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .oh6 import *
|
||||
161
pydcs_extensions/oh6/oh6.py
Normal file
@ -0,0 +1,161 @@
|
||||
from typing import Set
|
||||
|
||||
from dcs import task
|
||||
from dcs.helicopters import HelicopterType
|
||||
|
||||
from game.modsupport import helicoptermod
|
||||
from pydcs_extensions.weapon_injector import inject_weapons
|
||||
|
||||
|
||||
class WeaponsOH6:
|
||||
Camrig = {"clsid": "{OH-6_CAMRIG}", "name": "Camrig", "weight": 70}
|
||||
Frag_Grenade = {"clsid": "{OH6_FRAG}", "name": "Frag Grenade", "weight": 0}
|
||||
M134_Door_Minigun = {
|
||||
"clsid": "{OH-6_M134_Door}",
|
||||
"name": "M134 Door Minigun",
|
||||
"weight": 110,
|
||||
}
|
||||
M134_Minigun_ = {
|
||||
"clsid": "{OH-6_M134_Minigun}",
|
||||
"name": "M134 Minigun",
|
||||
"weight": 39,
|
||||
}
|
||||
M60_Doorgun = {"clsid": "{OH-6_M60_Door}", "name": "M60 Doorgun", "weight": 110}
|
||||
Searchlight = {"clsid": "{OH-6_Searchlight}", "name": "Searchlight", "weight": 70}
|
||||
SMOKE_Grenade_Blue = {
|
||||
"clsid": "{OH6_SMOKE_BLUE}",
|
||||
"name": "SMOKE Grenade Blue",
|
||||
"weight": 0,
|
||||
}
|
||||
SMOKE_Grenade_Green = {
|
||||
"clsid": "{OH6_SMOKE_GREEN}",
|
||||
"name": "SMOKE Grenade Green",
|
||||
"weight": 0,
|
||||
}
|
||||
SMOKE_Grenade_RED = {
|
||||
"clsid": "{OH6_SMOKE_RED}",
|
||||
"name": "SMOKE Grenade RED",
|
||||
"weight": 0,
|
||||
}
|
||||
SMOKE_Grenade_yellow = {
|
||||
"clsid": "{OH6_SMOKE_YELLOW}",
|
||||
"name": "SMOKE Grenade yellow",
|
||||
"weight": 0,
|
||||
}
|
||||
XM158_Weapon_System__4_ = {
|
||||
"clsid": "{OH6_XM158_4}",
|
||||
"name": "XM158 Weapon System (4)",
|
||||
"weight": 76.8,
|
||||
}
|
||||
XM158_Weapon_System__7_ = {
|
||||
"clsid": "{OH6_XM158}",
|
||||
"name": "XM158 Weapon System (7)",
|
||||
"weight": 99.9,
|
||||
}
|
||||
|
||||
|
||||
inject_weapons(WeaponsOH6)
|
||||
|
||||
|
||||
@helicoptermod
|
||||
class OH_6A(HelicopterType):
|
||||
id = "OH-6A"
|
||||
flyable = True
|
||||
height = 3
|
||||
width = 8.33
|
||||
length = 10
|
||||
fuel_max = 181
|
||||
max_speed = 217
|
||||
category = "Air" # Helicopter
|
||||
radio_frequency = 262
|
||||
|
||||
panel_radio = {
|
||||
1: {
|
||||
"channels": {
|
||||
1: 264,
|
||||
2: 265,
|
||||
4: 254,
|
||||
8: 258,
|
||||
16: 267,
|
||||
17: 251,
|
||||
9: 262,
|
||||
18: 253,
|
||||
5: 250,
|
||||
10: 259,
|
||||
20: 252,
|
||||
11: 268,
|
||||
3: 256,
|
||||
6: 270,
|
||||
12: 269,
|
||||
13: 260,
|
||||
7: 257,
|
||||
14: 263,
|
||||
19: 266,
|
||||
15: 261,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
property_defaults = {
|
||||
"CableCutterEnables": False,
|
||||
}
|
||||
|
||||
class Properties:
|
||||
class CableCutterEnables:
|
||||
id = "CableCutterEnables"
|
||||
|
||||
livery_name = "OH-6A" # from type
|
||||
|
||||
class Pylon1:
|
||||
SMOKE_Grenade_RED = (1, WeaponsOH6.SMOKE_Grenade_RED)
|
||||
SMOKE_Grenade_Green = (1, WeaponsOH6.SMOKE_Grenade_Green)
|
||||
SMOKE_Grenade_Blue = (1, WeaponsOH6.SMOKE_Grenade_Blue)
|
||||
SMOKE_Grenade_yellow = (1, WeaponsOH6.SMOKE_Grenade_yellow)
|
||||
|
||||
class Pylon2:
|
||||
SMOKE_Grenade_RED = (2, WeaponsOH6.SMOKE_Grenade_RED)
|
||||
SMOKE_Grenade_Green = (2, WeaponsOH6.SMOKE_Grenade_Green)
|
||||
SMOKE_Grenade_Blue = (2, WeaponsOH6.SMOKE_Grenade_Blue)
|
||||
SMOKE_Grenade_yellow = (2, WeaponsOH6.SMOKE_Grenade_yellow)
|
||||
|
||||
class Pylon3:
|
||||
SMOKE_Grenade_RED = (3, WeaponsOH6.SMOKE_Grenade_RED)
|
||||
SMOKE_Grenade_Green = (3, WeaponsOH6.SMOKE_Grenade_Green)
|
||||
SMOKE_Grenade_Blue = (3, WeaponsOH6.SMOKE_Grenade_Blue)
|
||||
SMOKE_Grenade_yellow = (3, WeaponsOH6.SMOKE_Grenade_yellow)
|
||||
|
||||
class Pylon4:
|
||||
SMOKE_Grenade_RED = (4, WeaponsOH6.SMOKE_Grenade_RED)
|
||||
SMOKE_Grenade_Green = (4, WeaponsOH6.SMOKE_Grenade_Green)
|
||||
SMOKE_Grenade_Blue = (4, WeaponsOH6.SMOKE_Grenade_Blue)
|
||||
SMOKE_Grenade_yellow = (4, WeaponsOH6.SMOKE_Grenade_yellow)
|
||||
|
||||
class Pylon5:
|
||||
Frag_Grenade = (5, WeaponsOH6.Frag_Grenade)
|
||||
|
||||
# ERRR <CLEAN>
|
||||
# ERRR <CLEAN>
|
||||
|
||||
class Pylon8:
|
||||
M134_Minigun_ = (8, WeaponsOH6.M134_Minigun_)
|
||||
|
||||
class Pylon9:
|
||||
XM158_Weapon_System__7_ = (9, WeaponsOH6.XM158_Weapon_System__7_)
|
||||
XM158_Weapon_System__4_ = (9, WeaponsOH6.XM158_Weapon_System__4_)
|
||||
|
||||
class Pylon10:
|
||||
XM158_Weapon_System__7_ = (10, WeaponsOH6.XM158_Weapon_System__7_)
|
||||
XM158_Weapon_System__4_ = (10, WeaponsOH6.XM158_Weapon_System__4_)
|
||||
|
||||
class Pylon11:
|
||||
M60_Doorgun = (11, WeaponsOH6.M60_Doorgun)
|
||||
M134_Door_Minigun = (11, WeaponsOH6.M134_Door_Minigun)
|
||||
|
||||
class Pylon12:
|
||||
Camrig = (12, WeaponsOH6.Camrig)
|
||||
Searchlight = (12, WeaponsOH6.Searchlight)
|
||||
|
||||
pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
|
||||
|
||||
tasks = [task.Transport, task.Reconnaissance]
|
||||
task_default = task.Reconnaissance
|
||||
1
pydcs_extensions/oh6_vietnamassetpack/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .oh6_vietnamassetpack import *
|
||||
336
pydcs_extensions/oh6_vietnamassetpack/oh6_vietnamassetpack.py
Normal file
@ -0,0 +1,336 @@
|
||||
# Requires OH-6 Vietnam Asset Pack:
|
||||
# https://github.com/tobi-be/DCS-OH-6A
|
||||
#
|
||||
|
||||
from typing import Set
|
||||
|
||||
from dcs import unittype, task
|
||||
from dcs.helicopters import HelicopterType
|
||||
|
||||
from game.modsupport import vehiclemod, shipmod, helicoptermod
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_mutt_gun(unittype.VehicleType):
|
||||
id = "vap_mutt_gun"
|
||||
name = "VAP US MUTT Gun"
|
||||
detection_range = 0
|
||||
threat_range = 5000
|
||||
air_weapon_dist = 5000
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_type63_mlrs(unittype.VehicleType):
|
||||
id = "vap_type63_mlrs"
|
||||
name = "VAP VC Type63 107mm MLRS"
|
||||
detection_range = 5000
|
||||
threat_range = 5000
|
||||
air_weapon_dist = 5000
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_vc_bicycle_mortar(unittype.VehicleType):
|
||||
id = "vap_vc_bicycle_mortar"
|
||||
name = "VAP VC Bicycle Mortar"
|
||||
detection_range = 0
|
||||
threat_range = 7000
|
||||
air_weapon_dist = 7000
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_zis_150_aa(unittype.VehicleType):
|
||||
id = "vap_zis_150_aa"
|
||||
name = "VAP VC Zis 150 AAA"
|
||||
detection_range = 5000
|
||||
threat_range = 7000
|
||||
air_weapon_dist = 7000
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_us_hooch_LP(unittype.VehicleType):
|
||||
id = "vap_us_hooch_LP"
|
||||
name = "VAP US Hooch Low Poly"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_ammo_50cal_line(unittype.VehicleType):
|
||||
id = "vap_ammo_50cal_line"
|
||||
name = "VAP US Ammo 50Cal Line"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_ammo_50cal_pack(unittype.VehicleType):
|
||||
id = "vap_ammo_50cal_pack"
|
||||
name = "VAP US Ammo 50Cal Pack"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_barrels_line(unittype.VehicleType):
|
||||
id = "vap_barrels_line"
|
||||
name = "VAP Barrels Line"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_barrels(unittype.VehicleType):
|
||||
id = "vap_barrels"
|
||||
name = "VAP Barrels Pack"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_ammo_box_pile(unittype.VehicleType):
|
||||
id = "vap_ammo_box_pile"
|
||||
name = "VAP Ammo Box Pile"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_ammo_box_wood_long(unittype.VehicleType):
|
||||
id = "vap_ammo_box_wood_long"
|
||||
name = "VAP Ammo Box Long"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_ammo_box_wood_small(unittype.VehicleType):
|
||||
id = "vap_ammo_box_wood_small"
|
||||
name = "VAP Ammo Box Small"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_barrel_red(unittype.VehicleType):
|
||||
id = "vap_barrel_red"
|
||||
name = "VAP Barrel Red"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_barrel_green(unittype.VehicleType):
|
||||
id = "vap_barrel_green"
|
||||
name = "VAP Barrel Green"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_mre_boxes(unittype.VehicleType):
|
||||
id = "vap_mre_boxes"
|
||||
name = "VAP US MRE Boxes"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_mixed_cargo_1(unittype.VehicleType):
|
||||
id = "vap_mixed_cargo_1"
|
||||
name = "VAP US Mixed Cargo 1"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_mixed_cargo_2(unittype.VehicleType):
|
||||
id = "vap_mixed_cargo_2"
|
||||
name = "VAP US Mixed Cargo 2"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_watchtower(unittype.VehicleType):
|
||||
id = "vap_watchtower"
|
||||
name = "VAP Vietcong Watchtower"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_house_high(unittype.VehicleType):
|
||||
id = "vap_house_high"
|
||||
name = "VAP Bamboo House High"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_house_long(unittype.VehicleType):
|
||||
id = "vap_house_long"
|
||||
name = "VAP Bamboo House Long"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_house_small(unittype.VehicleType):
|
||||
id = "vap_house_small"
|
||||
name = "VAP Bamboo House Small"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_house_T(unittype.VehicleType):
|
||||
id = "vap_house_T"
|
||||
name = "VAP Bamboo House T-Shape"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_house_tiny(unittype.VehicleType):
|
||||
id = "vap_house_tiny"
|
||||
name = "VAP Bamboo House Tiny"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_house1(unittype.VehicleType):
|
||||
id = "vap_house1"
|
||||
name = "VAP Bamboo House"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_us_hooch_radio(unittype.VehicleType):
|
||||
id = "vap_us_hooch_radio"
|
||||
name = "VAP US Hooch Radio"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_us_hooch_closed(unittype.VehicleType):
|
||||
id = "vap_us_hooch_closed"
|
||||
name = "VAP US Hooch"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_vc_bunker_single(unittype.VehicleType):
|
||||
id = "vap_vc_bunker_single"
|
||||
name = "VAP VC Bunker"
|
||||
detection_range = 0
|
||||
threat_range = 800
|
||||
air_weapon_dist = 800
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_vc_mg_nest(unittype.VehicleType):
|
||||
id = "vap_vc_mg_nest"
|
||||
name = "VAP VC MG Nest"
|
||||
detection_range = 1000
|
||||
threat_range = 500
|
||||
air_weapon_dist = 500
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_mule(unittype.VehicleType):
|
||||
id = "vap_mule"
|
||||
name = "VAP US Mule"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_mutt(unittype.VehicleType):
|
||||
id = "vap_mutt"
|
||||
name = "VAP US MUTT"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_m35_truck(unittype.VehicleType):
|
||||
id = "vap_m35_truck"
|
||||
name = "VAP US M35 Truck"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_vc_zis(unittype.VehicleType):
|
||||
id = "vap_vc_zis"
|
||||
name = "VAP VC Zis 150"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_vc_bicycle(unittype.VehicleType):
|
||||
id = "vap_vc_bicycle"
|
||||
name = "VAP VC Bicycle"
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_vc_zil(unittype.VehicleType):
|
||||
id = "vap_vc_zil"
|
||||
name = "VAP VC Zil 130"
|
||||
detection_range = 5000
|
||||
threat_range = 500
|
||||
air_weapon_dist = 500
|
||||
|
||||
|
||||
@vehiclemod
|
||||
class Vap_vc_bicycle_ak(unittype.VehicleType):
|
||||
id = "vap_vc_bicycle_ak"
|
||||
name = "VAP VC Bicycle AK"
|
||||
detection_range = 5000
|
||||
threat_range = 500
|
||||
air_weapon_dist = 500
|
||||
|
||||
|
||||
@shipmod
|
||||
class Vap_us_seafloat(unittype.ShipType):
|
||||
id = "vap_us_seafloat"
|
||||
name = "VAP - US Sea Float Barge"
|
||||
helicopter_num = 4
|
||||
parking = 4
|
||||
detection_range = 0
|
||||
threat_range = 0
|
||||
air_weapon_dist = 0
|
||||
@ -335,6 +335,9 @@ def create_game(
|
||||
f104_starfighter=False,
|
||||
f105_thunderchief=False,
|
||||
hercules=False,
|
||||
oh_6=False,
|
||||
oh_6_vietnamassetpack=False,
|
||||
uh_60l=False,
|
||||
jas39_gripen=False,
|
||||
sk60_saab105=False,
|
||||
su15_flagon=False,
|
||||
|
||||
@ -33,6 +33,12 @@ class SquadronLiverySelector(QComboBox):
|
||||
for x in faction.liveries_overrides.get(self.aircraft_type, [])
|
||||
if x in [y.id.lower() for y in liveries]
|
||||
]
|
||||
if selected_livery is None and squadron.livery_set:
|
||||
self.addItem("Using livery-set from squadron's yaml", userData=None)
|
||||
self.setEnabled(False)
|
||||
return
|
||||
if selected_livery is None and squadron.aircraft.default_livery:
|
||||
selected_livery = squadron.aircraft.default_livery
|
||||
if len(overrides) > 0:
|
||||
self.addItem("Use livery overrides", userData=None)
|
||||
for livery in sorted(liveries):
|
||||
|
||||
@ -130,6 +130,20 @@ class QAutoCreateDialog(QDialog):
|
||||
self.sead_sweep_type,
|
||||
)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
self.armed_recon = self._create_checkbox("Armed Recon")
|
||||
self.armed_recon_count = _spinbox_template()
|
||||
hbox.addWidget(self.armed_recon)
|
||||
hbox.addWidget(self.armed_recon_count)
|
||||
self.armed_recon_type = self._create_type_selector(FlightType.ARMED_RECON)
|
||||
hbox.addWidget(self.armed_recon_type)
|
||||
self.layout.addLayout(hbox)
|
||||
self.checkboxes[self.armed_recon] = (
|
||||
FlightType.ARMED_RECON,
|
||||
self.armed_recon_count,
|
||||
self.armed_recon_type,
|
||||
)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
self.refueling = self._create_checkbox("Refueling")
|
||||
self.refueling_count = _spinbox_template()
|
||||
@ -161,6 +175,8 @@ class QAutoCreateDialog(QDialog):
|
||||
FlightType.ANTISHIP,
|
||||
FlightType.BAI,
|
||||
FlightType.CAS,
|
||||
FlightType.ARMED_RECON,
|
||||
FlightType.AIR_ASSAULT,
|
||||
}
|
||||
for mt in self.package.target.mission_types(self.is_ownfor):
|
||||
if mt in primary_tasks:
|
||||
|
||||
@ -107,6 +107,8 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
f106_deltadart=self.field("f106_deltadart"),
|
||||
hercules=self.field("hercules"),
|
||||
irondome=self.field("irondome"),
|
||||
oh_6=self.field("oh_6"),
|
||||
oh_6_vietnamassetpack=self.field("oh_6_vietnamassetpack"),
|
||||
uh_60l=self.field("uh_60l"),
|
||||
jas39_gripen=self.field("jas39_gripen"),
|
||||
super_etendard=self.field("super_etendard"),
|
||||
|
||||
@ -98,6 +98,10 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
self.registerField("ea6b_prowler", self.ea6b_prowler)
|
||||
self.hercules = QtWidgets.QCheckBox()
|
||||
self.registerField("hercules", self.hercules)
|
||||
self.oh_6 = QtWidgets.QCheckBox()
|
||||
self.registerField("oh_6", self.oh_6)
|
||||
self.oh_6_vietnamassetpack = QtWidgets.QCheckBox()
|
||||
self.registerField("oh_6_vietnamassetpack", self.oh_6_vietnamassetpack)
|
||||
self.uh_60l = QtWidgets.QCheckBox()
|
||||
self.registerField("uh_60l", self.uh_60l)
|
||||
self.f4bc_phantom = QtWidgets.QCheckBox()
|
||||
@ -196,6 +200,8 @@ class GeneratorOptions(QtWidgets.QWizardPage):
|
||||
("Su-57 Felon (build-04)", self.su57_felon),
|
||||
("Super Étendard (v2.5.5)", self.super_etendard),
|
||||
("Swedish Military Assets pack (1.10)", self.swedishmilitaryassetspack),
|
||||
("OH-6 Cayuse (v1.2)", self.oh_6),
|
||||
("OH-6 Vietnam Asset Pack (v1.0)", self.oh_6_vietnamassetpack),
|
||||
("UH-60L Black Hawk (v1.3.1)", self.uh_60l),
|
||||
]
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@ description: <p>Argentina and China have taken the Falklands by surprise. Curren
|
||||
miz: RetakeTheFalklands.miz
|
||||
performance: 2
|
||||
recommended_start_date: 2002-12-21
|
||||
settings:
|
||||
squadron_start_full: true
|
||||
version: "10.7"
|
||||
squadrons:
|
||||
# Off-map spawn
|
||||
@ -22,6 +24,12 @@ squadrons:
|
||||
aircraft:
|
||||
- F-15E Strike Eagle (Suite 4+)
|
||||
size: 12
|
||||
# Gamblers
|
||||
- primary: DEAD
|
||||
secondary: any
|
||||
aircraft:
|
||||
- 77th FS
|
||||
size: 12
|
||||
- primary: Strike
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
@ -88,14 +96,6 @@ squadrons:
|
||||
size: 12
|
||||
aircraft:
|
||||
- J-15 Flanker X-2
|
||||
# Blue - San Julian
|
||||
11:
|
||||
# Gamblers
|
||||
- primary: DEAD
|
||||
secondary: any
|
||||
aircraft:
|
||||
- 77th FS
|
||||
size: 9
|
||||
# RED - Punta Arenas
|
||||
9:
|
||||
- primary: CAS
|
||||
|
||||
@ -16,14 +16,25 @@ recommended_player_income_multiplier: 1.5
|
||||
recommended_enemy_income_multiplier: 0.7
|
||||
settings:
|
||||
airbase_threat_range: 300
|
||||
# Set mission duration to 45 minutes
|
||||
desired_player_mission_duration: 45
|
||||
# Set max frontline width to 30 km
|
||||
max_frontline_width: 30
|
||||
squadron_start_full: true
|
||||
squadrons:
|
||||
#BLUFOR CVN
|
||||
Naval-3:
|
||||
# Pukin' Dogs F-14
|
||||
# The Swordsmen F-14
|
||||
- primary: BARCAP
|
||||
secondary: air-to-air
|
||||
aircraft:
|
||||
- VF-143
|
||||
- VF-32
|
||||
size: 14
|
||||
- primary: Strike
|
||||
secondary: air-to-air
|
||||
aircraft:
|
||||
- VF-213
|
||||
- F-14B Tomcat
|
||||
size: 14
|
||||
# Golden Dragons F/A-18
|
||||
- primary: SEAD
|
||||
@ -52,13 +63,18 @@ squadrons:
|
||||
- primary: BAI
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- VMA-223
|
||||
size: 12
|
||||
- primary: Transport
|
||||
- AV-8B Harrier II Night Attack
|
||||
size: 10
|
||||
- primary: Air Assault
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- HMLA-169 (UH-1H)
|
||||
size: 8
|
||||
- UH-1H Iroquois
|
||||
size: 4
|
||||
- primary: BAI
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- AH-1W SuperCobra
|
||||
size: 6
|
||||
# Al-Dhafra AFB
|
||||
4:
|
||||
#USAF F-16C Gamblers
|
||||
@ -92,12 +108,6 @@ squadrons:
|
||||
#USAF F-15C
|
||||
# Al-Minhab AFB
|
||||
12:
|
||||
- primary: Transport
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- 101st Combat Aviation Brigade
|
||||
#US Army UH-60
|
||||
size: 6
|
||||
- primary: SEAD
|
||||
secondary: any
|
||||
aircraft:
|
||||
@ -115,8 +125,30 @@ squadrons:
|
||||
#USAF A-10CI
|
||||
- primary: Transport
|
||||
aircraft:
|
||||
- C-130J-30 Super Hercules
|
||||
- C-130
|
||||
size: 8
|
||||
# Khasab / 12
|
||||
10:
|
||||
- primary: Transport
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- 101st Combat Aviation Brigade
|
||||
#US Army UH-60
|
||||
size: 4
|
||||
- primary: BAI
|
||||
size: 4
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- A-10C Thunderbolt II (Suite 7)
|
||||
#USAF A-10CI
|
||||
- primary: CAS
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Wolfpack, 1-82 ARB
|
||||
#US Army Apache AH-64D
|
||||
size: 4
|
||||
### OPFOR
|
||||
# Kish Intl
|
||||
24:
|
||||
- primary: AEW&C
|
||||
@ -156,7 +188,12 @@ squadrons:
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- MiG-29A Fulcrum-A
|
||||
size: 6
|
||||
size: 12
|
||||
- primary: BARCAP
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
- Mirage-F1EQ
|
||||
size: 12
|
||||
- primary: Strike
|
||||
secondary: air-to-ground
|
||||
aircraft:
|
||||
|
||||
@ -3,7 +3,7 @@ name: Syria - The Long Road to H3
|
||||
theater: Syria
|
||||
authors: tmz42 (original campaign by Plob)
|
||||
description:
|
||||
<p>From Incirlik to H-3, repel the alliance between Iraq and Syria.</p>
|
||||
<p>From Incirlik to H-3, repel the alliance between Syria and Iraq.</p>
|
||||
<p>This campaign is based on and meant as a lighter alternative to Syria - Full Map.</p>
|
||||
recommended_player_faction: NATO OIF
|
||||
recommended_enemy_faction:
|
||||
@ -25,7 +25,6 @@ recommended_enemy_faction:
|
||||
- SA 342L Gazelle
|
||||
- Su-22M4 Fitter-K
|
||||
- Su-24M Fencer-D
|
||||
- Tu-22M3 Backfire-C
|
||||
- Su-25 Frogfoot
|
||||
- Mirage-F1EQ
|
||||
- H-6J Badger
|
||||
@ -42,10 +41,9 @@ recommended_enemy_faction:
|
||||
- MT-LB
|
||||
- T-55A
|
||||
- T-72B with Kontakt-1 ERA
|
||||
- T-90A
|
||||
- ZSU-57-2 'Sparka'
|
||||
- ZSU-23-4 Shilka
|
||||
artillery_units:
|
||||
- BM-21 Grad
|
||||
- 2S1 Gvozdika
|
||||
- 2S9 Nona-S
|
||||
logistics_units:
|
||||
@ -65,19 +63,16 @@ recommended_enemy_faction:
|
||||
- SA-6
|
||||
- SA-11
|
||||
- SA-10/S-300PS
|
||||
- SA-12/S-300V
|
||||
- Cold-War-Flak
|
||||
- Silkworm
|
||||
- KS-19/SON-9
|
||||
naval_units:
|
||||
- Corvette 1124.4 Grish
|
||||
- Corvette 1241.1 Molniya
|
||||
- FAC La Combattante IIa
|
||||
- Frigate 1135M Rezky
|
||||
- LS Ropucha
|
||||
air_defense_units:
|
||||
- SAM P19 "Flat Face" SR (SA-2/3)
|
||||
- EWR 1L13
|
||||
- EWR 55G6
|
||||
- SAM SA-8 Osa "Gecko" TEL
|
||||
- SA-9 Strela
|
||||
- SA-13 Gopher (9K35 Strela-10M3)
|
||||
@ -102,6 +97,7 @@ settings:
|
||||
desired_player_mission_duration: 45
|
||||
# Set max frontline width to 30 km
|
||||
max_frontline_width: 30
|
||||
squadron_start_full: true
|
||||
squadrons:
|
||||
####################### BLUEFOR
|
||||
Blue CV:
|
||||
|
||||
@ -120,7 +120,7 @@ local unitPayloads = {
|
||||
["name"] = "Retribution Escort",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
|
||||
["CLSID"] = "{M299_4xAGM_114L}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[2] = {
|
||||
@ -128,7 +128,7 @@ local unitPayloads = {
|
||||
["num"] = 4,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
|
||||
["CLSID"] = "{M299_4xAGM_114L}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[4] = {
|
||||
|
||||
153
resources/customized_payloads/OH-6A.lua
Normal file
@ -0,0 +1,153 @@
|
||||
local unitPayloads = {
|
||||
["name"] = "OH-6A",
|
||||
["payloads"] = {
|
||||
[1] = {
|
||||
["displayName"] = "Retribution BAI",
|
||||
["name"] = "Retribution BAI",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{OH-6_M60_Door}",
|
||||
["num"] = 11,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "<CLEAN>",
|
||||
["num"] = 6,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "<CLEAN>",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{OH-6_M134_Minigun}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{OH6_FRAG}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{OH6_SMOKE_BLUE}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{OH6_SMOKE_GREEN}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{OH6_SMOKE_RED}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[9] = {
|
||||
["CLSID"] = "{OH6_SMOKE_YELLOW}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 17,
|
||||
[2] = 35,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
["displayName"] = "Retribution OCA/Aircraft",
|
||||
["name"] = "Retribution OCA/Aircraft",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{OH6_XM158}",
|
||||
["num"] = 10,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "{OH6_XM158}",
|
||||
["num"] = 9,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "{OH6_FRAG}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{OH6_SMOKE_BLUE}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "<CLEAN>",
|
||||
["num"] = 6,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "<CLEAN>",
|
||||
["num"] = 7,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{OH6_SMOKE_GREEN}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{OH6_SMOKE_RED}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[9] = {
|
||||
["CLSID"] = "{OH6_SMOKE_YELLOW}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 35,
|
||||
[2] = 17,
|
||||
[3] = 31,
|
||||
[4] = 15,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
["displayName"] = "Retribution CAS",
|
||||
["name"] = "Retribution CAS",
|
||||
["pylons"] = {
|
||||
[1] = {
|
||||
["CLSID"] = "{OH-6 M60 Door}",
|
||||
["num"] = 11,
|
||||
},
|
||||
[2] = {
|
||||
["CLSID"] = "<CLEAN>",
|
||||
["num"] = 6,
|
||||
},
|
||||
[3] = {
|
||||
["CLSID"] = "<CLEAN>",
|
||||
["num"] = 7,
|
||||
},
|
||||
[4] = {
|
||||
["CLSID"] = "{OH-6 M134 Minigun}",
|
||||
["num"] = 8,
|
||||
},
|
||||
[5] = {
|
||||
["CLSID"] = "{OH6_FRAG}",
|
||||
["num"] = 5,
|
||||
},
|
||||
[6] = {
|
||||
["CLSID"] = "{OH6_SMOKE_BLUE}",
|
||||
["num"] = 4,
|
||||
},
|
||||
[7] = {
|
||||
["CLSID"] = "{OH6_SMOKE_GREEN}",
|
||||
["num"] = 3,
|
||||
},
|
||||
[8] = {
|
||||
["CLSID"] = "{OH6_SMOKE_RED}",
|
||||
["num"] = 2,
|
||||
},
|
||||
[9] = {
|
||||
["CLSID"] = "{OH6_SMOKE_YELLOW}",
|
||||
["num"] = 1,
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 17,
|
||||
[2] = 35,
|
||||
},
|
||||
},
|
||||
},
|
||||
["tasks"] = {
|
||||
[1] = 35,
|
||||
[2] = 17,
|
||||
[3] = 31,
|
||||
[4] = 15,
|
||||
},
|
||||
["unitType"] = "OH-6A",
|
||||
}
|
||||
return unitPayloads
|
||||
@ -7,6 +7,7 @@
|
||||
"aircrafts": [
|
||||
"CH-47D",
|
||||
"CH-53E",
|
||||
"OH-6A Cayuse",
|
||||
"UH-1H Iroquois",
|
||||
"AH-1W SuperCobra",
|
||||
"OV-10A Bronco",
|
||||
@ -38,7 +39,8 @@
|
||||
"frontline_units": [
|
||||
"M113",
|
||||
"M163 Vulcan Air Defense System",
|
||||
"M60A3 \"Patton\""
|
||||
"M60A3 \"Patton\"",
|
||||
"M151A1C MUTT w/ 106mm Recoilless Rifle"
|
||||
],
|
||||
"artillery_units": [
|
||||
"M109A6 Paladin"
|
||||
@ -48,7 +50,10 @@
|
||||
"Infantry M4 Georgia"
|
||||
],
|
||||
"logistics_units": [
|
||||
"Truck M818 6x6"
|
||||
"Truck M818 6x6",
|
||||
"VAP US M35 Truck",
|
||||
"M151 1/4-ton 4x4 utility truck",
|
||||
"M274 1/2-ton 4x4 utility truck"
|
||||
],
|
||||
"air_defense_units": [
|
||||
"SAM Hawk SR (AN/MPQ-50)",
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"aircrafts": [
|
||||
"CH-47D",
|
||||
"CH-53E",
|
||||
"OH-6A Cayuse",
|
||||
"UH-1H Iroquois",
|
||||
"AH-1W SuperCobra",
|
||||
"OV-10A Bronco",
|
||||
@ -36,7 +37,8 @@
|
||||
"frontline_units": [
|
||||
"M113",
|
||||
"M163 Vulcan Air Defense System",
|
||||
"M60A3 \"Patton\""
|
||||
"M60A3 \"Patton\"",
|
||||
"M151A1C MUTT w/ 106mm Recoilless Rifle"
|
||||
],
|
||||
"artillery_units": [
|
||||
"M109A6 Paladin"
|
||||
@ -46,7 +48,10 @@
|
||||
"Infantry M4 Georgia"
|
||||
],
|
||||
"logistics_units": [
|
||||
"Truck M818 6x6"
|
||||
"Truck M818 6x6",
|
||||
"VAP US M35 Truck",
|
||||
"M151 1/4-ton 4x4 utility truck",
|
||||
"M274 1/2-ton 4x4 utility truck"
|
||||
],
|
||||
"air_defense_units": [
|
||||
"SAM Hawk SR (AN/MPQ-50)",
|
||||
|
||||
@ -29,11 +29,14 @@
|
||||
"F-16D Fighting Falcon (Block 50+)",
|
||||
"F-16D Fighting Falcon (Block 50)",
|
||||
"F-22A Raptor",
|
||||
"F-4E-45MC Phantom II",
|
||||
"F-5E Tiger II",
|
||||
"F-5E Tiger II (FC)",
|
||||
"F/A-18C Hornet (Lot 20)",
|
||||
"F/A-18E Super Hornet",
|
||||
"F/A-18F Super Hornet",
|
||||
"EA-18G Growler",
|
||||
"J-11A Flanker-L",
|
||||
"JF-17 Thunder",
|
||||
"Ka-50 Hokum",
|
||||
"Ka-50 Hokum III",
|
||||
@ -52,6 +55,7 @@
|
||||
"OH-58D(R) Kiowa Warrior",
|
||||
"SA 342L Gazelle",
|
||||
"SA 342M Gazelle",
|
||||
"Su-24M Fencer-D",
|
||||
"Su-25T Frogfoot",
|
||||
"Su-27 Flanker-B",
|
||||
"Su-30MKA Flanker-H",
|
||||
@ -148,10 +152,14 @@
|
||||
"jtac_unit": "MQ-9 Reaper",
|
||||
"unrestricted_satnav": true,
|
||||
"liveries_overrides": {
|
||||
"Ka-50 Hokum": ["georgia camo"],
|
||||
"J-11A Flanker-L": ["USN Aggressor VFC-13 'Ferris' (Fictional)"],
|
||||
"JF-17 Thunder": ["'Splinter' Camo for Blue Side (Fictional)"],
|
||||
"Ka-50 Hokum": ["georgia camo"],
|
||||
"Ka-50 Hokum III": ["Ka-50_black_neutral"],
|
||||
"Mi-8MTV2 Hip": ["Ukraine"],
|
||||
"Mi-24P Hind-F": ["Ukrainian Army Aviation"],
|
||||
"MiG-29S Fulcrum-C": ["Air Force Ukraine Standard"],
|
||||
"Su-24M Fencer-D": ["Ukrainian Air Force Standard"],
|
||||
"Su-25T Frogfoot": ["af standard 101"],
|
||||
"Su-27 Flanker-B": ["Air Force Ukraine Standard"]
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"F-105G Thunderchief",
|
||||
"F-106A Delta Dart",
|
||||
"F-106B Delta Dart",
|
||||
"OH-6A Cayuse",
|
||||
"UH-1H Iroquois"
|
||||
],
|
||||
"awacs": [
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
"C-47 Skytrain",
|
||||
"C-130",
|
||||
"C-130J-30 Super Hercules",
|
||||
"OH-6A Cayuse",
|
||||
"UH-1H Iroquois",
|
||||
"AH-1W SuperCobra",
|
||||
"OH-58D(R) Kiowa Warrior",
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
"F-106B Delta Dart",
|
||||
"S-3B Viking",
|
||||
"OV-10A Bronco",
|
||||
"OH-6A Cayuse",
|
||||
"UH-1H Iroquois"
|
||||
],
|
||||
"awacs": [
|
||||
|
||||
54
resources/factions/vietcong_1970.json
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
"country": "Vietnam",
|
||||
"name": "Viet Cong 1970",
|
||||
"authors": "Ghosti",
|
||||
"description": "<p>National Liberation Front of South Vietnam during the Vietnam War from 1965 to 1975. Includes air units of the PAVN/VPAF. Requires the OH-6 Vietnam Asset Pack.</p>",
|
||||
"locales": [
|
||||
"vi_Vn"
|
||||
],
|
||||
"aircrafts": [
|
||||
"Mi-8MTV2 Hip",
|
||||
"MiG-19P Farmer-B",
|
||||
"MiG-21bis Fishbed-N"
|
||||
],
|
||||
"awacs": [],
|
||||
"tankers": [],
|
||||
"frontline_units": [
|
||||
"PT-76",
|
||||
"VAP VC Zil 130 Armed",
|
||||
"VAP VC Bicycle AK",
|
||||
"VAP VC MG Nest",
|
||||
"VAP VC Bunker"
|
||||
],
|
||||
"artillery_units": [
|
||||
"VAP VC Type63 107mm MLRS"
|
||||
],
|
||||
"logistics_units": [
|
||||
"VAP VC Zis 150",
|
||||
"VAP VC Bicycle"
|
||||
],
|
||||
"infantry_units": [
|
||||
"Infantry AK-74 Rus",
|
||||
"VAP VC Bicycle Mortar"
|
||||
],
|
||||
"missiles": [],
|
||||
"preset_groups": [
|
||||
"KS-19/SON-9"
|
||||
],
|
||||
"naval_units": [
|
||||
"Boat Armed Hi-speed",
|
||||
"Boat Schnellboot type S130"
|
||||
],
|
||||
"air_defense_units": [
|
||||
"VAP VC Zis 150 AAA",
|
||||
"S-60 57mm",
|
||||
"ZSU-57-2 'Sparka'",
|
||||
"AAA ZU-23 Emplacement",
|
||||
"ZU-23 on Ural-375",
|
||||
"ZSU-23-4 Shilka"
|
||||
],
|
||||
"requirements": {
|
||||
"OH-6 Vietnam Asset Pack": "https://github.com/tobi-be/DCS-OH-6A"
|
||||
},
|
||||
"doctrine": "coldwar"
|
||||
}
|
||||
@ -6,6 +6,9 @@ country: USA
|
||||
role: Strike Fighter
|
||||
aircraft: F/A-18C Hornet (Lot 20)
|
||||
livery: VMFA-122 high visibility
|
||||
bases:
|
||||
shore: true
|
||||
carrier: true
|
||||
mission_types:
|
||||
- Anti-ship
|
||||
- BAI
|
||||
|
||||
@ -6,6 +6,9 @@ country: USA
|
||||
role: Strike Fighter
|
||||
aircraft: F/A-18C Hornet (Lot 20)
|
||||
livery: VMFA-251 high visibility
|
||||
bases:
|
||||
shore: true
|
||||
carrier: true
|
||||
mission_types:
|
||||
- Anti-ship
|
||||
- BAI
|
||||
|
||||
BIN
resources/ui/units/aircrafts/banners/OH-6A.jpg
Normal file
|
After Width: | Height: | Size: 336 KiB |
BIN
resources/ui/units/aircrafts/icons/OH-6A_24.jpg
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
resources/ui/units/vehicles/icons/PT_76_24.jpg
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
resources/ui/units/vehicles/icons/vap_m35_truck_24.jpg
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
resources/ui/units/vehicles/icons/vap_mule_24.jpg
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
resources/ui/units/vehicles/icons/vap_mutt_24.jpg
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
resources/ui/units/vehicles/icons/vap_mutt_gun_24.jpg
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
resources/ui/units/vehicles/icons/vap_type63_mlrs_24.jpg
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
resources/ui/units/vehicles/icons/vap_vc_bicycle_24.jpg
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
resources/ui/units/vehicles/icons/vap_vc_bicycle_ak_24.jpg
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
resources/ui/units/vehicles/icons/vap_vc_bicycle_mortar_24.jpg
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
resources/ui/units/vehicles/icons/vap_vc_bunker_single_24.jpg
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
resources/ui/units/vehicles/icons/vap_vc_mg_nest_24.jpg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
resources/ui/units/vehicles/icons/vap_vc_zil_24.jpg
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
resources/ui/units/vehicles/icons/vap_vc_zis_24.jpg
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
resources/ui/units/vehicles/icons/vap_zis_150_aa_24.jpg
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
@ -16,6 +16,9 @@ price: 12
|
||||
role: Close Air Support/Attack
|
||||
variants:
|
||||
A-10A Thunderbolt II: {}
|
||||
altitudes:
|
||||
cruise: 15000
|
||||
combat: 10000
|
||||
tasks:
|
||||
BAI: 680
|
||||
CAS: 680
|
||||
|
||||
@ -14,6 +14,9 @@ price: 18
|
||||
role: Close Air Support/Attack
|
||||
variants:
|
||||
A-10C Thunderbolt II (Suite 3): {}
|
||||
altitudes:
|
||||
cruise: 15000
|
||||
combat: 10000
|
||||
radios:
|
||||
intra_flight: AN/ARC-186(V) AM
|
||||
inter_flight: AN/ARC-164
|
||||
|
||||
@ -14,6 +14,9 @@ price: 20
|
||||
role: Close Air Support/Attack
|
||||
variants:
|
||||
A-10C Thunderbolt II (Suite 7): {}
|
||||
altitudes:
|
||||
cruise: 15000
|
||||
combat: 10000
|
||||
radios:
|
||||
# DCS will clobber channel 1 of the AN/ARC-164 with the flight's assigned
|
||||
# frequency, so we may as well use that one for intra-flight.
|
||||
|
||||
20
resources/units/aircraft/OH-6A.yaml
Normal file
@ -0,0 +1,20 @@
|
||||
class: Helicopter
|
||||
carrier_capable: false
|
||||
description:
|
||||
The Hughes OH-6 Cayuse is a single-engine light helicopter designed and
|
||||
produced by the American aerospace company Hughes Helicopters.
|
||||
introduced: 1966
|
||||
lha_capable: false
|
||||
can_carry_crates: false
|
||||
manufacturer: Hughes Helicopters
|
||||
origin: USA
|
||||
price: 3
|
||||
role: Light Observation/Light Attack
|
||||
variants:
|
||||
OH-6A Cayuse: {}
|
||||
tasks:
|
||||
BAI: 0
|
||||
CAS: 0
|
||||
OCA/Aircraft: 0
|
||||
Air Assault: 50
|
||||
Transport: 50
|
||||
@ -1,6 +1,6 @@
|
||||
class: Tank
|
||||
description:
|
||||
introduced: 1992
|
||||
description: Abrams M1A2 SEPv3 is a modernised configuration of the Abrams main battle tank (MBT) in service with the US Army.The new version offers enhanced protection and survivability, as well as higher lethality than its predecessors. The tank also features various advancements in technology, including improved armour, communications, reliability, sustainment, and fuel efficiency.
|
||||
introduced: 2017
|
||||
manufacturer: General Dynamics Land Systems
|
||||
origin: USA
|
||||
price: 25
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
class: APC
|
||||
description: 2007
|
||||
introduced:
|
||||
description: The International M1224 MaxxPro MRAP (Mine-Resistant Ambush Protected) is an armored fighting vehicle designed by American company Navistar International's subsidiary Navistar Defense along with the Israeli Plasan Sasa, who designed and manufactures the vehicle's armor. The vehicle was designed to take part in the US military's Mine Resistant Ambush Protected vehicle program, led by the US Marine Corps, as well as a similar US Army-led Medium Mine Protected Vehicle program.
|
||||
introduced: 2007
|
||||
manufacturer: Navistar/Plasan
|
||||
origin: USA
|
||||
price: 8
|
||||
|
||||
14
resources/units/ground_units/SHERIDAN.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
class: ATGM
|
||||
description: The M551 Sheridan AR/AAV (Armored Reconnaissance/Airborne Assault Vehicle)
|
||||
is a light tank developed by the United States and named after General Philip Sheridan,
|
||||
of American Civil War fame. It was designed to be landed by parachute and to swim across
|
||||
rivers. It is armed with the technically advanced M81/M81 Modified/M81E1 152 mm
|
||||
gun/launcher, which fires both conventional ammunition and the MGM-51 Shillelagh guided
|
||||
anti-tank missile.
|
||||
introduced: 1966
|
||||
manufacturer: General Motors, Cadillac Motor Company
|
||||
origin: USA
|
||||
price: 16
|
||||
role: Light Tank
|
||||
variants:
|
||||
M551 "Sheridan": {}
|
||||
14
resources/units/ground_units/T62.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
class: Tank
|
||||
description: The T-62 is a Soviet main battle tank that was first introduced in 1961.
|
||||
As a further development of the T-55 series, the T-62 retained many similar design
|
||||
elements of its predecessor including low profile and thick turret armour. In
|
||||
contrast with previous tanks, which were armed with rifled tank guns, the T-62 was
|
||||
the first production tank armed with a smoothbore tank gun that could fire APFSDS
|
||||
rounds at higher velocities.
|
||||
introduced: 1961
|
||||
manufacturer: UralVagonZavod
|
||||
origin: USSR/Russia
|
||||
price: 19
|
||||
role: Main Battle Tank
|
||||
variants:
|
||||
T-62: {}
|
||||
17
resources/units/ground_units/T64BV.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
class: Tank
|
||||
description: The T-64 is a Soviet second-generation main battle tank, designed by
|
||||
Kharkiv Morozov Machine Building Design Bureau in Ukraine, introduced in the early
|
||||
1960s. It was a more advanced counterpart to the T-62; the T-64 served in tank
|
||||
divisions, while the T-62 supported infantry in motorized rifle divisions. It
|
||||
introduced a number of advanced features including composite armour, a compact
|
||||
engine and transmission, and a smoothbore 125-mm gun equipped with an autoloader
|
||||
to allow the crew to be reduced to three so the tank could be smaller and lighter.
|
||||
In spite of being armed and armoured like a heavy tank, the T-64 weighed only 38
|
||||
tonnes (42 short tons; 37 long tons).
|
||||
introduced: 1966
|
||||
manufacturer: Kharkiv
|
||||
origin: USSR/Russia
|
||||
price: 19
|
||||
role: Main Battle Tank
|
||||
variants:
|
||||
T-64BV: {}
|
||||
4
resources/units/ground_units/vap_m35_truck.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
class: Logistics
|
||||
price: 3
|
||||
variants:
|
||||
VAP US M35 Truck: null
|
||||
5
resources/units/ground_units/vap_mule.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
class: Logistics
|
||||
price: 3
|
||||
variants:
|
||||
VAP US Mule: {}
|
||||
M274 1/2-ton 4x4 utility truck: {}
|
||||
5
resources/units/ground_units/vap_mutt.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
class: Logistics
|
||||
price: 3
|
||||
variants:
|
||||
VAP US MUTT: {}
|
||||
M151 1/4-ton 4x4 utility truck: {}
|
||||
6
resources/units/ground_units/vap_mutt_gun.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
class: ATGM
|
||||
price: 10
|
||||
role: Self-Propelled Recoilless Rifle
|
||||
variants:
|
||||
VAP US MUTT Gun: {}
|
||||
M151A1C MUTT w/ 106mm Recoilless Rifle: {}
|
||||
5
resources/units/ground_units/vap_type63_mlrs.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
class: Artillery
|
||||
price: 10
|
||||
role: Multiple-Launch Rocket System
|
||||
variants:
|
||||
VAP VC Type63 107mm MLRS: {}
|
||||
4
resources/units/ground_units/vap_vc_bicycle.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
class: Logistics
|
||||
price: 2
|
||||
variants:
|
||||
VAP VC Bicycle: null
|
||||
5
resources/units/ground_units/vap_vc_bicycle_ak.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
class: Recon
|
||||
price: 2
|
||||
role: Recon
|
||||
variants:
|
||||
VAP VC Bicycle AK: {}
|
||||
5
resources/units/ground_units/vap_vc_bicycle_mortar.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
class: Infantry
|
||||
price: 0
|
||||
spawn_weight: 1
|
||||
variants:
|
||||
VAP VC Bicycle Mortar: null
|
||||
4
resources/units/ground_units/vap_vc_bunker_single.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
class: IFV
|
||||
price: 4
|
||||
variants:
|
||||
VAP VC Bunker: null
|
||||
4
resources/units/ground_units/vap_vc_mg_nest.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
class: APC
|
||||
price: 3
|
||||
variants:
|
||||
VAP VC MG Nest: null
|
||||
6
resources/units/ground_units/vap_vc_zil.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
class: ATGM
|
||||
description:
|
||||
price: 7
|
||||
role: Armed Truck
|
||||
variants:
|
||||
VAP VC Zil 130 Armed: {}
|
||||
4
resources/units/ground_units/vap_vc_zis.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
class: Logistics
|
||||
price: 3
|
||||
variants:
|
||||
VAP VC Zis 150: null
|
||||
6
resources/units/ground_units/vap_zis_150_aa.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
class: AAA
|
||||
description:
|
||||
price: 7
|
||||
role: Self-Propelled Anti-Aircraft Gun
|
||||
variants:
|
||||
VAP VC Zis 150 AAA: {}
|
||||
4
resources/units/ships/vap_us_seafloat.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
class: Boat
|
||||
price: 0
|
||||
variants:
|
||||
VAP - US Sea Float Barge: null
|
||||