Merge branch 'pretense-generator' of https://github.com/MetalStormGhost/dcs-retribution into pretense-generator

This commit is contained in:
MetalStormGhost
2024-04-06 13:58:06 +03:00
92 changed files with 5759 additions and 4050 deletions

View File

@@ -1,6 +1,8 @@
# Retribution v1.3.0 # 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.
## Features/Improvements ## Features/Improvements
* **[Engine]** Support for DCS v2.9.3.51704
* **[Package Planning]** Option to "Auto-Create" package * **[Package Planning]** Option to "Auto-Create" package
* **[Modding]** Custom weapons injection system (definition in aircraft's yaml file) * **[Modding]** Custom weapons injection system (definition in aircraft's yaml file)
* **[Payload Editor]** Ability to save/back-up payloads * **[Payload Editor]** Ability to save/back-up payloads
@@ -30,12 +32,15 @@
* **[COMMs]** Aircraft-specific callsigns will now also be used. * **[COMMs]** Aircraft-specific callsigns will now also be used.
* **[COMMs]** Ability to set a specific callsign to a flight. * **[COMMs]** Ability to set a specific callsign to a flight.
* **[Mission Generator]** Channel terrain fix on exclusion zones, sea zones and inclusion zones * **[Mission Generator]** Channel terrain fix on exclusion zones, sea zones and inclusion zones
* **[Options]** Cheat-option for accessing Air Wing Config Dialog after campaign start * **[Options]** Cheat-option for accessing Air Wing Config Dialog after campaign start (re-initializes turn if applied, thus plan your mission ___after___ making changes)
* **[Options]** Option to enable unlimited fuel for AI (player and non-player flights) * **[Options]** Option to enable unlimited fuel for AI (player and non-player flights)
* **[Mission Generator]** F-15E Strike targets are automatically added as Mission Set 1 * **[Mission Generator]** F-15E Strike targets are automatically added as Mission Set 1
* **[Mission Generator]** Set F-14's IP waypoint according to the flight-plan's ingress point * **[Mission Generator]** Set F-14's IP waypoint according to the flight-plan's ingress point
* **[Mission Generator]** Automatically de-spawn aircraft when arrival/divert is an off-map spawn * **[Mission Generator]** Automatically de-spawn aircraft when arrival/divert is an off-map spawn
* **[Options]** Option to de-spawn AI flights in the air if their start-type was manually set to In-Flight * **[Options]** Option to de-spawn AI flights in the air if their start-type was manually set to In-Flight
* **[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)
## Fixes ## Fixes
* **[Mission Generation]** Anti-ship strikes should use "group attack" in their attack-task * **[Mission Generation]** Anti-ship strikes should use "group attack" in their attack-task
@@ -49,6 +54,8 @@
* **[Capture Logic]** Release all parking slots when an airbase is captured * **[Capture Logic]** Release all parking slots when an airbase is captured
* **[Modding]** Swedish Military Assets Pack air defence presets are now correctly removed from the faction when the mod is disabled. * **[Modding]** Swedish Military Assets Pack air defence presets are now correctly removed from the faction when the mod is disabled.
* **[Mission Generation]** Naval aircraft not always returning to carrier * **[Mission Generation]** Naval aircraft not always returning to carrier
* **[Mission Generation]** AI AirLift aircraft crashing into terrain due to insufficient waypoints
* **[Mission Generation]** Fix friendly AI shooting at fires on the front-line
# Retribution v1.2.1 (hotfix) # Retribution v1.2.1 (hotfix)

View File

@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import random
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from typing import Iterator, TYPE_CHECKING, Type from typing import Iterator, TYPE_CHECKING, Type
@@ -38,6 +39,7 @@ class AirAssaultLayout(FormationAttackLayout):
if self.pickup is not None: if self.pickup is not None:
yield self.pickup yield self.pickup
yield from self.nav_to yield from self.nav_to
yield self.join
yield self.ingress yield self.ingress
if self.drop_off is not None: if self.drop_off is not None:
yield self.drop_off yield self.drop_off
@@ -131,19 +133,34 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
self._generate_ctld_pickup(), self._generate_ctld_pickup(),
) )
) )
pickup.alt = heli_alt
pickup_position = pickup.position pickup_position = pickup.position
ingress = builder.ingress(
FlightWaypointType.INGRESS_AIR_ASSAULT,
self.package.waypoints.ingress,
self.package.target,
)
assault_area = builder.assault_area(self.package.target) assault_area = builder.assault_area(self.package.target)
heading = self.package.target.position.heading_between_point(pickup_position)
if self.flight.is_hercules: if self.flight.is_hercules:
assault_area.only_for_player = False assault_area.only_for_player = False
assault_area.alt = feet(1000) assault_area.alt = feet(1000)
# TODO: define CTLD dropoff zones in campaign miz? tgt = self.package.target
drop_off_zone = MissionTarget( if isinstance(tgt, CTLD) and tgt.ctld_zones:
"Dropoff zone", top3 = sorted(
self.package.target.position.point_from_heading(heading, 1200), tgt.ctld_zones, key=lambda x: ingress.position.distance_to_point(x[0])
) )[:3]
pos, dist = random.choice(top3)
drop_pos = pos.random_point_within(dist)
else:
heading = tgt.position.heading_between_point(ingress.position)
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 dz = builder.dropoff_zone(drop_off_zone) if self.flight.is_helo else None
if dz:
dz.alt = heli_alt
return AirAssaultLayout( return AirAssaultLayout(
departure=builder.takeoff(self.flight.departure), departure=builder.takeoff(self.flight.departure),
@@ -154,11 +171,7 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
altitude, altitude,
altitude_is_agl, altitude_is_agl,
), ),
ingress=builder.ingress( ingress=ingress,
FlightWaypointType.INGRESS_AIR_ASSAULT,
self.package.waypoints.ingress,
self.package.target,
),
drop_off=dz, drop_off=dz,
targets=[assault_area], targets=[assault_area],
nav_from=builder.nav_path( nav_from=builder.nav_path(
@@ -171,8 +184,8 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
divert=builder.divert(self.flight.divert), divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(), bullseye=builder.bullseye(),
hold=None, hold=None,
join=builder.join(pickup_position), join=builder.join(ingress.position),
split=builder.split(self.package.waypoints.split), split=builder.split(self.flight.arrival.position),
refuel=None, refuel=None,
) )

View File

@@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import random
from collections.abc import Iterator from collections.abc import Iterator
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
@@ -7,7 +8,7 @@ from typing import Optional
from typing import TYPE_CHECKING, Type from typing import TYPE_CHECKING, Type
from game.theater.missiontarget import MissionTarget from game.theater.missiontarget import MissionTarget
from game.utils import feet from game.utils import feet, Distance
from ._common_ctld import generate_random_ctld_point from ._common_ctld import generate_random_ctld_point
from .ibuilder import IBuilder from .ibuilder import IBuilder
from .planningerror import PlanningError from .planningerror import PlanningError
@@ -23,13 +24,17 @@ if TYPE_CHECKING:
@dataclass @dataclass
class AirliftLayout(StandardLayout): class AirliftLayout(StandardLayout):
pickup_ascent: FlightWaypoint | None
pickup_descent: FlightWaypoint | None
# There will not be a pickup waypoint when the pickup airfield is the departure # There will not be a pickup waypoint when the pickup airfield is the departure
# airfield for cargo planes, as the cargo is pre-loaded. Helicopters will still pick # airfield for cargo planes, as the cargo is pre-loaded. Helicopters will still pick
# up the cargo near the airfield. # up the cargo near the airfield.
pickup: FlightWaypoint | None pickup: FlightWaypoint | None
# pickup_zone will be used for player flights to create the CTLD stuff # pickup_zone will be used for player flights to create the CTLD stuff
ctld_pickup_zone: FlightWaypoint | None ctld_pickup_zone: FlightWaypoint | None
drop_off_ascent: FlightWaypoint | None
nav_to_drop_off: list[FlightWaypoint] nav_to_drop_off: list[FlightWaypoint]
drop_off_descent: FlightWaypoint | None
# There will not be a drop-off waypoint when the drop-off airfield and the arrival # There will not be a drop-off waypoint when the drop-off airfield and the arrival
# airfield is the same for a cargo plane, as planes will land to unload and we don't # airfield is the same for a cargo plane, as planes will land to unload and we don't
# want a double landing. Helicopters will still drop their cargo near the airfield # want a double landing. Helicopters will still drop their cargo near the airfield
@@ -37,6 +42,8 @@ class AirliftLayout(StandardLayout):
drop_off: FlightWaypoint | None drop_off: FlightWaypoint | None
# drop_off_zone will be used for player flights to create the CTLD stuff # drop_off_zone will be used for player flights to create the CTLD stuff
ctld_drop_off_zone: FlightWaypoint | None ctld_drop_off_zone: FlightWaypoint | None
return_ascent: FlightWaypoint
return_descent: FlightWaypoint
def add_waypoint( def add_waypoint(
self, wpt: FlightWaypoint, next_wpt: Optional[FlightWaypoint] self, wpt: FlightWaypoint, next_wpt: Optional[FlightWaypoint]
@@ -60,17 +67,27 @@ class AirliftLayout(StandardLayout):
def iter_waypoints(self) -> Iterator[FlightWaypoint]: def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure yield self.departure
if self.pickup_ascent is not None:
yield self.pickup_ascent
yield from self.nav_to yield from self.nav_to
if self.pickup_descent is not None:
yield self.pickup_descent
if self.pickup is not None: if self.pickup is not None:
yield self.pickup yield self.pickup
if self.ctld_pickup_zone is not None: if self.ctld_pickup_zone is not None:
yield self.ctld_pickup_zone yield self.ctld_pickup_zone
if self.drop_off_ascent is not None:
yield self.drop_off_ascent
yield from self.nav_to_drop_off yield from self.nav_to_drop_off
if self.drop_off_descent is not None:
yield self.drop_off_descent
if self.drop_off is not None: if self.drop_off is not None:
yield self.drop_off yield self.drop_off
yield self.return_ascent
if self.ctld_drop_off_zone is not None: if self.ctld_drop_off_zone is not None:
yield self.ctld_drop_off_zone yield self.ctld_drop_off_zone
yield from self.nav_from yield from self.nav_from
yield self.return_descent
yield self.arrival yield self.arrival
if self.divert is not None: if self.divert is not None:
yield self.divert yield self.divert
@@ -121,15 +138,47 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
builder = WaypointBuilder(self.flight) builder = WaypointBuilder(self.flight)
pickup_ascent = None
pickup_descent = None
pickup = None pickup = None
drop_off_ascent = None
drop_off_descent = None
drop_off = None drop_off = None
pickup_zone = None pickup_zone = None
drop_off_zone = None drop_off_zone = None
if cargo.origin != self.flight.departure: if cargo.origin != self.flight.departure:
pickup = builder.cargo_stop(cargo.origin) pickup = builder.cargo_stop(cargo.origin)
pickup_ascent = self._create_ascent_or_descent(
builder,
self.flight.departure.position,
cargo.origin.position,
altitude,
altitude_is_agl,
)
pickup_descent = self._create_ascent_or_descent(
builder,
cargo.origin.position,
self.flight.departure.position,
altitude,
altitude_is_agl,
)
if cargo.next_stop != self.flight.arrival: if cargo.next_stop != self.flight.arrival:
drop_off = builder.cargo_stop(cargo.next_stop) drop_off = builder.cargo_stop(cargo.next_stop)
drop_off_ascent = self._create_ascent_or_descent(
builder,
cargo.origin.position,
cargo.next_stop.position,
altitude,
altitude_is_agl,
)
drop_off_descent = self._create_ascent_or_descent(
builder,
cargo.next_stop.position,
cargo.origin.position,
altitude,
altitude_is_agl,
)
if self.flight.is_helo: if self.flight.is_helo:
# Create CTLD Zones for Helo flights # Create CTLD Zones for Helo flights
@@ -150,25 +199,50 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
altitude_is_agl, altitude_is_agl,
) )
return_ascent = self._create_ascent_or_descent(
builder,
cargo.next_stop.position
if cargo.next_stop != self.flight.arrival
else cargo.origin.position,
self.flight.arrival.position,
altitude,
altitude_is_agl,
)
return_descent = self._create_ascent_or_descent(
builder,
self.flight.arrival.position,
cargo.next_stop.position
if cargo.next_stop != self.flight.arrival
else cargo.origin.position,
altitude,
altitude_is_agl,
)
return AirliftLayout( return AirliftLayout(
departure=builder.takeoff(self.flight.departure), departure=builder.takeoff(self.flight.departure),
pickup_ascent=pickup_ascent,
nav_to=nav_to_pickup, nav_to=nav_to_pickup,
pickup_descent=pickup_descent,
pickup=pickup, pickup=pickup,
ctld_pickup_zone=pickup_zone, ctld_pickup_zone=pickup_zone,
drop_off_ascent=drop_off_ascent,
nav_to_drop_off=builder.nav_path( nav_to_drop_off=builder.nav_path(
cargo.origin.position, cargo.origin.position,
cargo.next_stop.position, cargo.next_stop.position,
altitude, altitude,
altitude_is_agl, altitude_is_agl,
), ),
drop_off_descent=drop_off_descent,
drop_off=drop_off, drop_off=drop_off,
ctld_drop_off_zone=drop_off_zone, ctld_drop_off_zone=drop_off_zone,
return_ascent=return_ascent,
nav_from=builder.nav_path( nav_from=builder.nav_path(
cargo.origin.position, cargo.origin.position,
self.flight.arrival.position, self.flight.arrival.position,
altitude, altitude,
altitude_is_agl, altitude_is_agl,
), ),
return_descent=return_descent,
arrival=builder.land(self.flight.arrival), arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert), divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(), bullseye=builder.bullseye(),
@@ -188,3 +262,18 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
if cargo and cargo.transport and isinstance(cargo.transport.destination, CTLD): if cargo and cargo.transport and isinstance(cargo.transport.destination, CTLD):
return generate_random_ctld_point(cargo.transport.destination) return generate_random_ctld_point(cargo.transport.destination)
raise RuntimeError("Could not generate CTLD dropoff") raise RuntimeError("Could not generate CTLD dropoff")
@staticmethod
def _create_ascent_or_descent(
builder: WaypointBuilder,
start: Point,
end: Point,
alt: Distance,
agl: bool,
) -> FlightWaypoint:
distance = start.distance_to_point(end)
rdistance = 1000 if agl else min(distance / 10, 20000)
heading = round(start.heading_between_point(end))
rheading = random.randint(heading - 30, heading + 30) % 360
pos = start.point_from_heading(float(rheading), rdistance)
return builder.nav(pos, alt, agl)

View File

@@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta, datetime
from typing import Type from typing import Type
from .airassault import AirAssaultLayout from .airassault import AirAssaultLayout
@@ -16,18 +15,6 @@ from ...utils import feet
class EscortFlightPlan(FormationAttackFlightPlan): class EscortFlightPlan(FormationAttackFlightPlan):
@property
def push_time(self) -> datetime:
hold2join_time = (
self.travel_time_between_waypoints(
self.layout.hold,
self.layout.join,
)
if self.layout.hold is not None
else timedelta(0)
)
return self.join_time - hold2join_time
@staticmethod @staticmethod
def builder_type() -> Type[Builder]: def builder_type() -> Type[Builder]:
return Builder return Builder
@@ -44,16 +31,17 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
ingress.only_for_player = True ingress.only_for_player = True
target.only_for_player = True target.only_for_player = True
hold = None hold = None
if not self.primary_flight_is_air_assault: if not self.flight.is_helo:
hold = builder.hold(self._hold_point()) hold = builder.hold(self._hold_point())
elif self.package.primary_flight is not None:
fp = self.package.primary_flight.flight_plan
assert isinstance(fp.layout, AirAssaultLayout)
if fp.layout.pickup:
hold = builder.hold(fp.layout.pickup.position)
join = builder.join(self.package.waypoints.join) join_pos = (
split = builder.split(self.package.waypoints.split) self.package.waypoints.ingress
if self.flight.is_helo
else self.package.waypoints.join
)
join = builder.join(join_pos)
split = builder.split(self._get_split())
ingress_alt = self.doctrine.ingress_altitude ingress_alt = self.doctrine.ingress_altitude
is_helo = builder.flight.is_helo is_helo = builder.flight.is_helo
@@ -70,10 +58,12 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
layout, AirliftLayout layout, AirliftLayout
) )
if isinstance(layout, AirliftLayout): if isinstance(layout, AirliftLayout):
join = builder.join(layout.departure.position) ascent = layout.pickup_ascent or layout.drop_off_ascent
else: assert ascent is not None
join = builder.join(layout.ingress.position) join = builder.join(ascent.position)
if layout.pickup: 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) join = builder.join(layout.pickup.position)
split = builder.split(layout.arrival.position) split = builder.split(layout.arrival.position)
if layout.drop_off: if layout.drop_off:

View File

@@ -71,15 +71,6 @@ class FlightPlan(ABC, Generic[LayoutT]):
"""A list of all waypoints in the flight plan, in order.""" """A list of all waypoints in the flight plan, in order."""
return list(self.iter_waypoints()) return list(self.iter_waypoints())
def get_index_of_wpt_by_type(self, wpt_type: FlightWaypointType) -> int:
index = 0
for wpt in self.waypoints:
if wpt and not wpt.only_for_player:
index += 1
if wpt.waypoint_type == wpt_type:
return index
return -1
def iter_waypoints(self) -> Iterator[FlightWaypoint]: def iter_waypoints(self) -> Iterator[FlightWaypoint]:
"""Iterates over all waypoints in the flight plan, in order.""" """Iterates over all waypoints in the flight plan, in order."""
yield from self.layout.iter_waypoints() yield from self.layout.iter_waypoints()
@@ -113,6 +104,19 @@ class FlightPlan(ABC, Generic[LayoutT]):
# #
# Plus, it's a loiter point so there's no reason to hurry. # Plus, it's a loiter point so there's no reason to hurry.
factor = 0.75 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. # TODO: Adjust if AGL.
# We don't have an exact heightmap, but we should probably be performing # 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 # *some* adjustment for NTTR since the minimum altitude of the map is

View File

@@ -17,7 +17,7 @@ if TYPE_CHECKING:
@dataclass @dataclass
class FormationLayout(LoiterLayout, ABC): class FormationLayout(LoiterLayout, ABC):
join: Optional[FlightWaypoint] join: FlightWaypoint
split: FlightWaypoint split: FlightWaypoint
refuel: Optional[FlightWaypoint] refuel: Optional[FlightWaypoint]
@@ -92,10 +92,15 @@ class FormationFlightPlan(LoiterFlightPlan, ABC):
@property @property
def push_time(self) -> datetime: def push_time(self) -> datetime:
return self.join_time - self.travel_time_between_waypoints( hold2join_time = (
self.layout.hold, self.travel_time_between_waypoints(
self.layout.join, self.layout.hold,
self.layout.join,
)
if self.layout.hold
else timedelta(0)
) )
return self.join_time - hold2join_time
@property @property
def mission_begin_on_station_time(self) -> datetime | None: def mission_begin_on_station_time(self) -> datetime | None:

View File

@@ -142,8 +142,7 @@ class FormationAttackLayout(FormationLayout):
if self.hold: if self.hold:
yield self.hold yield self.hold
yield from self.nav_to yield from self.nav_to
if self.join: yield self.join
yield self.join
if self.lineup: if self.lineup:
yield self.lineup yield self.lineup
yield self.ingress yield self.ingress
@@ -187,11 +186,13 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
) )
hold = None hold = None
join = None if not self.flight.is_helo:
if not self.primary_flight_is_air_assault:
hold = builder.hold(self._hold_point()) hold = builder.hold(self._hold_point())
join = builder.join(self.package.waypoints.join) join_pos = self.package.waypoints.join
split = builder.split(self.package.waypoints.split) if self.flight.is_helo:
join_pos = self.package.waypoints.ingress
join = builder.join(join_pos)
split = builder.split(self._get_split())
refuel = self._build_refuel(builder) refuel = self._build_refuel(builder)
ingress = builder.ingress( ingress = builder.ingress(
@@ -255,6 +256,9 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
@property @property
def primary_flight_is_air_assault(self) -> bool: def primary_flight_is_air_assault(self) -> bool:
if self.flight is self.package.primary_flight: if self.flight is self.package.primary_flight:
# Can't call self.package.primary_flight.flight_plan here
# because the flight-plan wasn't created yet.
# Calling the fligh_plan property would result in infinite recursion
return self.flight.flight_type == FlightType.AIR_ASSAULT return self.flight.flight_type == FlightType.AIR_ASSAULT
else: else:
assert self.package.primary_flight is not None assert self.package.primary_flight is not None
@@ -296,3 +300,13 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
return HoldZoneGeometry( return HoldZoneGeometry(
target, origin, ip, join, self.coalition, self.theater target, origin, ip, join, self.coalition, self.theater
).find_best_hold_point() ).find_best_hold_point()
def _get_split(self) -> Point:
assert self.package.waypoints is not None
assert self.package.primary_flight is not None
split_pos = (
self.package.primary_flight.arrival.position
if self.package.primary_flight.is_helo
else self.package.waypoints.split
)
return split_pos

View File

@@ -15,7 +15,6 @@ from typing import (
from dcs.mapping import Point, Vector2 from dcs.mapping import Point, Vector2
from game.ato.flightplans._common_ctld import generate_random_ctld_point
from game.ato.flightwaypoint import AltitudeReference, FlightWaypoint from game.ato.flightwaypoint import AltitudeReference, FlightWaypoint
from game.ato.flightwaypointtype import FlightWaypointType from game.ato.flightwaypointtype import FlightWaypointType
from game.theater import ( from game.theater import (
@@ -25,7 +24,6 @@ from game.theater import (
TheaterGroundObject, TheaterGroundObject,
TheaterUnit, TheaterUnit,
) )
from game.theater.interfaces.CTLD import CTLD
from game.utils import Distance, meters, nautical_miles, feet from game.utils import Distance, meters, nautical_miles, feet
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -250,10 +248,14 @@ class WaypointBuilder:
else feet(1000) else feet(1000)
) )
heading = objective.position.heading_between_point(position)
return FlightWaypoint( return FlightWaypoint(
"INGRESS", "INGRESS",
ingress_type, ingress_type,
position, objective.position.point_from_heading(heading, nautical_miles(5).meters)
if self.is_helo
else position,
alt, alt,
alt_type, alt_type,
description=f"INGRESS on {objective.name}", description=f"INGRESS on {objective.name}",
@@ -635,14 +637,10 @@ class WaypointBuilder:
"""Creates a cargo stop waypoint. """Creates a cargo stop waypoint.
This waypoint is used by AirLift as a landing and stopover waypoint This waypoint is used by AirLift as a landing and stopover waypoint
""" """
if isinstance(control_point, CTLD) and control_point.ctld_zones:
pos = generate_random_ctld_point(control_point)
else:
pos = control_point.position
return FlightWaypoint( return FlightWaypoint(
"CARGOSTOP", "CARGOSTOP",
FlightWaypointType.CARGO_STOP, FlightWaypointType.CARGO_STOP,
pos, control_point.position,
meters(0), meters(0),
"RADIO", "RADIO",
description=f"Stop for cargo at {control_point.name}", description=f"Stop for cargo at {control_point.name}",

View File

@@ -11,6 +11,7 @@ from dcs.unittype import FlyingType
from game.data.weapons import Pylon, Weapon, WeaponType from game.data.weapons import Pylon, Weapon, WeaponType
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
from .flighttype import FlightType from .flighttype import FlightType
from ..persistency import prefer_liberation_payloads
if TYPE_CHECKING: if TYPE_CHECKING:
from .flight import Flight from .flight import Flight
@@ -161,7 +162,10 @@ class Loadout:
# last - the first element in the tuple will be tried first, then the second, # last - the first element in the tuple will be tried first, then the second,
# etc. # etc.
loadout_names = { loadout_names = {
t: [f"Retribution {t.value}", f"Liberation {t.value}"] for t in FlightType t: [f"Liberation {t.value}", f"Retribution {t.value}"]
if prefer_liberation_payloads()
else [f"Retribution {t.value}", f"Liberation {t.value}"]
for t in FlightType
} }
legacy_names = { legacy_names = {
FlightType.TARCAP: ( FlightType.TARCAP: (

View File

@@ -3,6 +3,7 @@ from enum import Enum, auto
from typing import Optional from typing import Optional
from game.ato.flighttype import FlightType from game.ato.flighttype import FlightType
from game.dcs.aircrafttype import AircraftType
from game.theater import MissionTarget from game.theater import MissionTarget
@@ -33,6 +34,8 @@ class ProposedFlight:
#: field is None. #: field is None.
escort_type: Optional[EscortType] = field(default=None) escort_type: Optional[EscortType] = field(default=None)
preferred_type: Optional[AircraftType] = field(default=None)
def __str__(self) -> str: def __str__(self) -> str:
return f"{self.task} {self.num_aircraft} ship" return f"{self.task} {self.num_aircraft} ship"

View File

@@ -140,7 +140,7 @@ class ObjectiveFinder:
def vulnerable_control_points(self) -> Iterator[ControlPoint]: def vulnerable_control_points(self) -> Iterator[ControlPoint]:
"""Iterates over friendly CPs that are vulnerable to enemy CPs. """Iterates over friendly CPs that are vulnerable to enemy CPs.
Vulnerability is defined as any enemy CP within threat range of of the Vulnerability is defined as any enemy CP within threat range of the
CP. CP.
""" """
for cp in self.friendly_control_points(): for cp in self.friendly_control_points():

View File

@@ -49,7 +49,12 @@ class PackageBuilder:
pf = self.package.primary_flight pf = self.package.primary_flight
heli = pf.is_helo if pf else False heli = pf.is_helo if pf else False
squadron = self.air_wing.best_squadron_for( squadron = self.air_wing.best_squadron_for(
self.package.target, plan.task, plan.num_aircraft, heli, this_turn=True self.package.target,
plan.task,
plan.num_aircraft,
heli,
this_turn=True,
preferred_type=plan.preferred_type,
) )
if squadron is None: if squadron is None:
return False return False

View File

@@ -0,0 +1,15 @@
from collections.abc import Iterator
from game.commander.tasks.primitive.antiship import PlanAntiShip
from game.commander.theaterstate import TheaterState
from game.htn import CompoundTask, Method
class AttackShips(CompoundTask[TheaterState]):
def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]:
for ship in state.enemy_ships:
# Ammo depots are targeted based on the needs of the front line by
# ReduceEnemyFrontLineCapacity. No reason to target them before that front
# line is active.
if ship.has_live_radar_sam:
yield [PlanAntiShip(ship)]

View File

@@ -6,6 +6,7 @@ from game.commander.tasks.compound.attackairinfrastructure import (
) )
from game.commander.tasks.compound.attackbattlepositions import AttackBattlePositions from game.commander.tasks.compound.attackbattlepositions import AttackBattlePositions
from game.commander.tasks.compound.attackbuildings import AttackBuildings from game.commander.tasks.compound.attackbuildings import AttackBuildings
from game.commander.tasks.compound.attackships import AttackShips
from game.commander.tasks.compound.capturebases import CaptureBases from game.commander.tasks.compound.capturebases import CaptureBases
from game.commander.tasks.compound.defendbases import DefendBases from game.commander.tasks.compound.defendbases import DefendBases
from game.commander.tasks.compound.degradeiads import DegradeIads from game.commander.tasks.compound.degradeiads import DegradeIads
@@ -25,10 +26,11 @@ class PlanNextAction(CompoundTask[TheaterState]):
def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]:
yield [TheaterSupport()] yield [TheaterSupport()]
yield [ProtectAirSpace()] yield [ProtectAirSpace()]
yield [CaptureBases()]
yield [DefendBases()] yield [DefendBases()]
yield [InterdictReinforcements()] yield [InterdictReinforcements()]
yield [DegradeIads()]
yield [AttackBattlePositions()] yield [AttackBattlePositions()]
yield [CaptureBases()]
yield [AttackAirInfrastructure(self.aircraft_cold_start)] yield [AttackAirInfrastructure(self.aircraft_cold_start)]
yield [AttackBuildings()] yield [AttackBuildings()]
yield [DegradeIads()] yield [AttackShips()]

View File

@@ -372,10 +372,10 @@ class Game:
persistency.autosave(self) persistency.autosave(self)
def check_win_loss(self) -> TurnState: def check_win_loss(self) -> TurnState:
if not self.theater.player_points(): if not self.theater.player_points(state_check=True):
return TurnState.LOSS return TurnState.LOSS
if not self.theater.enemy_points(): if not self.theater.enemy_points(state_check=True):
return TurnState.WIN return TurnState.WIN
return TurnState.CONTINUE return TurnState.CONTINUE

View File

@@ -7,6 +7,8 @@ from typing import TYPE_CHECKING, Any
from dcs.countries import countries_by_name from dcs.countries import countries_by_name
from game.ato import FlightType from game.ato import FlightType
from game.ato.flightplans.formation import FormationLayout
from game.ato.flightplans.waypointbuilder import WaypointBuilder
from game.ato.packagewaypoints import PackageWaypoints from game.ato.packagewaypoints import PackageWaypoints
from game.data.doctrine import MODERN_DOCTRINE, COLDWAR_DOCTRINE, WWII_DOCTRINE from game.data.doctrine import MODERN_DOCTRINE, COLDWAR_DOCTRINE, WWII_DOCTRINE
from game.theater import ParkingType, SeasonalConditions from game.theater import ParkingType, SeasonalConditions
@@ -107,6 +109,10 @@ class Migrator:
try_set_attr(layout, "nav_from", []) try_set_attr(layout, "nav_from", [])
if f.flight_type == FlightType.CAS: if f.flight_type == FlightType.CAS:
try_set_attr(layout, "ingress", None) try_set_attr(layout, "ingress", None)
if isinstance(layout, FormationLayout):
if not layout.join and f.package.waypoints:
builder = WaypointBuilder(f, [])
layout.join = builder.join(f.package.waypoints.join)
def _update_flights(self) -> None: def _update_flights(self) -> None:
to_remove = [] to_remove = []

View File

@@ -1,5 +1,5 @@
import logging import logging
from typing import Any, Optional, Type from typing import Any, Optional, Type, List
from dcs.task import ( from dcs.task import (
AWACS, AWACS,
@@ -124,7 +124,8 @@ class AircraftBehavior:
unit.gun = 0 unit.gun = 0
group.points[0].tasks.append(OptRTBOnBingoFuel(rtb_on_bingo)) group.points[0].tasks.append(OptRTBOnBingoFuel(rtb_on_bingo))
group.points[0].tasks.append(OptJettisonEmptyTanks()) if flight.coalition.game.settings.ai_jettison_empty_tanks:
group.points[0].tasks.append(OptJettisonEmptyTanks())
# Do not restrict afterburner. # Do not restrict afterburner.
# https://forums.eagle.ru/forum/english/digital-combat-simulator/dcs-world-2-5/bugs-and-problems-ai/ai-ad/7121294-ai-stuck-at-high-aoa-after-making-sharp-turn-if-afterburner-is-restricted # https://forums.eagle.ru/forum/english/digital-combat-simulator/dcs-world-2-5/bugs-and-problems-ai/ai-ad/7121294-ai-stuck-at-high-aoa-after-making-sharp-turn-if-afterburner-is-restricted
@@ -152,7 +153,7 @@ class AircraftBehavior:
self.configure_behavior(flight, group, rtb_winchester=ammo_type) self.configure_behavior(flight, group, rtb_winchester=ammo_type)
def configure_cas(self, group: FlyingGroup[Any], flight: Flight) -> None: def configure_cas(self, group: FlyingGroup[Any], flight: Flight) -> None:
self.configure_task(flight, group, CAS, AFAC) self.configure_task(flight, group, CAS, [AFAC, AntishipStrike])
self.configure_behavior( self.configure_behavior(
flight, flight,
group, group,
@@ -170,7 +171,7 @@ class AircraftBehavior:
# Note that the only effect that the DCS task type has is in determining which # Note that the only effect that the DCS task type has is in determining which
# waypoint actions the group may perform. # waypoint actions the group may perform.
self.configure_task(flight, group, SEAD, CAS) self.configure_task(flight, group, SEAD, [CAS, AFAC, AntishipStrike])
self.configure_behavior( self.configure_behavior(
flight, flight,
group, group,
@@ -186,7 +187,7 @@ class AircraftBehavior:
# available aircraft, and F-14s are not able to be SEAD despite having TALDs. # available aircraft, and F-14s are not able to be SEAD despite having TALDs.
# https://forums.eagle.ru/topic/272112-cannot-assign-f-14-to-sead/ # https://forums.eagle.ru/topic/272112-cannot-assign-f-14-to-sead/
self.configure_task(flight, group, SEAD, CAS) self.configure_task(flight, group, SEAD, [CAS, AFAC, AntishipStrike])
self.configure_behavior( self.configure_behavior(
flight, flight,
group, group,
@@ -200,7 +201,7 @@ class AircraftBehavior:
) )
def configure_strike(self, group: FlyingGroup[Any], flight: Flight) -> None: def configure_strike(self, group: FlyingGroup[Any], flight: Flight) -> None:
self.configure_task(flight, group, GroundAttack, PinpointStrike) self.configure_task(flight, group, GroundAttack, [PinpointStrike, AFAC])
self.configure_behavior( self.configure_behavior(
flight, flight,
group, group,
@@ -211,7 +212,7 @@ class AircraftBehavior:
) )
def configure_anti_ship(self, group: FlyingGroup[Any], flight: Flight) -> None: def configure_anti_ship(self, group: FlyingGroup[Any], flight: Flight) -> None:
self.configure_task(flight, group, AntishipStrike, CAS) self.configure_task(flight, group, AntishipStrike, [CAS, AFAC, SEAD])
self.configure_behavior( self.configure_behavior(
flight, flight,
group, group,
@@ -233,7 +234,7 @@ class AircraftBehavior:
) )
def configure_oca_strike(self, group: FlyingGroup[Any], flight: Flight) -> None: def configure_oca_strike(self, group: FlyingGroup[Any], flight: Flight) -> None:
self.configure_task(flight, group, CAS) self.configure_task(flight, group, CAS, [AFAC, SEAD])
self.configure_behavior( self.configure_behavior(
flight, flight,
group, group,
@@ -345,7 +346,7 @@ class AircraftBehavior:
flight: Flight, flight: Flight,
group: FlyingGroup[Any], group: FlyingGroup[Any],
preferred_task: Type[MainTask], preferred_task: Type[MainTask],
fallback_task: Optional[Type[MainTask]] = None, fallback_tasks: Optional[List[Type[MainTask]]] = None,
) -> None: ) -> None:
ac_type = flight.unit_type.dcs_unit_type.id ac_type = flight.unit_type.dcs_unit_type.id
@@ -358,15 +359,22 @@ class AircraftBehavior:
if preferred_task in flight.unit_type.dcs_unit_type.tasks: if preferred_task in flight.unit_type.dcs_unit_type.tasks:
group.task = preferred_task.name group.task = preferred_task.name
elif fallback_task and fallback_task in flight.unit_type.dcs_unit_type.tasks: elif fallback_tasks:
group.task = fallback_task.name 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: elif flight.unit_type.dcs_unit_type.task_default and preferred_task == Nothing:
group.task = flight.unit_type.dcs_unit_type.task_default.name group.task = flight.unit_type.dcs_unit_type.task_default.name
logging.warning( logging.warning(
f"{ac_type} is not capable of 'Nothing', using default task '{group.task}'" f"{ac_type} is not capable of 'Nothing', using default task '{group.task}'"
) )
else: else:
fallback_part = f" nor {fallback_task.name}" if fallback_task else "" fallback_part = (
f" nor any of the following fall-back tasks: {[task.name for task in fallback_tasks]}"
if fallback_tasks
else ""
)
raise RuntimeError( raise RuntimeError(
f"{ac_type} is neither capable of {preferred_task.name}" f"{ac_type} is neither capable of {preferred_task.name}"
f"{fallback_part}. Can't generate {flight.flight_type} flight." f"{fallback_part}. Can't generate {flight.flight_type} flight."

View File

@@ -243,6 +243,8 @@ class FlightGroupSpawner:
speed=speed.kph, speed=speed.kph,
maintask=None, maintask=None,
group_size=self.flight.count, group_size=self.flight.count,
callsign_name=self.flight.callsign.name if self.flight.callsign else None,
callsign_nr=self.flight.callsign.nr if self.flight.callsign else None,
) )
group.points[0].alt_type = alt_type group.points[0].alt_type = alt_type

View File

@@ -15,9 +15,9 @@ class AntiShipIngressBuilder(PydcsWaypointBuilder):
target = self.package.target target = self.package.target
if isinstance(target, NavalControlPoint): if isinstance(target, NavalControlPoint):
carrier_name = target.get_carrier_group_name() carrier_tgo = target.ground_objects[0]
if carrier_name: for g in carrier_tgo.groups:
group_names.append(carrier_name) group_names.append(g.group_name)
elif isinstance(target, TheaterGroundObject): elif isinstance(target, TheaterGroundObject):
for group in target.groups: for group in target.groups:
group_names.append(group.group_name) group_names.append(group.group_name)

View File

@@ -11,7 +11,8 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
class BaiIngressBuilder(PydcsWaypointBuilder): class BaiIngressBuilder(PydcsWaypointBuilder):
def add_tasks(self, waypoint: MovingPoint) -> None: def add_tasks(self, waypoint: MovingPoint) -> None:
self.register_special_ingress_points() self.register_special_ingress_points()
waypoint.tasks.append(OptFormation.trail_open()) if not self.flight.is_helo:
waypoint.tasks.append(OptFormation.trail_open())
# TODO: Add common "UnitGroupTarget" base type. # TODO: Add common "UnitGroupTarget" base type.
group_names = [] group_names = []
target = self.package.target target = self.package.target

View File

@@ -94,7 +94,11 @@ class JoinPointBuilder(PydcsWaypointBuilder):
max_dist: float = 30.0, max_dist: float = 30.0,
vertical_spacing: float = 2000.0, vertical_spacing: float = 2000.0,
) -> None: ) -> None:
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFire)) 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 rx = (random.random() + 0.1) * 333
ry = feet(vertical_spacing).meters ry = feet(vertical_spacing).meters

View File

@@ -4,6 +4,7 @@ from dcs.task import (
ControlledTask, ControlledTask,
EngageTargets, EngageTargets,
Targets, Targets,
OptROE,
) )
from game.utils import nautical_miles from game.utils import nautical_miles
@@ -13,6 +14,7 @@ from .pydcswaypointbuilder import PydcsWaypointBuilder
class SeadSweepIngressBuilder(PydcsWaypointBuilder): class SeadSweepIngressBuilder(PydcsWaypointBuilder):
def add_tasks(self, waypoint: MovingPoint) -> None: def add_tasks(self, waypoint: MovingPoint) -> None:
self.register_special_ingress_points() self.register_special_ingress_points()
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFireWeaponFree))
# Preemptively use ECM to better avoid getting swatted. # Preemptively use ECM to better avoid getting swatted.
ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar) ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar)
waypoint.tasks.append(ecm_option) waypoint.tasks.append(ecm_option)
@@ -26,7 +28,7 @@ class SeadSweepIngressBuilder(PydcsWaypointBuilder):
self.flight.coalition.game.settings.sead_sweep_engagement_range_distance self.flight.coalition.game.settings.sead_sweep_engagement_range_distance
).meters ).meters
), ),
targets=[Targets.All.GroundUnits.AirDefence.AAA.SAMRelated], targets=[Targets.All.GroundUnits.AirDefence],
) )
) )
) )

View File

@@ -7,6 +7,7 @@ from dcs.task import (
SwitchWaypoint, SwitchWaypoint,
) )
from game.utils import knots
from .pydcswaypointbuilder import PydcsWaypointBuilder from .pydcswaypointbuilder import PydcsWaypointBuilder
@@ -29,10 +30,12 @@ class SplitPointBuilder(PydcsWaypointBuilder):
waypoint.tasks.append(OptFormation.rotary_wedge()) waypoint.tasks.append(OptFormation.rotary_wedge())
else: else:
waypoint.tasks.append(OptFormation.finger_four_close()) waypoint.tasks.append(OptFormation.finger_four_close())
if not self.flight.is_helo: waypoint.speed_locked = True
waypoint.speed_locked = True waypoint.ETA_locked = False
if self.flight.is_helo:
waypoint.speed = knots(100).meters_per_second
else:
waypoint.speed = self.flight.coalition.doctrine.rtb_speed.meters_per_second waypoint.speed = self.flight.coalition.doctrine.rtb_speed.meters_per_second
waypoint.ETA_locked = False
if self.flight is self.package.primary_flight: if self.flight is self.package.primary_flight:
script = RunScript( script = RunScript(
f'trigger.action.setUserFlag("split-{id(self.package)}", true)' f'trigger.action.setUserFlag("split-{id(self.package)}", true)'

View File

@@ -1,7 +1,7 @@
import logging import logging
from dcs.point import MovingPoint from dcs.point import MovingPoint
from dcs.task import EngageTargets, OptFormation, Targets from dcs.task import EngageTargets, OptFormation, Targets, OptROE
from game.ato.flightplans.sweep import SweepFlightPlan from game.ato.flightplans.sweep import SweepFlightPlan
from game.utils import nautical_miles from game.utils import nautical_miles
@@ -16,6 +16,8 @@ class SweepIngressBuilder(PydcsWaypointBuilder):
else: else:
waypoint.tasks.append(OptFormation.spread_four_open()) waypoint.tasks.append(OptFormation.spread_four_open())
waypoint.tasks.append(OptROE(value=OptROE.Values.OpenFireWeaponFree))
if not isinstance(self.flight.flight_plan, SweepFlightPlan): if not isinstance(self.flight.flight_plan, SweepFlightPlan):
flight_plan_type = self.flight.flight_plan.__class__.__name__ flight_plan_type = self.flight.flight_plan.__class__.__name__
logging.error( logging.error(

View File

@@ -73,7 +73,7 @@ class VisualsGenerator:
self.game = game self.game = game
def _generate_frontline_smokes(self) -> None: def _generate_frontline_smokes(self) -> None:
country = self.mission.country(self.game.red.faction.country.name) country = list(self.mission.coalition["neutrals"].countries.values())[0]
for front_line in self.game.theater.conflicts(): for front_line in self.game.theater.conflicts():
from_cp = front_line.blue_cp from_cp = front_line.blue_cp
to_cp = front_line.red_cp to_cp = front_line.red_cp

View File

@@ -16,6 +16,8 @@ if TYPE_CHECKING:
from game import Game from game import Game
_dcs_saved_game_folder: Optional[str] = None _dcs_saved_game_folder: Optional[str] = None
_prefer_liberation_payloads: bool = False
_server_port: int = 16880
# fmt: off # fmt: off
@@ -61,6 +63,8 @@ class MigrationUnpickler(pickle.Unpickler):
return dcs.terrain.falklands.airports.Hipico_Flying_Club return dcs.terrain.falklands.airports.Hipico_Flying_Club
if name in ["SaveManager", "SaveGameBundle"]: if name in ["SaveManager", "SaveGameBundle"]:
return DummyObject return DummyObject
if name == "CaletaTortel":
return dcs.terrain.falklands.airports.Caleta_Tortel_Airport
if module == "pydcs_extensions.f4b.f4b": if module == "pydcs_extensions.f4b.f4b":
return pydcs_extensions.f4 return pydcs_extensions.f4
if module == "pydcs_extensions.irondome.irondome": if module == "pydcs_extensions.irondome.irondome":
@@ -74,9 +78,13 @@ class MigrationUnpickler(pickle.Unpickler):
# fmt: on # fmt: on
def setup(user_folder: str) -> None: def setup(user_folder: str, prefer_liberation_payloads: bool, port: int) -> None:
global _dcs_saved_game_folder global _dcs_saved_game_folder
global _prefer_liberation_payloads
global _server_port
_dcs_saved_game_folder = user_folder _dcs_saved_game_folder = user_folder
_prefer_liberation_payloads = prefer_liberation_payloads
_server_port = port
if not save_dir().exists(): if not save_dir().exists():
save_dir().mkdir(parents=True) save_dir().mkdir(parents=True)
@@ -110,6 +118,11 @@ def payloads_dir(backup: bool = False) -> Path:
return payloads return payloads
def prefer_liberation_payloads() -> bool:
global _prefer_liberation_payloads
return _prefer_liberation_payloads
def user_custom_weapon_injections_dir() -> Path: def user_custom_weapon_injections_dir() -> Path:
return base_path() / "Retribution" / "WeaponInjections" return base_path() / "Retribution" / "WeaponInjections"
@@ -118,6 +131,11 @@ def save_dir() -> Path:
return base_path() / "Retribution" / "Saves" return base_path() / "Retribution" / "Saves"
def server_port() -> int:
global _server_port
return _server_port
def _temporary_save_file() -> str: def _temporary_save_file() -> str:
return str(save_dir() / "tmpsave.retribution") return str(save_dir() / "tmpsave.retribution")

View File

@@ -281,9 +281,45 @@ class PretenseAircraftGenerator:
num_of_bai = 0 num_of_bai = 0
num_of_strike = 0 num_of_strike = 0
num_of_cap = 0 num_of_cap = 0
sead_tasks = [FlightType.SEAD, FlightType.SEAD_SWEEP, FlightType.SEAD_ESCORT]
strike_tasks = [
FlightType.STRIKE,
FlightType.OCA_RUNWAY,
FlightType.OCA_AIRCRAFT,
]
patrol_tasks = [
FlightType.BARCAP,
FlightType.TARCAP,
FlightType.ESCORT,
FlightType.INTERCEPTION,
]
sead_capable_cp = False
cas_capable_cp = False
bai_capable_cp = False
strike_capable_cp = False
patrol_capable_cp = False
# First check what are the capabilities of the squadrons on this CP
for squadron in cp.squadrons:
for task in sead_tasks:
if task in squadron.auto_assignable_mission_types:
sead_capable_cp = True
for task in strike_tasks:
if task in squadron.auto_assignable_mission_types:
if not squadron.aircraft.helicopter:
strike_capable_cp = True
for task in patrol_tasks:
if task in squadron.auto_assignable_mission_types:
if not squadron.aircraft.helicopter:
patrol_capable_cp = True
if FlightType.CAS in squadron.auto_assignable_mission_types:
cas_capable_cp = True
if FlightType.BAI in squadron.auto_assignable_mission_types:
bai_capable_cp = True
random_squadron_list = list(cp.squadrons) random_squadron_list = list(cp.squadrons)
random.shuffle(random_squadron_list) random.shuffle(random_squadron_list)
# Then plan transports, AEWC and tankers
for squadron in random_squadron_list: for squadron in random_squadron_list:
# Intentionally don't spawn anything at OffMapSpawns in Pretense # Intentionally don't spawn anything at OffMapSpawns in Pretense
if isinstance(squadron.location, OffMapSpawn): if isinstance(squadron.location, OffMapSpawn):
@@ -291,14 +327,6 @@ class PretenseAircraftGenerator:
if cp.coalition != squadron.coalition: if cp.coalition != squadron.coalition:
continue continue
squadron.owned_aircraft += (
self.game.settings.pretense_ai_aircraft_per_flight
)
squadron.untasked_aircraft += (
self.game.settings.pretense_ai_aircraft_per_flight
)
squadron.populate_for_turn_0(False)
package = Package(cp, squadron.flight_db, auto_asap=False)
mission_types = squadron.auto_assignable_mission_types mission_types = squadron.auto_assignable_mission_types
aircraft_per_flight = 1 aircraft_per_flight = 1
if squadron.aircraft.helicopter and ( if squadron.aircraft.helicopter and (
@@ -311,52 +339,6 @@ class PretenseAircraftGenerator:
or FlightType.AIR_ASSAULT in mission_types or FlightType.AIR_ASSAULT in mission_types
): ):
flight_type = FlightType.TRANSPORT flight_type = FlightType.TRANSPORT
elif (
FlightType.SEAD in mission_types
or FlightType.SEAD_SWEEP in mission_types
or FlightType.SEAD_ESCORT in mission_types
) and num_of_sead < self.game.settings.pretense_sead_flights_per_cp:
flight_type = FlightType.SEAD
num_of_sead += 1
aircraft_per_flight = self.game.settings.pretense_ai_aircraft_per_flight
elif (
FlightType.DEAD in mission_types
and num_of_sead < self.game.settings.pretense_sead_flights_per_cp
):
flight_type = FlightType.DEAD
num_of_sead += 1
aircraft_per_flight = self.game.settings.pretense_ai_aircraft_per_flight
elif (
(squadron.aircraft.helicopter and (FlightType.ESCORT in mission_types))
or (FlightType.CAS in mission_types)
and num_of_cas < self.game.settings.pretense_cas_flights_per_cp
):
flight_type = FlightType.CAS
num_of_cas += 1
aircraft_per_flight = self.game.settings.pretense_ai_aircraft_per_flight
elif (
FlightType.BAI in mission_types
) and num_of_bai < self.game.settings.pretense_bai_flights_per_cp:
flight_type = FlightType.BAI
num_of_bai += 1
aircraft_per_flight = self.game.settings.pretense_ai_aircraft_per_flight
elif (
FlightType.STRIKE in mission_types
or FlightType.OCA_RUNWAY in mission_types
or FlightType.OCA_AIRCRAFT in mission_types
) and num_of_strike < self.game.settings.pretense_strike_flights_per_cp:
flight_type = FlightType.STRIKE
num_of_strike += 1
aircraft_per_flight = self.game.settings.pretense_ai_aircraft_per_flight
elif (
FlightType.BARCAP in mission_types
or FlightType.TARCAP in mission_types
or FlightType.ESCORT in mission_types
or FlightType.INTERCEPTION in mission_types
) and num_of_cap < self.game.settings.pretense_barcap_flights_per_cp:
flight_type = FlightType.BARCAP
num_of_cap += 1
aircraft_per_flight = self.game.settings.pretense_ai_aircraft_per_flight
elif FlightType.AEWC in mission_types: elif FlightType.AEWC in mission_types:
flight_type = FlightType.AEWC flight_type = FlightType.AEWC
aircraft_per_flight = PRETENSE_AI_AWACS_PER_FLIGHT aircraft_per_flight = PRETENSE_AI_AWACS_PER_FLIGHT
@@ -366,37 +348,181 @@ class PretenseAircraftGenerator:
else: else:
continue continue
if flight_type == FlightType.TRANSPORT: self.generate_pretense_flight(
flight = Flight( ato, cp, squadron, aircraft_per_flight, flight_type
package,
squadron,
aircraft_per_flight,
FlightType.PRETENSE_CARGO,
StartType.IN_FLIGHT,
divert=cp,
)
package.add_flight(flight)
flight.state = Navigating(flight, self.game.settings, waypoint_index=1)
else:
flight = Flight(
package,
squadron,
aircraft_per_flight,
flight_type,
StartType.COLD,
divert=cp,
)
package.add_flight(flight)
flight.state = WaitingForStart(
flight, self.game.settings, self.game.conditions.start_time
)
print(
f"Generated flight for {flight_type} flying {squadron.aircraft.display_name} at {squadron.location.name}"
) )
ato.add_package(package) # Then plan SEAD and DEAD, if capable
if sead_capable_cp:
while num_of_sead < self.game.settings.pretense_sead_flights_per_cp:
for squadron in random_squadron_list:
# Intentionally don't spawn anything at OffMapSpawns in Pretense
if isinstance(squadron.location, OffMapSpawn):
continue
if cp.coalition != squadron.coalition:
continue
mission_types = squadron.auto_assignable_mission_types
if (
(
FlightType.SEAD in mission_types
or FlightType.SEAD_SWEEP in mission_types
or FlightType.SEAD_ESCORT in mission_types
)
and num_of_sead
< self.game.settings.pretense_sead_flights_per_cp
):
flight_type = FlightType.SEAD
num_of_sead += 1
aircraft_per_flight = (
self.game.settings.pretense_ai_aircraft_per_flight
)
elif (
FlightType.DEAD in mission_types
and num_of_sead
< self.game.settings.pretense_sead_flights_per_cp
):
flight_type = FlightType.DEAD
num_of_sead += 1
aircraft_per_flight = (
self.game.settings.pretense_ai_aircraft_per_flight
)
else:
continue
self.generate_pretense_flight(
ato, cp, squadron, aircraft_per_flight, flight_type
)
# Then plan Strike, if capable
if strike_capable_cp:
while num_of_strike < self.game.settings.pretense_strike_flights_per_cp:
for squadron in random_squadron_list:
# Intentionally don't spawn anything at OffMapSpawns in Pretense
if isinstance(squadron.location, OffMapSpawn):
continue
if cp.coalition != squadron.coalition:
continue
mission_types = squadron.auto_assignable_mission_types
for task in strike_tasks:
if task in mission_types and not squadron.aircraft.helicopter:
flight_type = FlightType.STRIKE
num_of_strike += 1
aircraft_per_flight = (
self.game.settings.pretense_ai_aircraft_per_flight
)
self.generate_pretense_flight(
ato, cp, squadron, aircraft_per_flight, flight_type
)
break
# Then plan air-to-air, if capable
if patrol_capable_cp:
while num_of_cap < self.game.settings.pretense_barcap_flights_per_cp:
for squadron in random_squadron_list:
# Intentionally don't spawn anything at OffMapSpawns in Pretense
if isinstance(squadron.location, OffMapSpawn):
continue
if cp.coalition != squadron.coalition:
continue
mission_types = squadron.auto_assignable_mission_types
for task in patrol_tasks:
if task in mission_types and not squadron.aircraft.helicopter:
flight_type = FlightType.BARCAP
num_of_cap += 1
aircraft_per_flight = (
self.game.settings.pretense_ai_aircraft_per_flight
)
self.generate_pretense_flight(
ato, cp, squadron, aircraft_per_flight, flight_type
)
break
# Then plan CAS, if capable
if cas_capable_cp:
while num_of_cas < self.game.settings.pretense_cas_flights_per_cp:
for squadron in random_squadron_list:
# Intentionally don't spawn anything at OffMapSpawns in Pretense
if isinstance(squadron.location, OffMapSpawn):
continue
if cp.coalition != squadron.coalition:
continue
mission_types = squadron.auto_assignable_mission_types
if (
squadron.aircraft.helicopter
and (FlightType.ESCORT in mission_types)
) or (FlightType.CAS in mission_types):
flight_type = FlightType.CAS
num_of_cas += 1
aircraft_per_flight = (
self.game.settings.pretense_ai_aircraft_per_flight
)
self.generate_pretense_flight(
ato, cp, squadron, aircraft_per_flight, flight_type
)
# And finally, plan BAI, if capable
if bai_capable_cp:
while num_of_bai < self.game.settings.pretense_bai_flights_per_cp:
for squadron in random_squadron_list:
# Intentionally don't spawn anything at OffMapSpawns in Pretense
if isinstance(squadron.location, OffMapSpawn):
continue
if cp.coalition != squadron.coalition:
continue
mission_types = squadron.auto_assignable_mission_types
if FlightType.BAI in mission_types:
flight_type = FlightType.BAI
num_of_bai += 1
aircraft_per_flight = (
self.game.settings.pretense_ai_aircraft_per_flight
)
self.generate_pretense_flight(
ato, cp, squadron, aircraft_per_flight, flight_type
)
return return
def generate_pretense_flight(
self,
ato: AirTaskingOrder,
cp: ControlPoint,
squadron: Squadron,
aircraft_per_flight: int,
flight_type: FlightType,
) -> None:
squadron.owned_aircraft += self.game.settings.pretense_ai_aircraft_per_flight
squadron.untasked_aircraft += self.game.settings.pretense_ai_aircraft_per_flight
squadron.populate_for_turn_0(False)
package = Package(cp, squadron.flight_db, auto_asap=False)
if flight_type == FlightType.TRANSPORT:
flight = Flight(
package,
squadron,
aircraft_per_flight,
FlightType.PRETENSE_CARGO,
StartType.IN_FLIGHT,
divert=cp,
)
package.add_flight(flight)
flight.state = Navigating(flight, self.game.settings, waypoint_index=1)
else:
flight = Flight(
package,
squadron,
aircraft_per_flight,
flight_type,
StartType.COLD,
divert=cp,
)
package.add_flight(flight)
flight.state = WaitingForStart(
flight, self.game.settings, self.game.conditions.start_time
)
print(
f"Generated flight for {flight_type} flying {squadron.aircraft.display_name} at {squadron.location.name}"
)
ato.add_package(package)
def generate_pretense_aircraft_for_other_side( def generate_pretense_aircraft_for_other_side(
self, cp: ControlPoint, coalition: Coalition, ato: AirTaskingOrder self, cp: ControlPoint, coalition: Coalition, ato: AirTaskingOrder
) -> None: ) -> None:

View File

@@ -219,13 +219,6 @@ class ProcurementAi:
budget, fulfilled = self.fulfill_aircraft_request( budget, fulfilled = self.fulfill_aircraft_request(
squadrons, request.number, budget squadrons, request.number, budget
) )
if not fulfilled:
# The request was not fulfilled because we could not afford any suitable
# aircraft. Rather than continuing, which could proceed to buy tons of
# cheap escorts that will never allow us to plan a strike package, stop
# buying so we can save the budget until a turn where we *can* afford to
# fill the package.
break
return budget return budget
@property @property

View File

@@ -2,6 +2,7 @@ import time
from collections.abc import Iterator from collections.abc import Iterator
from contextlib import contextmanager from contextlib import contextmanager
from threading import Thread from threading import Thread
from typing import Optional
import uvicorn import uvicorn
from uvicorn import Config from uvicorn import Config
@@ -13,12 +14,13 @@ from game.sim import GameUpdateEvents
class Server(uvicorn.Server): class Server(uvicorn.Server):
def __init__(self) -> None: def __init__(self, port: Optional[int]) -> None:
settings = ServerSettings.get(port)
super().__init__( super().__init__(
Config( Config(
app=app, app=app,
host=ServerSettings.get().server_bind_address, host=settings.server_bind_address,
port=ServerSettings.get().server_port, port=settings.server_port,
# Configured explicitly with default_logging.yaml or logging.yaml. # Configured explicitly with default_logging.yaml or logging.yaml.
log_config=None, log_config=None,
) )

View File

@@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from functools import lru_cache from functools import lru_cache
from typing import Optional
from pydantic_settings import BaseSettings from pydantic_settings import BaseSettings
@@ -30,5 +31,5 @@ class ServerSettings(BaseSettings):
@classmethod @classmethod
@lru_cache @lru_cache
def get(cls) -> ServerSettings: def get(cls, port: Optional[int] = server_port) -> ServerSettings:
return cls() return cls(server_port=port)

View File

@@ -193,11 +193,12 @@ class Settings:
default=False, default=False,
detail=( detail=(
"If checked, squadrons with a primary task matching the mission will be " "If checked, squadrons with a primary task matching the mission will be "
"preferred even if there is a closer squadron capable of the mission as a" "preferred even if there is a closer squadron capable of the mission as a "
"secondary task. Expect longer flights, but squadrons will be more often " "secondary task. Expect longer flights, but squadrons will be more often "
"assigned to their primary task." "assigned to their primary task."
), ),
) )
# CAMPAIGN DOCTRINE
autoplan_tankers_for_strike: bool = boolean_option( autoplan_tankers_for_strike: bool = boolean_option(
"Auto-planner plans refueling flights for Strike packages", "Auto-planner plans refueling flights for Strike packages",
page=CAMPAIGN_DOCTRINE_PAGE, page=CAMPAIGN_DOCTRINE_PAGE,
@@ -283,6 +284,23 @@ class Settings:
"setting to avoid the AI flying into the terrain." "setting to avoid the AI flying into the terrain."
), ),
) )
atflir_autoswap: bool = boolean_option(
"Auto-swap ATFLIR to LITENING",
page=CAMPAIGN_DOCTRINE_PAGE,
section=GENERAL_SECTION,
default=True,
detail=(
"Automatically swaps ATFLIR to LITENING pod for newly generated land-based F-18 flights "
"without having to change the payload. <u>Takes effect after current turn!</u>"
),
)
ai_jettison_empty_tanks: bool = boolean_option(
"Enable AI empty fuel tank jettison",
page=CAMPAIGN_DOCTRINE_PAGE,
section=GENERAL_SECTION,
default=False,
detail=("AI will jettison their fuel tanks as soon as they're empty."),
)
airbase_threat_range: int = bounded_int_option( airbase_threat_range: int = bounded_int_option(
"Airbase threat range (nmi)", "Airbase threat range (nmi)",
page=CAMPAIGN_DOCTRINE_PAGE, page=CAMPAIGN_DOCTRINE_PAGE,
@@ -291,7 +309,7 @@ class Settings:
min=0, min=0,
max=300, max=300,
detail=( detail=(
"Will impact both defensive (BARCAP) and offensive flights. Also has a performance impact," "Will impact both defensive (BARCAP) and offensive flights. Also has a performance impact, "
"lower threat range generally means less BARCAPs are planned." "lower threat range generally means less BARCAPs are planned."
), ),
) )
@@ -339,7 +357,7 @@ class Settings:
min=0, min=0,
max=300, max=300,
detail=( detail=(
"How far, at minimum, will AEW&C racetracks be planned" "How far, at minimum, will AEW&C racetracks be planned "
"to known threat zones." "to known threat zones."
), ),
) )
@@ -375,7 +393,7 @@ class Settings:
default=True, default=True,
detail=( detail=(
"If set, squadrons will be limited to a maximum number of pilots and dead " "If set, squadrons will be limited to a maximum number of pilots and dead "
"pilots will replenish at a fixed rate, each defined with the settings" "pilots will replenish at a fixed rate, each defined with the settings "
"below. Auto-purchase may buy aircraft for which there are no pilots" "below. Auto-purchase may buy aircraft for which there are no pilots"
"available, so this feature is still a work-in-progress." "available, so this feature is still a work-in-progress."
), ),
@@ -573,7 +591,7 @@ class Settings:
default=35, default=35,
min=0, min=0,
max=100, max=100,
detail="See 2-ship weight factor (WF2)", detail="See 2-ship weight factor (WF3)",
) )
fpa_4ship_weight: int = bounded_int_option( fpa_4ship_weight: int = bounded_int_option(
"4-ship weight factor (WF4)", "4-ship weight factor (WF4)",
@@ -582,7 +600,7 @@ class Settings:
default=15, default=15,
min=0, min=0,
max=100, max=100,
detail="See 2-ship weight factor (WF2)", detail="See 2-ship weight factor (WF4)",
) )
# Mission Generator # Mission Generator
@@ -675,16 +693,6 @@ class Settings:
"targets available for OCA/Aircraft missions." "targets available for OCA/Aircraft missions."
), ),
) )
atflir_autoswap: bool = boolean_option(
"Auto-swap ATFLIR to LITENING",
MISSION_GENERATOR_PAGE,
GAMEPLAY_SECTION,
default=True,
detail=(
"Automatically swaps ATFLIR to LITENING pod for newly generated land-based F-18 flights "
"without having to change the payload. <u>Takes effect after current turn!</u>"
),
)
default_start_type: StartType = choices_option( default_start_type: StartType = choices_option(
"Default start type for AI aircraft", "Default start type for AI aircraft",
page=MISSION_GENERATOR_PAGE, page=MISSION_GENERATOR_PAGE,
@@ -777,7 +785,7 @@ class Settings:
GAMEPLAY_SECTION, GAMEPLAY_SECTION,
default=False, default=False,
detail=( detail=(
"If enabled, AI can use roadbases or airbases which only have ground spawns." "If enabled, AI can use roadbases or airbases which only have ground spawns. "
"AI will always air-start from these bases (due to DCS limitation)." "AI will always air-start from these bases (due to DCS limitation)."
), ),
) )
@@ -787,7 +795,7 @@ class Settings:
GAMEPLAY_SECTION, GAMEPLAY_SECTION,
default=True, default=True,
detail=( detail=(
"Can be used to remove lightposts and other obstacles from roadbase runways." "Can be used to remove lightposts and other obstacles from roadbase runways. "
"Might not work in DCS multiplayer." "Might not work in DCS multiplayer."
), ),
) )

View File

@@ -51,6 +51,7 @@ class AirWing:
size: int, size: int,
heli: bool, heli: bool,
this_turn: bool, this_turn: bool,
preferred_type: Optional[AircraftType] = None,
) -> list[Squadron]: ) -> list[Squadron]:
airfield_cache = ObjectiveDistanceCache.get_closest_airfields(location) airfield_cache = ObjectiveDistanceCache.get_closest_airfields(location)
best_aircraft = AircraftType.priority_list_for_task(task) best_aircraft = AircraftType.priority_list_for_task(task)
@@ -59,7 +60,13 @@ class AirWing:
if control_point.captured != self.player: if control_point.captured != self.player:
continue continue
capable_at_base = [] capable_at_base = []
for squadron in control_point.squadrons: squadrons = [
s
for s in control_point.squadrons
if not preferred_type
or s.aircraft.variant_id == preferred_type.variant_id
]
for squadron in squadrons:
if squadron.can_auto_assign_mission( if squadron.can_auto_assign_mission(
location, task, size, heli, this_turn location, task, size, heli, this_turn
): ):
@@ -92,8 +99,11 @@ class AirWing:
size: int, size: int,
heli: bool, heli: bool,
this_turn: bool, this_turn: bool,
preferred_type: Optional[AircraftType] = None,
) -> Optional[Squadron]: ) -> Optional[Squadron]:
for squadron in self.best_squadrons_for(location, task, size, heli, this_turn): for squadron in self.best_squadrons_for(
location, task, size, heli, this_turn, preferred_type
):
return squadron return squadron
return None return None

View File

@@ -120,20 +120,27 @@ class ConflictTheater:
) )
return new_point return new_point
def control_points_for(self, player: bool) -> Iterator[ControlPoint]: def control_points_for(
self, player: bool, state_check: bool = False
) -> Iterator[ControlPoint]:
for point in self.controlpoints: for point in self.controlpoints:
if point.captured == player: if point.captured == player:
yield point if not state_check:
yield point
elif point.is_carrier and point.runway_is_operational():
yield point
elif not point.is_carrier:
yield point
def player_points(self) -> List[ControlPoint]: def player_points(self, state_check: bool = False) -> List[ControlPoint]:
return list(self.control_points_for(player=True)) return list(self.control_points_for(player=True, state_check=state_check))
def conflicts(self) -> Iterator[FrontLine]: def conflicts(self) -> Iterator[FrontLine]:
for cp in self.player_points(): for cp in self.player_points():
yield from cp.front_lines.values() yield from cp.front_lines.values()
def enemy_points(self) -> List[ControlPoint]: def enemy_points(self, state_check: bool = False) -> List[ControlPoint]:
return list(self.control_points_for(player=False)) return list(self.control_points_for(player=False, state_check=state_check))
def closest_control_point( def closest_control_point(
self, point: Point, allow_naval: bool = False self, point: Point, allow_naval: bool = False

View File

@@ -321,6 +321,13 @@ class AirliftPlanner:
if self.package.flights: if self.package.flights:
self.package.set_tot_asap(now) self.package.set_tot_asap(now)
self.game.ato_for(self.for_player).add_package(self.package) self.game.ato_for(self.for_player).add_package(self.package)
from game.server import EventStream
from game.sim import GameUpdateEvents
events = GameUpdateEvents()
for f in self.package.flights:
events = events.new_flight(f)
EventStream.put_nowait(events)
def create_airlift_flight(self, squadron: Squadron) -> int: def create_airlift_flight(self, squadron: Squadron) -> int:
available_aircraft = squadron.untasked_aircraft available_aircraft = squadron.untasked_aircraft
@@ -606,6 +613,8 @@ class PendingTransfers:
== TransitConnection.Shipping == TransitConnection.Shipping
): ):
return self.cargo_ships.add(transfer, next_stop) return self.cargo_ships.add(transfer, next_stop)
else:
next_stop = transfer.destination
AirliftPlanner(self.game, transfer, next_stop).create_package_for_airlift(now) AirliftPlanner(self.game, transfer, next_stop).create_package_for_airlift(now)
def new_transfer(self, transfer: TransferOrder, now: datetime) -> None: def new_transfer(self, transfer: TransferOrder, now: datetime) -> None:

View File

@@ -11,6 +11,8 @@ from game import persistency
global __dcs_saved_game_directory global __dcs_saved_game_directory
global __dcs_installation_directory global __dcs_installation_directory
global __last_save_file global __last_save_file
global __prefer_liberation_payloads
global __server_port
USER_PATH = Path(os.environ["LOCALAPPDATA"]) / "DCSRetribution" USER_PATH = Path(os.environ["LOCALAPPDATA"]) / "DCSRetribution"
@@ -23,6 +25,8 @@ def init():
global __dcs_installation_directory global __dcs_installation_directory
global __last_save_file global __last_save_file
global __ignore_empty_install_directory global __ignore_empty_install_directory
global __prefer_liberation_payloads
global __server_port
if PREFERENCES_PATH.exists(): if PREFERENCES_PATH.exists():
try: try:
@@ -35,16 +39,24 @@ def init():
__ignore_empty_install_directory = pref_data.get( __ignore_empty_install_directory = pref_data.get(
"ignore_empty_install_directory", False "ignore_empty_install_directory", False
) )
__prefer_liberation_payloads = pref_data.get(
"prefer_liberation_payloads", False
)
__server_port = pref_data.get("server_port", 16880)
is_first_start = False is_first_start = False
except (KeyError, json.JSONDecodeError): except (KeyError, json.JSONDecodeError):
__dcs_saved_game_directory = "" __dcs_saved_game_directory = ""
__dcs_installation_directory = "" __dcs_installation_directory = ""
__last_save_file = "" __last_save_file = ""
__ignore_empty_install_directory = False __ignore_empty_install_directory = False
__prefer_liberation_payloads = False
__server_port = 16880
is_first_start = True is_first_start = True
else: else:
__last_save_file = "" __last_save_file = ""
__ignore_empty_install_directory = False __ignore_empty_install_directory = False
__prefer_liberation_payloads = False
__server_port = 16880
try: try:
__dcs_saved_game_directory = ( __dcs_saved_game_directory = (
dcs.installation.get_dcs_saved_games_directory() dcs.installation.get_dcs_saved_games_directory()
@@ -61,16 +73,22 @@ def init():
__dcs_installation_directory = "" __dcs_installation_directory = ""
is_first_start = True is_first_start = True
persistency.setup(__dcs_saved_game_directory) persistency.setup(
__dcs_saved_game_directory, __prefer_liberation_payloads, __server_port
)
return is_first_start return is_first_start
def setup(saved_game_dir, install_dir): def setup(saved_game_dir, install_dir, prefer_liberation_payloads, port):
global __dcs_saved_game_directory global __dcs_saved_game_directory
global __dcs_installation_directory global __dcs_installation_directory
global __prefer_liberation_payloads
global __server_port
__dcs_saved_game_directory = saved_game_dir __dcs_saved_game_directory = saved_game_dir
__dcs_installation_directory = install_dir __dcs_installation_directory = install_dir
persistency.setup(__dcs_saved_game_directory) __prefer_liberation_payloads = prefer_liberation_payloads
__server_port = port
persistency.setup(saved_game_dir, prefer_liberation_payloads, port)
def setup_last_save_file(last_save_file): def setup_last_save_file(last_save_file):
@@ -83,11 +101,14 @@ def save_config():
global __dcs_installation_directory global __dcs_installation_directory
global __last_save_file global __last_save_file
global __ignore_empty_install_directory global __ignore_empty_install_directory
global __server_port
pref_data = { pref_data = {
"saved_game_dir": __dcs_saved_game_directory, "saved_game_dir": __dcs_saved_game_directory,
"dcs_install_dir": __dcs_installation_directory, "dcs_install_dir": __dcs_installation_directory,
"last_save_file": __last_save_file, "last_save_file": __last_save_file,
"ignore_empty_install_directory": __ignore_empty_install_directory, "ignore_empty_install_directory": __ignore_empty_install_directory,
"prefer_liberation_payloads": __prefer_liberation_payloads,
"server_port": __server_port,
} }
PREFERENCES_PATH.parent.mkdir(exist_ok=True, parents=True) PREFERENCES_PATH.parent.mkdir(exist_ok=True, parents=True)
with PREFERENCES_PATH.open("w") as prefs: with PREFERENCES_PATH.open("w") as prefs:
@@ -104,6 +125,16 @@ def get_saved_game_dir():
return __dcs_saved_game_directory return __dcs_saved_game_directory
def prefer_liberation_payloads():
global __prefer_liberation_payloads
return __prefer_liberation_payloads
def server_port():
global __server_port
return __server_port
def ignore_empty_install_directory(): def ignore_empty_install_directory():
global __ignore_empty_install_directory global __ignore_empty_install_directory
return __ignore_empty_install_directory return __ignore_empty_install_directory

View File

@@ -61,18 +61,6 @@ def inject_custom_payloads(user_path: Path) -> None:
PayloadDirectories.set_preferred(user_path / "MissionEditor" / "UnitPayloads") PayloadDirectories.set_preferred(user_path / "MissionEditor" / "UnitPayloads")
def inject_mod_payloads(mod_path: Path) -> None:
if mod_path.exists():
payloads = mod_path
else:
raise RuntimeError(
f"Could not find mod payloads at {mod_path}."
f"Aircraft will have no payloads."
)
# We configure these as preferred so the mod's loadouts override the stock ones.
PayloadDirectories.set_preferred(payloads)
def on_game_load(game: Optional[Game]) -> None: def on_game_load(game: Optional[Game]) -> None:
EventStream.drain() EventStream.drain()
EventStream.put_nowait(GameUpdateEvents().game_loaded(game)) EventStream.put_nowait(GameUpdateEvents().game_loaded(game))
@@ -454,7 +442,8 @@ def main():
dump_task_priorities() dump_task_priorities()
return return
with Server().run_in_thread(): liberation_install.init()
with Server(liberation_install.server_port()).run_in_thread():
run_ui(game, UiFlags(args.dev, args.show_sim_speed_controls)) run_ui(game, UiFlags(args.dev, args.show_sim_speed_controls))

View File

@@ -166,6 +166,8 @@ class QTopPanel(QFrame):
with logged_duration("Skipping turn"): with logged_duration("Skipping turn"):
self.game.pass_turn(no_action=True) self.game.pass_turn(no_action=True)
GameUpdateSignal.get_instance().updateGame(self.game) GameUpdateSignal.get_instance().updateGame(self.game)
state = self.game_model.game.check_win_loss()
GameUpdateSignal.get_instance().gameStateChanged(state)
self.proceedButton.setEnabled(True) self.proceedButton.setEnabled(True)
def negative_start_packages(self, now: datetime) -> List[Package]: def negative_start_packages(self, now: datetime) -> List[Package]:

View File

@@ -8,6 +8,7 @@ from PySide6.QtWebEngineCore import QWebEnginePage, QWebEngineSettings
from PySide6.QtWebEngineWidgets import QWebEngineView from PySide6.QtWebEngineWidgets import QWebEngineView
from game.server.settings import ServerSettings from game.server.settings import ServerSettings
from qt_ui.liberation_install import server_port
from qt_ui.models import GameModel from qt_ui.models import GameModel
@@ -44,7 +45,7 @@ class QLiberationMap(QWebEngineView):
url = QUrl("http://localhost:3000") url = QUrl("http://localhost:3000")
else: else:
url = QUrl.fromLocalFile(str(Path("client/build/index.html").resolve())) url = QUrl.fromLocalFile(str(Path("client/build/index.html").resolve()))
server_settings = ServerSettings.get() server_settings = ServerSettings.get(server_port())
host = server_settings.server_bind_address host = server_settings.server_bind_address
if host.startswith("::"): if host.startswith("::"):
host = f"[{host}]" host = f"[{host}]"

View File

@@ -19,6 +19,8 @@ from PySide6.QtWidgets import (
) )
from game.ato.flight import Flight from game.ato.flight import Flight
from game.server import EventStream
from game.sim import GameUpdateEvents
from game.squadrons import Squadron from game.squadrons import Squadron
from game.theater import ConflictTheater from game.theater import ConflictTheater
from qt_ui.delegates import TwoColumnRowDelegate from qt_ui.delegates import TwoColumnRowDelegate
@@ -258,6 +260,9 @@ class AirWingTabs(QTabWidget):
def open_awcd(self, gm: GameModel): def open_awcd(self, gm: GameModel):
AirWingConfigurationDialog(gm.game, True, self).exec_() AirWingConfigurationDialog(gm.game, True, self).exec_()
events = GameUpdateEvents().begin_new_turn()
EventStream.put_nowait(events)
gm.ato_model.on_sim_update(events)
class AirWingDialog(QDialog): class AirWingDialog(QDialog):

View File

@@ -569,7 +569,7 @@ class QLiberationWindow(QMainWindow):
LAYOUTS.import_templates() LAYOUTS.import_templates()
def showLogsDialog(self): def showLogsDialog(self):
self.dialog = QLogsWindow() self.dialog = QLogsWindow(self)
self.dialog.show() self.dialog.show()
def onDebriefing(self, debrief: Debriefing): def onDebriefing(self, debrief: Debriefing):

View File

@@ -8,6 +8,7 @@ from PySide6.QtWidgets import (
QPlainTextEdit, QPlainTextEdit,
QVBoxLayout, QVBoxLayout,
QPushButton, QPushButton,
QWidget,
) )
from qt_ui.logging_handler import HookableInMemoryHandler from qt_ui.logging_handler import HookableInMemoryHandler
@@ -21,8 +22,8 @@ class QLogsWindow(QDialog):
clear_button: QPushButton clear_button: QPushButton
_logging_handler: typing.Optional[HookableInMemoryHandler] _logging_handler: typing.Optional[HookableInMemoryHandler]
def __init__(self): def __init__(self, parent: QWidget):
super().__init__() super().__init__(parent)
self.setWindowTitle("Logs") self.setWindowTitle("Logs")
self.setMinimumSize(400, 100) self.setMinimumSize(400, 100)

View File

@@ -47,76 +47,100 @@ class QAutoCreateDialog(QDialog):
hbox = QHBoxLayout() hbox = QHBoxLayout()
self.primary_combobox = QComboBox() self.primary_combobox = QComboBox()
self.primary_combobox.setFixedWidth(100)
self.primary_count = _spinbox_template() self.primary_count = _spinbox_template()
self.primary_type = QComboBox()
nr_targets = len(self.package.target.strike_targets) nr_targets = len(self.package.target.strike_targets)
count = max(1, min(4, nr_targets // 2) + nr_targets % 1) if nr_targets else 4 count = max(1, min(4, nr_targets // 2) + nr_targets % 1) if nr_targets else 4
self.primary_count.setValue(count) self.primary_count.setValue(count)
hbox.addWidget(self.primary_combobox) hbox.addWidget(self.primary_combobox)
hbox.addWidget(self.primary_count) hbox.addWidget(self.primary_count)
hbox.addWidget(self.primary_type)
self.layout.addLayout(hbox) self.layout.addLayout(hbox)
self.checkboxes = {} self.checkboxes = {}
hbox = QHBoxLayout() hbox = QHBoxLayout()
self.tarcap = QCheckBox() self.tarcap = self._create_checkbox("TARCAP")
self.tarcap.setText("TARCAP")
self.tarcap_count = _spinbox_template() self.tarcap_count = _spinbox_template()
hbox.addWidget(self.tarcap) hbox.addWidget(self.tarcap)
hbox.addWidget(self.tarcap_count) hbox.addWidget(self.tarcap_count)
self.tarcap_type = self._create_type_selector(FlightType.TARCAP)
hbox.addWidget(self.tarcap_type)
self.layout.addLayout(hbox) self.layout.addLayout(hbox)
self.checkboxes[self.tarcap] = (FlightType.TARCAP, self.tarcap_count) self.checkboxes[self.tarcap] = (
FlightType.TARCAP,
self.tarcap_count,
self.tarcap_type,
)
hbox = QHBoxLayout() hbox = QHBoxLayout()
self.escort = QCheckBox() self.escort = self._create_checkbox("Escort")
self.escort.setText("Escort")
self.escort_count = _spinbox_template() self.escort_count = _spinbox_template()
hbox.addWidget(self.escort) hbox.addWidget(self.escort)
hbox.addWidget(self.escort_count) hbox.addWidget(self.escort_count)
self.escort_type = self._create_type_selector(FlightType.ESCORT)
hbox.addWidget(self.escort_type)
self.layout.addLayout(hbox) self.layout.addLayout(hbox)
self.checkboxes[self.escort] = (FlightType.ESCORT, self.escort_count) self.checkboxes[self.escort] = (
FlightType.ESCORT,
self.escort_count,
self.escort_type,
)
hbox = QHBoxLayout() hbox = QHBoxLayout()
self.sead_escort = QCheckBox() self.sead_escort = self._create_checkbox("SEAD Escort")
self.sead_escort.setText("SEAD Escort")
self.sead_escort_count = _spinbox_template() self.sead_escort_count = _spinbox_template()
hbox.addWidget(self.sead_escort) hbox.addWidget(self.sead_escort)
hbox.addWidget(self.sead_escort_count) hbox.addWidget(self.sead_escort_count)
self.sead_escort_type = self._create_type_selector(FlightType.SEAD_ESCORT)
hbox.addWidget(self.sead_escort_type)
self.layout.addLayout(hbox) self.layout.addLayout(hbox)
self.checkboxes[self.sead_escort] = ( self.checkboxes[self.sead_escort] = (
FlightType.SEAD_ESCORT, FlightType.SEAD_ESCORT,
self.sead_escort_count, self.sead_escort_count,
self.sead_escort_type,
) )
hbox = QHBoxLayout() hbox = QHBoxLayout()
self.sead = QCheckBox() self.sead = self._create_checkbox("SEAD")
self.sead.setText("SEAD")
self.sead_count = _spinbox_template() self.sead_count = _spinbox_template()
hbox.addWidget(self.sead) hbox.addWidget(self.sead)
hbox.addWidget(self.sead_count) hbox.addWidget(self.sead_count)
self.sead_type = self._create_type_selector(FlightType.SEAD)
hbox.addWidget(self.sead_type)
self.layout.addLayout(hbox) self.layout.addLayout(hbox)
self.checkboxes[self.sead] = (FlightType.SEAD, self.sead_count) self.checkboxes[self.sead] = (FlightType.SEAD, self.sead_count, self.sead_type)
hbox = QHBoxLayout() hbox = QHBoxLayout()
self.sead_sweep = QCheckBox() self.sead_sweep = self._create_checkbox("SEAD Sweep")
self.sead_sweep.setText("SEAD Sweep")
self.sead_sweep_count = _spinbox_template() self.sead_sweep_count = _spinbox_template()
hbox.addWidget(self.sead_sweep) hbox.addWidget(self.sead_sweep)
hbox.addWidget(self.sead_sweep_count) hbox.addWidget(self.sead_sweep_count)
self.sead_sweep_type = self._create_type_selector(FlightType.SEAD_SWEEP)
hbox.addWidget(self.sead_sweep_type)
self.layout.addLayout(hbox) self.layout.addLayout(hbox)
self.checkboxes[self.sead_sweep] = ( self.checkboxes[self.sead_sweep] = (
FlightType.SEAD_SWEEP, FlightType.SEAD_SWEEP,
self.sead_sweep_count, self.sead_sweep_count,
self.sead_sweep_type,
) )
hbox = QHBoxLayout() hbox = QHBoxLayout()
self.refueling = QCheckBox() self.refueling = self._create_checkbox("Refueling")
self.refueling.setText("Refueling")
self.refueling_count = _spinbox_template() self.refueling_count = _spinbox_template()
self.refueling_count.setValue(1) self.refueling_count.setValue(1)
hbox.addWidget(self.refueling) hbox.addWidget(self.refueling)
hbox.addWidget(self.refueling_count) hbox.addWidget(self.refueling_count)
self.refueling_type = self._create_type_selector(FlightType.REFUELING)
hbox.addWidget(self.refueling_type, 1)
self.layout.addLayout(hbox) self.layout.addLayout(hbox)
self.checkboxes[self.refueling] = (FlightType.REFUELING, self.refueling_count) self.checkboxes[self.refueling] = (
FlightType.REFUELING,
self.refueling_count,
self.refueling_type,
)
self.create_button = QPushButton("Create") self.create_button = QPushButton("Create")
self.create_button.setProperty("style", "start-button") self.create_button.setProperty("style", "start-button")
@@ -139,6 +163,28 @@ class QAutoCreateDialog(QDialog):
if mt in primary_tasks: if mt in primary_tasks:
self.primary_combobox.addItem(mt.value, mt) self.primary_combobox.addItem(mt.value, mt)
self.primary_combobox.setCurrentIndex(0) self.primary_combobox.setCurrentIndex(0)
self._load_aircraft_types()
@staticmethod
def _create_checkbox(label: str) -> QCheckBox:
cb = QCheckBox(label)
cb.setFixedWidth(100)
return cb
def _create_type_selector(self, flight_type: FlightType) -> QComboBox:
airwing = self.game.blue.air_wing
cb = QComboBox()
for ac in airwing.best_available_aircrafts_for(flight_type):
cb.addItem(ac.variant_id, ac)
return cb
def _load_aircraft_types(self):
self.primary_type.clear()
for ac in self.game.blue.air_wing.best_available_aircrafts_for(
self.primary_combobox.currentData()
):
self.primary_type.addItem(ac.variant_id, ac)
self.primary_type.setCurrentIndex(0)
def on_primary_task_changed(self) -> None: def on_primary_task_changed(self) -> None:
disable = self.primary_combobox.currentData() == FlightType.CAS disable = self.primary_combobox.currentData() == FlightType.CAS
@@ -147,15 +193,26 @@ class QAutoCreateDialog(QDialog):
if disable: if disable:
cb.setChecked(False) cb.setChecked(False)
cb.setDisabled(disable) cb.setDisabled(disable)
self._load_aircraft_types()
def on_create_clicked(self) -> None: def on_create_clicked(self) -> None:
pf: List[ProposedFlight] = [] pf: List[ProposedFlight] = []
count = self.primary_count.value() count = self.primary_count.value()
pf.append(ProposedFlight(self.primary_combobox.currentData(), count)) pf.append(
ProposedFlight(
self.primary_combobox.currentData(),
count,
preferred_type=self.primary_type.currentData(),
)
)
for cb in self.checkboxes: for cb in self.checkboxes:
if cb.isChecked(): if cb.isChecked():
type, spinner = self.checkboxes[cb] type, spinner, ac_box = self.checkboxes[cb]
pf.append(ProposedFlight(type, spinner.value())) pf.append(
ProposedFlight(
type, spinner.value(), preferred_type=ac_box.currentData()
)
)
with MultiEventTracer() as tracer: with MultiEventTracer() as tracer:
with tracer.trace(f"Auto-plan package"): with tracer.trace(f"Auto-plan package"):
pm = ProposedMission(self.package.target, pf, asap=True) pm = ProposedMission(self.package.target, pf, asap=True)

View File

@@ -237,11 +237,12 @@ class QPackageDialog(QDialog):
auto_create_dialog = QAutoCreateDialog( auto_create_dialog = QAutoCreateDialog(
self.game, self.package_model, parent=self.window() self.game, self.package_model, parent=self.window()
) )
auto_create_dialog.exec_() if auto_create_dialog.exec_() == QDialog.DialogCode.Accepted:
for f in self.package_model.package.flights: for f in self.package_model.package.flights:
EventStream.put_nowait(GameUpdateEvents().new_flight(f)) EventStream.put_nowait(GameUpdateEvents().new_flight(f))
self.package_model.update_tot() self.package_model.update_tot()
self.package_changed.emit() self.package_changed.emit()
self.auto_create_button.setDisabled(True)
def on_change_name(self) -> None: def on_change_name(self) -> None:
self.package_model.package.custom_name = self.package_name_text.text() self.package_model.package.custom_name = self.package_name_text.text()

View File

@@ -11,6 +11,8 @@ from PySide6.QtWidgets import (
QMessageBox, QMessageBox,
QPushButton, QPushButton,
QVBoxLayout, QVBoxLayout,
QCheckBox,
QSpinBox,
) )
from qt_ui import liberation_install, liberation_theme from qt_ui import liberation_install, liberation_theme
@@ -40,6 +42,14 @@ class QLiberationPreferences(QFrame):
self.themeSelect = QComboBox() self.themeSelect = QComboBox()
[self.themeSelect.addItem(y["themeName"]) for x, y in THEMES.items()] [self.themeSelect.addItem(y["themeName"]) for x, y in THEMES.items()]
preference = liberation_install.prefer_liberation_payloads()
self.prefer_liberation_payloads = preference if preference else False
self.payloads_cb = QCheckBox()
self.payloads_cb.setChecked(self.prefer_liberation_payloads)
self.port = liberation_install.server_port()
self.port_input = QSpinBox()
self.initUi() self.initUi()
def initUi(self): def initUi(self):
@@ -73,6 +83,25 @@ class QLiberationPreferences(QFrame):
layout.addWidget(self.themeSelect, 4, 1, alignment=Qt.AlignmentFlag.AlignRight) layout.addWidget(self.themeSelect, 4, 1, alignment=Qt.AlignmentFlag.AlignRight)
self.themeSelect.setCurrentIndex(get_theme_index()) self.themeSelect.setCurrentIndex(get_theme_index())
layout.addWidget(
QLabel("<strong>Prefer custom Liberation payloads:</strong>"),
5,
0,
alignment=Qt.AlignmentFlag.AlignLeft,
)
layout.addWidget(self.payloads_cb, 5, 1, alignment=Qt.AlignmentFlag.AlignRight)
layout.addWidget(
QLabel("<strong>Server port (restart required):</strong>"),
6,
0,
alignment=Qt.AlignmentFlag.AlignLeft,
)
layout.addWidget(self.port_input, 6, 1, alignment=Qt.AlignmentFlag.AlignRight)
self.port_input.setRange(1, 2**16 - 1)
self.port_input.setValue(self.port)
self.port_input.setStyleSheet("QSpinBox{ width: 50 }")
main_layout.addLayout(layout) main_layout.addLayout(layout)
main_layout.addStretch() main_layout.addStretch()
@@ -98,6 +127,8 @@ class QLiberationPreferences(QFrame):
print("Applying changes") print("Applying changes")
self.saved_game_dir = self.edit_saved_game_dir.text() self.saved_game_dir = self.edit_saved_game_dir.text()
self.dcs_install_dir = self.edit_dcs_install_dir.text() self.dcs_install_dir = self.edit_dcs_install_dir.text()
self.prefer_liberation_payloads = self.payloads_cb.isChecked()
self.port = self.port_input.value()
set_theme_index(self.themeSelect.currentIndex()) set_theme_index(self.themeSelect.currentIndex())
if not os.path.isdir(self.saved_game_dir): if not os.path.isdir(self.saved_game_dir):
@@ -153,7 +184,12 @@ class QLiberationPreferences(QFrame):
error_dialog.exec_() error_dialog.exec_()
return False return False
liberation_install.setup(self.saved_game_dir, self.dcs_install_dir) liberation_install.setup(
self.saved_game_dir,
self.dcs_install_dir,
self.prefer_liberation_payloads,
self.port,
)
liberation_install.save_config() liberation_install.save_config()
liberation_theme.save_theme_config() liberation_theme.save_theme_config()
return True return True

View File

@@ -10,7 +10,7 @@ click==8.1.7
colorama==0.4.6 colorama==0.4.6
distlib==0.3.8 distlib==0.3.8
Faker==22.6.0 Faker==22.6.0
fastapi==0.109.1 fastapi==0.109.2
filelock==3.13.1 filelock==3.13.1
h11==0.14.0 h11==0.14.0
httptools==0.6.1 httptools==0.6.1
@@ -32,15 +32,15 @@ pluggy==1.4.0
pre-commit==3.6.0 pre-commit==3.6.0
pydantic==2.6.0 pydantic==2.6.0
pydantic-settings==2.1.0 pydantic-settings==2.1.0
-e git+https://github.com/dcs-retribution/pydcs@0bcdeecb4bd9032878b4dbf6fedac5a951429e26#egg=pydcs -e git+https://github.com/dcs-retribution/pydcs@353f5b177dd406122a83e8572fd6ca54adf84389#egg=pydcs
pyinstaller==5.13.2 pyinstaller==5.13.2
pyinstaller-hooks-contrib==2024.0 pyinstaller-hooks-contrib==2024.0
pyparsing==3.1.1 pyparsing==3.1.1
pyproj==3.6.1 pyproj==3.6.1
pyshp==2.3.1 pyshp==2.3.1
PySide6==6.6.1 PySide6==6.4.3
PySide6-Addons==6.6.1 PySide6-Addons==6.4.3
PySide6-Essentials==6.6.1 PySide6-Essentials==6.4.3
pytest==8.0.0 pytest==8.0.0
pytest-cov==4.1.0 pytest-cov==4.1.0
python-dateutil==2.8.2 python-dateutil==2.8.2
@@ -48,10 +48,10 @@ python-dotenv==1.0.1
pywin32-ctypes==0.2.2 pywin32-ctypes==0.2.2
PyYAML==6.0.1 PyYAML==6.0.1
Shapely==2.0.2 Shapely==2.0.2
shiboken6==6.6.1 shiboken6==6.4.3
six==1.16.0 six==1.16.0
sniffio==1.3.0 sniffio==1.3.0
starlette==0.35.1 starlette==0.36.3
suntime==1.2.5 suntime==1.2.5
tabulate==0.9.0 tabulate==0.9.0
text-unidecode==1.3 text-unidecode==1.3

View File

@@ -7,7 +7,7 @@ recommended_enemy_faction: China/Argentina Falklands Occupation Force
description: <p>Argentina and China have taken the Falklands by surprise. Currently on the East Coast of the United States for training, an Invicible-class carrier is steaming down to the South Atlantic to retake the islands, with the help of the United States Carrier Group. A beachhead has been established on the small air base of San Julian where the USAF has parked a small number of F-15Es and F-16 to assist. <p>Retake the Falklands, and proceed inland to neutralize the enemy.</p></p><p><b>Author's notes</b><br/>For this campaign, you can use UK Harrier and Apache skins, and Argentine JF-17 and Mirage Skins. Original campaign Gran Polvorin by Fuzzle.</p> description: <p>Argentina and China have taken the Falklands by surprise. Currently on the East Coast of the United States for training, an Invicible-class carrier is steaming down to the South Atlantic to retake the islands, with the help of the United States Carrier Group. A beachhead has been established on the small air base of San Julian where the USAF has parked a small number of F-15Es and F-16 to assist. <p>Retake the Falklands, and proceed inland to neutralize the enemy.</p></p><p><b>Author's notes</b><br/>For this campaign, you can use UK Harrier and Apache skins, and Argentine JF-17 and Mirage Skins. Original campaign Gran Polvorin by Fuzzle.</p>
miz: RetakeTheFalklands.miz miz: RetakeTheFalklands.miz
performance: 2 performance: 2
recommended_start_date: 2005-06-15 recommended_start_date: 2002-12-21
version: "10.7" version: "10.7"
squadrons: squadrons:
# Off-map spawn # Off-map spawn

View File

@@ -1,11 +1,11 @@
--- ---
name: Syria - WRL - Assault on Damascus (v1.1) #1.0 - Original Release / #1.1 - Player F15e added name: Syria - WRL - Assault on Damascus (v1.2) #1.0 - Original Release / #1.1 - Player F15e added / #1.2 - IADS ADDED & Massive Overhaul, Added C130 spawn support at main airbase
theater: Syria theater: Syria
authors: HolyOrangeJuice authors: HolyOrangeJuice
recommended_player_faction: WRL - Task Force Blue recommended_player_faction: WRL - Task Force Blue
recommended_enemy_faction: WRL - Task Force Red recommended_enemy_faction: WRL - Task Force Red
recommended_start_date: 2022-06-04 recommended_start_date: 2022-06-04
description: "<p>This mission was modified by HolyOrangeJuice [OscarJuliet] for the WRL Group. Join us for weekly PVE events. <a style=\"color: white\" href=\"https://werunliberation.com\">werunliberation.com</a></p><p>Original Battle for Golan Heights by Khopa.</p><p>This modified campaign does not represent any historical time period or events. Attack from Ramat-David and eliminate the enemy around Damascus.</p><p>All WRL Campaigns use high budget and high income to focus on the PVE goals to eliminate the enemy. Use lower starting money and income for increased difficulty.</p>" description: "<p>This campaign is the gold standard of WRL campaigns. This campaign will always have the latest retribution additions. Consider this a feature complete campaign as it progresses through updates. Play Battle 4 Gerogia as a beginner mission. Play this one for an advanced experience</p><p>This mission was heavily modified by HolyOrangeJuice [OscarJuliet] for the WRL Group. Join us for weekly PVE events. <a style=\"color: white\" href=\"https://werunliberation.com\">werunliberation.com</a></p><p>Original Battle for Golan Heights by Khopa.</p><p>This modified campaign does not represent any historical time period or events. Attack from Ramat-David and eliminate the enemy around Damascus.</p><p>All WRL Campaigns use high budget and high income to focus on the PVE goals to eliminate the enemy. Use lower starting money and income for increased difficulty.</p>"
miz: WRL_AssaultonDamascus.miz miz: WRL_AssaultonDamascus.miz
performance: 2 performance: 2
version: "10.7" #CTLD Zones Added version: "10.7" #CTLD Zones Added
@@ -13,9 +13,102 @@ recommended_player_money: 5000
recommended_enemy_money: 2000 recommended_enemy_money: 2000
recommended_player_income_multiplier: 5.0 recommended_player_income_multiplier: 5.0
recommended_enemy_income_multiplier: 1.0 recommended_enemy_income_multiplier: 1.0
advanced_iads: false
settings: settings:
max_frontline_width: 30 max_frontline_width: 30
advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers
iads_config:
#REDFOR DEFENSE MARJ AIRBASE AREA
- M-COMMAND-1:
- M-POWER-1
- M-POWER-2
- M-TOWER-1
- M-TOWER-2
- M-EWR-1:
- M-POWER-1
- M-TOWER-1
- M-EWR-2:
- M-POWER-1
- M-TOWER-1
- M-EWR-3:
- M-POWER-2
- M-TOWER-2
- M-SAM-1:
- M-POWER-1
- M-TOWER-1
- M-SAM-2:
- M-POWER-1
- M-TOWER-1
- M-SAM-3:
- M-POWER-2
- M-TOWER-2
- M-SAM-4:
- M-POWER-2
- M-TOWER-2
- M-SAM-5:
- M-POWER-2
- M-TOWER-2
- M-SAM-6:
- M-POWER-2
- M-TOWER-2
#REDFOR DEFENSE DAMASCUS AIRBASE AREA
- D-COMMAND-1:
- D-POWER-1
- D-POWER-2
- D-TOWER-1
- D-TOWER-2
- D-EWR-1:
- D-POWER-1
- D-TOWER-1
- D-EWR-2:
- D-POWER-2
- D-TOWER-2
- D-EWR-3:
- D-POWER-2
- D-TOWER-2
- D-SAM-1:
- D-POWER-1
- D-TOWER-1
- D-SAM-2:
- D-POWER-2
- D-TOWER-2
- D-SAM-3:
- D-POWER-1
- D-TOWER-1
- D-SAM-4:
- D-POWER-2
- D-TOWER-2
#REDFOR DEFENSE AL-DUMAYR AIRBASE AREA
- A-COMMAND-1:
- A-POWER-1
- A-TOWER-1
- A-EWR-1:
- A-POWER-1
- A-TOWER-1
- A-EWR-2:
- A-POWER-1
- A-TOWER-1
- A-SAM-1:
- A-POWER-1
- A-TOWER-1
- A-SAM-2:
- A-POWER-1
- A-TOWER-1
#BLUEFOR RAMAT DEFENSE
- R-COMMAND-1:
- R-POWER-1
- R-TOWER-1
- RAMAT1:
- R-POWER-1
- R-TOWER-1
- RAMAT2:
- R-POWER-1
- R-TOWER-1
- RAMAT3:
- R-POWER-1
- R-TOWER-1
- RAMAT4:
- R-POWER-1
- R-TOWER-1
squadrons: squadrons:
CVN-74 John Stennis: CVN-74 John Stennis:
- primary: BARCAP - primary: BARCAP
@@ -75,7 +168,12 @@ squadrons:
secondary: any secondary: any
aircraft: aircraft:
- F-117A Nighthawk - F-117A Nighthawk
size: 5 size: 8
- primary: BARCAP
secondary: air-to-air
aircraft:
- F-15C Eagle
size: 16
# Ramat-David # Ramat-David
30: 30:
- primary: BAI - primary: BAI
@@ -108,88 +206,103 @@ squadrons:
aircraft: aircraft:
- AV-8B Harrier II Night Attack - AV-8B Harrier II Night Attack
size: 16 size: 16
# Golan South
# Golan South:
# Golan North
Golan North: Golan North:
- primary: BAI - primary: BAI
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- A Company, 1-211th ARB #AH-64D Apache Longbow - A Company, 1-211th ARB #AH-64D Apache Longbow
size: 10 size: 8
- primary: BAI - primary: BAI
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- Mi-24P Hind-F - Mi-24P Hind-F
size: 10 size: 8
- primary: BAI - primary: BAI
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- Ka-50 Hokum III - Ka-50 Hokum III
size: 10 size: 8
- primary: Transport
secondary: air-to-ground
aircraft:
- HMLA-169 (UH-1H) #UH-1H Iroquois
size: 8
# Golan South
Golan South:
- primary: BAI
secondary: air-to-ground
aircraft:
- AH-1W SuperCobra
size: 4
- primary: BAI - primary: BAI
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- SA 342M Gazelle - SA 342M Gazelle
size: 4 size: 8
- primary: Transport - primary: Transport
secondary: any secondary: air-to-ground
aircraft:
- HMLA-169 (UH-1H) #UH-1H Iroquois
size: 4
- primary: Transport
secondary: any
aircraft: aircraft:
- Mi-8MTV2 Hip - Mi-8MTV2 Hip
size: 4 size: 8
# Marj Ruhayyil
23:
- primary: BARCAP
secondary: air-to-air
aircraft:
- MiG-21bis Fishbed-N
size: 16
# Al-Dumayr
9:
- primary: BARCAP
secondary: any
aircraft:
- Su-27 Flanker-B
size: 16
# Khalkhalah
18:
- primary: BARCAP
secondary: any
aircraft:
- MiG-23MLD Flogger-K
size: 16
# Damascus # Damascus
7: 7:
- primary: BARCAP - primary: BARCAP
secondary: any secondary: air-to-air
aircraft: aircraft:
- MiG-29S Fulcrum-C - MiG-29S Fulcrum-C
size: 16 size: 12
- primary: SEAD
secondary: air-to-ground
aircraft:
- Su-34 Fullback
size: 12
- primary: Strike - primary: Strike
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- Su-24M Fencer-D - Su-24M Fencer-D
size: 16 size: 12
- primary: SEAD # Marj Ruhayyil
secondary: air-to-ground # 23:
aircraft: # Al-Dumayr
- Su-25T Frogfoot # 9:
size: 16 # Khalkhalah
# 18:
# MEZZEH
# 25:
# FOB ALPHA
# FOB ALPHA:
# FOB BRAVO
# FOB BRAVO:
# MARJ AS SULTAN SOUTH
# 8:
# MARJ AS SULTAN NORTH
# 22:
# QABR AS SITT
# 29:
ground_forces: ground_forces:
KHALK1: SA-11 M-SAM-1: SA-11
KHALK2: SA-2/S-75 M-SAM-2: SA-11
DAMASCUS1: SA-11 M-SAM-3: SA-2/S-75
DUMAYR1: SA-2/S-75 M-SAM-4: SA-3/S-125
DUMAYR2: SA-2/S-75 M-SAM-5: SA-3/S-125
DUMAYR3: SA-10/S-300PS M-SAM-6: SA-3/S-125
M-SHORAD-1: SA-15 SHORAD
# M-AAA-1:
D-SAM-1: SA-2/S-75
D-SAM-2: SA-2/S-75
D-SAM-3: SA-6
D-SAM-4: SA-3/S-125
D-SHORAD-1: SA-15 SHORAD
# D-AAA-1:
K-SHORAD-1: SA-15 SHORAD
# K-AAA-1:
FOB-SHORAD-1: SA-15 SHORAD
# FOB-AAA-1:
A-SHORAD-1: SA-15 SHORAD
RAMAT1: Patriot RAMAT1: Patriot
RAMAT2: Hawk RAMAT2: Patriot
RAMAT3: Patriot RAMAT3: NASAMS AIM-120C
RAMAT4: NASAMS AIM-120C
GSOUTH1: NASAMS AIM-120C GSOUTH1: NASAMS AIM-120C
GSOUTH2: Hawk GSOUTH2: NASAMS AIM-120C
GNORTH1: NASAMS AIM-120C GNORTH1: NASAMS AIM-120C

View File

@@ -1,28 +1,25 @@
--- ---
name: Syria - WRL - Battle For Syria North (1.0) #1.0 Release with Player F15e name: Syria - WRL - Battle For Syria North (v1.2) #1.2 Complete Mission Overhaul - Frontlines Removed - CTLD or C130s are expected for base capture / Consider victory by destroying all airbases.
theater: Syria theater: Syria
authors: HolyOrangeJuice authors: HolyOrangeJuice
description: "<p>This mission was modified by HolyOrangeJuice [OscarJuliet] for the WRL Group. Original Mission by Sith1144. Join us for weekly PVE events. <a style=\"color: white\" href=\"https://werunliberation.com\">werunliberation.com</a></p><p>This modification of the mission is not meant to represent historical accuracy. An exciting battle on the Northern part of the Syria map.</p><p>All WRL Campaigns use high budget and high income to focus on the PVE goals to eliminate the enemy. Use lower starting money and income for increased difficulty</p>" description: "<p>This mission was heavily modified by HolyOrangeJuice [OscarJuliet] for the WRL Group. Original Mission by Sith1144. Join us for weekly PVE events. <a style=\"color: white\" href=\"https://werunliberation.com\">werunliberation.com</a></p><p>This modification of the mission is not meant to represent historical accuracy. An exciting battle on the Northern part of the Syria map.</p><p>All WRL Campaigns use high budget and high income to focus on the PVE goals to eliminate the enemy. Use lower starting money and income for increased difficulty</p>"
recommended_player_faction: WRL - Task Force Blue recommended_player_faction: WRL - Task Force Blue
recommended_enemy_faction: WRL - Task Force Red recommended_enemy_faction: WRL - Task Force Red
recommended_start_date: 2019-06-04 recommended_start_date: 2019-06-04
miz: WRL_Battle4SyriaNorth.miz miz: WRL_Battle4SyriaNorth.miz
performance: 2 performance: 2
version: "10.7" #No CTLD zones, campaign is too large for CTLD focus version: "10.7" #CTLD ZONES ADDED
recommended_player_money: 5000 recommended_player_money: 5000
recommended_enemy_money: 2000 recommended_enemy_money: 2000
recommended_player_income_multiplier: 5.0 recommended_player_income_multiplier: 5.0
recommended_enemy_income_multiplier: 1.0 recommended_enemy_income_multiplier: 1.0
advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers advanced_iads: true
#IADS: EWR and C2 get power generators. batteries have their own generators.
iads_config: iads_config:
# NATO IADS # NATO IADS
#EWRs
- NATO EWR-1: - NATO EWR-1:
- NATO IADS Command - NATO IADS Command
- NATO EWR: - NATO EWR:
- NATO IADS Command - NATO IADS Command
# SAMs
- NATO SAM: - NATO SAM:
- NATO IADS Command - NATO IADS Command
- NATO SAM-1: - NATO SAM-1:
@@ -39,202 +36,129 @@ iads_config:
- NATO IADS Command - NATO IADS Command
- NATO SAM-7: - NATO SAM-7:
- NATO IADS Command - NATO IADS Command
# Yellow defense zone (Gaziantep-Minakh) #BLUE DEFENSE AREA - HINT: Go after the power stations
#EWRs - B-COMMAND-1:
- YellowEWRN: #mountainrange (north) - B-POWER-1
- YellowPPW - B-TOWER-1
- YellowControlN - B-POWER-2
- YellowEWRS: #mountainrange (center) - B-TOWER-2
- YellowPPW - B-SAM-1:
- YellowControlW - B-POWER-1
- YellowEWRC: # internal - B-TOWER-1
- HamidiyeControl - B-SAM-2:
- GaziantepControl - B-POWER-1
- GaziantepPP - B-TOWER-1
- GaziantepAirControl: - B-SAM-3:
- GaziantepControl - B-POWER-1
- GaziantepPP - B-TOWER-1
# The air defense barrier behind the mountains - B-SAM-4:
- YellowBarrierN: - B-POWER-2
- YellowControlN - B-TOWER-2
- YellowBarrierC1: - B-SAM-5: #SA10
- YellowControlW - B-POWER-2
- YellowBarrierC2: - B-TOWER-2
- YellowControlW - B-EWR-1:
- YellowBarrierS: - B-POWER-1
- YellowControlW - B-TOWER-1
- YellowBarrierAAA: - B-EWR-2:
- YellowControlW - B-POWER-1
# the central long range SAM and its point defenses - B-TOWER-1
- YellowLongRangeSAMPointDefense: #RED DEFENSE AREA - HINT: Go after the power stations
- HamidiyeControl - R-COMMAND-1:
- YellowLongRangeSAM: - R-POWER-1
- HamidiyeControl - R-TOWER-1
- YellowLongRangeSAMAAA: - R-POWER-2
- HamidiyeControl - R-TOWER-2
# the defenses around Gaziantep airfield - R-SAM-1:
- GAZSAMN: - R-POWER-1
- GaziantepControl - R-TOWER-1
- GAZSAMW: - R-SAM-2:
- GaziantepControl - R-POWER-1
# the defenses around Minakh airfield - R-TOWER-1
- MinakhSAM1: - R-SAM-3:
- MinakhControl - R-POWER-1
- MinakhSAM2: - R-TOWER-1
- MinakhControl - R-SAM-4:
#C2 links - R-POWER-1
- YellowControlN: - R-TOWER-1
- HamidiyeControl - R-SAM-5:
- YellowControlW: - R-POWER-1
- HamidiyeControl - R-TOWER-1
- YellowControlN - R-SAM-6:
- YellowZoneCommand: - R-POWER-1
- GaziantepControl - R-TOWER-1
- MinakhControl - R-SAM-7:
- HamidiyeControl - R-POWER-1
- GaziantepPP - R-TOWER-1
- GaziantepAirControl - R-SAM-8:
# Green Defense Zone (HATAY) - R-POWER-2
# EWRs - R-TOWER-2
- CoastalEWRN: - R-SAM-9: #SA-10
- HatayControl - R-POWER-2
- AntakyaPower - R-TOWER-2
- CoastalEWRS: #YELLOW DEFNESE AREA - HINT: Go after the command bunkers
- SamandagControl - Y-COMMAND-1:
- AntakyaPower - Y-POWER-1
# The air defense barrier behind the mountains - Y-TOWER-1
- GreenBarrierSAM: - Y-POWER-2
- SamandagControl - Y-TOWER-2
- GreenBarrierSAM-1: - Y-TOWER-3
- SamandagControl - Y-COMMAND-2:
- GreenBarrierSAM-2: - Y-POWER-1
- HatayControl - Y-TOWER-1
- GreenBarrierSAM-3: - Y-POWER-2
- HatayControl - Y-TOWER-2
- GreenBarrierSAM-4: - Y-TOWER-3
- HatayControl - Y-SAM-1:
# Coastal Defenses - Y-POWER-1
- GreenSAM-2: - Y-TOWER-1
- SamandagControl - Y-POWER-2
- GreenSAM-3: - Y-TOWER-2
- SamandagControl - Y-SAM-2:
- GreenSAM-4: - Y-POWER-1
- SamandagControl - Y-TOWER-1
# Hatay Airfield - Y-POWER-2
- HataySAM: - Y-TOWER-2
- HatayControl - Y-SAM-3:
- HataySAM-1: - Y-POWER-1
- HatayControl - Y-TOWER-1
- HatayAAA: - Y-POWER-2
- HatayControl - Y-TOWER-2
# Industrial/Command zone - Y-SAM-4:
- GreenSAM: - Y-POWER-1
- IdlibControl - Y-TOWER-1
- GreenZoneCommand - Y-POWER-2
- GreenSAM-2: - Y-TOWER-2
- IdlibControl - Y-SAM-5:
- GreenZoneCommand - Y-POWER-1
# long range battery and defenses - Y-TOWER-1
- GreenZoneSAM: - Y-POWER-2
- ReyhanliControl - Y-TOWER-2
- GreenZoneSAMDefense: - Y-SAM-6:
- ReyhanliControl - Y-POWER-1
# C2 links - Y-TOWER-1
- GreenZoneCommand: - Y-POWER-2
- IdlibControl - Y-TOWER-2
- IdlibPower - Y-SAM-7:
- SamandagControl - Y-POWER-2
- HatayControl: - Y-TOWER-2
- ReyhanliControl - Y-TOWER-3
- SamandagControl - Y-SAM-8:
- AntakyaPower - Y-POWER-2
- SamandagControl: - Y-TOWER-2
- AntakyaPower - Y-TOWER-3
- IdlibControl: - Y-SAM-9:
- ReyhanliControl - Y-POWER-2
- SamandagControl - Y-TOWER-2
- IdlibPower - Y-TOWER-3
- ReyhanliControl: - Y-SAM-10:
- IdlibPower - Y-POWER-2
# Pink zone (Aleppo) - Y-TOWER-2
# EWR - Y-TOWER-3
- Abu al-Duhur Air Control: - Y-SAM-11: #SA-5
- Al Safira Power - Y-POWER-2
- Aleppo Air Control: - Y-TOWER-2
- Aleppo Power - Y-TOWER-3
- Kuweires Air Control:
- Al Safira Power
- Aleppo Power
- Jirah Air Control:
- Al Safira Power
# Aleppo city defenses
- AleppoSAM:
- AleppoCommand
- Aleppo Control
- AleppoSAM-1:
- AleppoCommand
- Aleppo Control
- AleppoSAM-2:
- AleppoCommand
- Aleppo Control
- AleppoSAM-3:
- AleppoCommand
- Aleppo Control
- AleppoSAM-4:
- AleppoCommand
- Aleppo Control
- AleppoSAM-5:
- AleppoCommand
- Aleppo Control
- AleppoSAM-6:
- AleppoCommand
- Aleppo Control
- AleppoSAM-7:
- AleppoCommand
- Aleppo Control
# Long Range SAM
- Pink SAM:
- Al Safira Power
- Aleppo Control
- AlSafiraCommand
- AlSafiraPD:
- Aleppo Control
- AlSafiraCommand
# Abu al-Duhur
- AbuSAM:
- Abu al-Duhur control
- AbuSAM-1:
- Abu al-Duhur control
# Kuweires
- KuweiresSAM:
- KuweiresControl
# Jirah
- JirahSAM:
- JirahControl
- JirahSAM-1:
- JirahControl
- JirahSAM-2:
- JirahControl
# C2 links
- AleppoCommand:
- Aleppo Power
- Al Safira Power
- Aleppo Control
- AlSafiraCommand:
- Al Safira Power
- Aleppo Power
- Aleppo Control
- KuweiresControl:
- Al Safira Power
- Aleppo Control
- JirahControl:
- Al Safira Power
- KuweiresControl
- Abu al-Duhur control:
- Aleppo Power
- Aleppo Control
- Aleppo Control:
- Aleppo Power
squadrons: squadrons:
#Incirlik #Incirlik
16: 16:
@@ -340,8 +264,8 @@ squadrons:
aircraft: aircraft:
- Mi-8MTV2 Hip - Mi-8MTV2 Hip
size: 4 size: 4
#carrier #NATO CARRIERS
Blue Carrier: NATO CVN:
- primary: BARCAP - primary: BARCAP
secondary: any secondary: any
aircraft: aircraft:
@@ -365,86 +289,88 @@ squadrons:
aircraft: aircraft:
- S-3B Viking - S-3B Viking
size: 4 size: 4
#Abu Al-Duhur NATO LHA:
1: - primary: BAI
- primary: BARCAP
secondary: any
aircraft:
- MiG-29S Fulcrum-C
size: 16
#Hatay
15:
- primary: SEAD
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- Su-25T Frogfoot - AV-8B Harrier II Night Attack
size: 12 #Abu Al-Duhur
#Minakh 1:
26:
- primary: BAI - primary: BAI
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- Su-34 Fullback - Su-34 Fullback
size: 12
#Hatay
15:
- primary: BAI
secondary: air-to-ground
aircraft:
- Su-24M Fencer-D
size: 12
#Minakh
26:
- primary: BARCAP
secondary: air-to-air
aircraft:
- MiG-21bis Fishbed-N
size: 12 size: 12
#Aleppo #Aleppo
27: 27:
- primary: BARCAP - primary: BARCAP
secondary: air-to-air secondary: air-to-air
aircraft: aircraft:
- MiG-29S Fulcrum-C - MiG-23MLD Flogger-K
size: 16 size: 12
#Jirah #Jirah
17: 17:
- primary: BARCAP - primary: BARCAP
secondary: air-to-air secondary: air-to-air
aircraft: aircraft:
- MiG-31 Foxhound - MiG-23MLD Flogger-K
size: 16 size: 12
#Gaziantep #Gaziantep
11: 11:
- primary: BAI - primary: BARCAP
secondary: air-to-ground secondary: air-to-air
aircraft: aircraft:
- Su-30 Flanker-C - MiG-21bis Fishbed-N
size: 12 size: 12
#Kuweires
31:
- primary: BARCAP
secondary: air-to-air
aircraft:
- MiG-29S Fulcrum-C
size: 12
ground_forces: ground_forces:
NATO SAM: Hawk NATO SAM: Hawk
NATO SAM-1: Hawk NATO SAM-1: Hawk
NATO SAM-2: Hawk NATO SAM-2: Hawk
NATO SAM-3: Hawk NATO SAM-3: Hawk
NATO SAM-4: Hawk NATO SAM-4: Hawk
YellowBarrierN: SA-2/S-75 with ZSU-23/57 B-SAM-1: SA-2/S-75
YellowBarrierC1: SA-6 B-SAM-2: SA-11
YellowBarrierC2: SA-11 B-SAM-3: SA-2/S-75
YellowBarrierS: SA-2/S-75 with ZSU-23/57 B-SAM-4: SA-2/S-75
YellowLongRangeSAM: SA-2/S-75 with ZSU-23/57 B-SAM-5: SA-10/S-300PS
GAZSAMN: SA-11 R-SAM-1: SA-2/S-75
GreenBarrierSAM-4: SA-2/S-75 with ZSU-23/57 R-SAM-2: SA-2/S-75
GreenBarrierSAM-3: SA-2/S-75 with ZSU-23/57 R-SAM-3: SA-11
GreenZoneSAMDefense: SA-11 R-SAM-4: SA-11
GreenZoneSAM: SA-2/S-75 with ZSU-23/57 R-SAM-5: SA-6
HataySAM: SA-11 R-SAM-6: SA-3/S-125
HataySAM-1: SA-2/S-75 with ZSU-23/57 R-SAM-7: SA-6
GreenSAM-2: SA-3/S-125 R-SAM-8: SA-11
GreenSAM-3: SA-6 R-SAM-9: SA-10/S-300PS
GreenSAM-1: SA-2/S-75 with ZSU-23/57 Y-SAM-1: SA-6
JirahSAM: SA-10/S-300PS Y-SAM-2: SA-3/S-125
JirahSAM-1: SA-11 Y-SAM-3: SA-6
JirahSAM-2: SA-2/S-75 with ZSU-23/57 Y-SAM-4: SA-3/S-125
KuweiresSAM: SA-6 Y-SAM-5: SA-6
Pink SAM: SA-11 Y-SAM-6: SA-3/S-125
AlSafiraPD: SA-15 SHORAD Y-SAM-7: SA-11
AleppoSAM: SA-3/S-125 Y-SAM-8: SA-2/S-75
AleppoSAM-1: SA-3/S-125 Y-SAM-9: SA-2/S-75
AleppoSAM-2: SA-3/S-125 Y-SAM-10: SA-2/S-75
AleppoSAM-3: SA-3/S-125 Y-SAM-11: SA-10/S-300PS
AleppoSAM-4: SA-3/S-125
AleppoSAM-5: SA-6
AleppoSAM-6: SA-6
AleppoSAM-7: SA-11
MinakhSAM1: SA-3/S-125
MinakhSAM2: SA-3/S-125
GAZSAMN: SA-11
GAZSAMW: SA-3/S-125
AbuSAM: SA-2/S-75 with ZSU-23/57
AbuSAM-1: SA-15 SHORAD

Binary file not shown.

View File

@@ -0,0 +1,69 @@
---
name: Falklands - Battle for No Man's Land
theater: Falklands
authors: Starfire
recommended_player_faction: USA 2005
recommended_enemy_faction: Private Military Company - Russian (Hard)
description:
<p><strong>Note:</strong> This campaign was designed for helicopters.</p><p>
Set against the rugged and windswept backdrop of the Falkland Islands,
this fictional campaign scenario unfolds with a dramatic dawn sneak attack
on RAF Mount Pleasant Airbase. Orchestrated by a Russia-backed private
military company, the deadly offensive with helicopter gunships and ground troops
has left the airbase's runways in ruins and its defences obliterated. This brutal
incursion resulted in significant casualties among the RAF personnel, with many
killed or wounded in the unexpected onslaught. The carrier HMS Queen Elizabeth and
its task force are on their way to evacuate the survivors and retake Mount Pleasant.
However, they are eight days away at full steam.</p><p>
Amidst this chaos, a beacon of hope emerges in the heart of the Falklands. At Port
Stanley, a small detachment of US military personnel, including helicopter pilots
and armor units, find themselves inadvertently thrust into the fray. Originally at
Port Stanley for some R&R following a training exercise, these soldiers now face
an unexpected and urgent call to action. Their mission is daunting but clear - to
prevent the capture of Port Stanley and liberate East Falkland from the clutches
of the PMC forces.</p><p>
This small group must strategically destroy the PMC forces deployed around the treacherous
valley lying between Wickham Heights and the Onion Ranges, an area ominously known
as No Man's Land. Their plan involves a daring assault to destroy the enemy's
helicopter gunships stationed at San Carlos FOB. Following this, they aim to force
the PMC ground forces into a strategic retreat southward, along the 1.6 mile wide
isthmus into Lafonia. This offensive is designed to create a defensible position
at Goose Green on the narrow isthmus, which can be held against a numerically
superior force until the arrival of Big Lizzie.</p>
miz: battle_for_no_mans_land.miz
performance: 1
recommended_start_date: 2001-11-10
version: "10.7"
squadrons:
#Port Stanley
1:
- primary: DEAD
secondary: air-to-ground
aircraft:
- AH-64D Apache Longbow
size: 6
- primary: BAI
secondary: air-to-ground
aircraft:
- AH-64D Apache Longbow
size: 6
- primary: Air Assault
secondary: any
aircraft:
- UH-60L
- UH-60A
size: 4
#San Carlos FOB
3:
- primary: BAI
secondary: air-to-ground
aircraft:
- Mi-24P Hind-F
size: 6
#Goose Green
24:
- primary: DEAD
secondary: air-to-ground
aircraft:
- Ka-50 Hokum (Blackshark 3)
size: 6

View File

@@ -1,152 +1,167 @@
--- ---
name: Sinai - Exercise Bright Star name: Sinai - Exercise Bright Star
theater: Sinai theater: Sinai
authors: Starfire authors: Starfire
recommended_player_faction: Bluefor Modern recommended_player_faction: Bluefor Modern
recommended_enemy_faction: Egypt 2010's recommended_enemy_faction: Egypt 2000
description: <p>For over 4 decades, the United States and Egypt have run a series of biannual joint military exercises called Bright Star. Over the years, the number of participating countries has grown substantially. Exercise Bright Star 2025 boasts 8 participant nations and 14 observer nations. The United States and a portion of the exercise coalition will play the part of a fictional hostile nation dubbed Orangeland, staging a mock invasion against Cairo. Israel, having for the first time accepted the invitation to observe, is hosting the aggressor faction of the exercise coalition at its airfields.</p> description:
miz: exercise_bright_star.miz <p>For over four decades, the United States and Egypt have conducted a series
performance: 1 of biannual joint military exercises known as Bright Star. As the
recommended_start_date: 2025-09-01 geopolitical landscape has transformed, so too has the scope and scale of
version: "10.7" Exercise Bright Star. The exercise has grown over the years to incorporate
squadrons: a wide array of international participants. The 2025 iteration of
Blue CV-1: Exercise Bright Star features eight participating nations alongside
- primary: SEAD fourteen observer nations.</p><p>
secondary: any For the 2025 exercises, the United States, along with a select contingent
aircraft: from the exercise coalition, will take on the role of a hypothetical
- F/A-18C Hornet (Lot 20) adversarial nation, dubbed Orangeland. This scenario is designed to
size: 24 simulate a mock invasion against Cairo, and presents a valuable
- primary: AEW&C opportunity for participating nations to refine their joint operational
aircraft: capabilities and improve logistical and tactical interoperability</p><p>
- E-2C Hawkeye A historic addition to Exercise Bright Star 2025 is the participation of
size: 2 Israel as an observer nation. This marks a significant milestone, given
- primary: Refueling the complex historical relations in the region, and symbolises a step
aircraft: forward in regional collaboration and military diplomacy. Israel's role,
- S-3B Tanker hosting the aggressor faction of the exercise coalition at its airfields,
size: 2 not only demonstrates the broadening scope of the exercise but also highlights
- primary: Air Assault the value of fostering an environment of mutual cooperation and shared
secondary: any security objectives.</p>
aircraft: miz: exercise_bright_star.miz
- SH-60B Seahawk performance: 1
size: 2 recommended_start_date: 2025-09-01
# Hatzerim (141) version: "10.7"
7: squadrons:
- primary: Escort Blue CV-1:
secondary: air-to-air - primary: SEAD
aircraft: secondary: any
- F-15C Eagle aircraft:
size: 20 - F/A-18C Hornet (Lot 20)
- primary: OCA/Runway size: 24
secondary: any - primary: AEW&C
aircraft: aircraft:
- F-15E Strike Eagle (Suite 4+) - E-2D Advanced Hawkeye
size: 8 size: 2
- primary: Strike - primary: Refueling
secondary: air-to-ground aircraft:
aircraft: - S-3B Tanker
- F-15E Strike Eagle size: 4
size: 8 Bombers from RAF Fairford:
- primary: DEAD - primary: Anti-ship
secondary: any secondary: air-to-ground
aircraft: aircraft:
- F-16CM Fighting Falcon (Block 50) - B-52H Stratofortress
size: 20 size: 8
- primary: BAI - primary: Strike
secondary: any secondary: air-to-ground
aircraft: aircraft:
- JF-17 Thunder - B-1B Lancer
size: 16 size: 8
- primary: BARCAP # Hatzerim (141)
secondary: any 7:
aircraft: - primary: Escort
- Mirage 2000C secondary: any
size: 16 aircraft:
# Kedem - F-15C Eagle
12: size: 20
- primary: Transport - primary: OCA/Runway
aircraft: secondary: any
- CH-47D aircraft:
size: 20 - F-15E Strike Eagle (Suite 4+)
- primary: Air Assault size: 16
secondary: air-to-ground - primary: DEAD
aircraft: secondary: any
- UH-1H Iroquois aircraft:
size: 4 - F-16CM Fighting Falcon (Block 50)
# Nevatim (106) size: 20
8: - primary: BAI
- primary: AEW&C secondary: any
aircraft: aircraft:
- E-3A - JF-17 Thunder
size: 2 size: 16
- primary: Refueling - primary: BARCAP
aircraft: secondary: any
- KC-135 Stratotanker aircraft:
size: 1 - Mirage 2000C
- primary: Refueling size: 12
aircraft: # Kedem
- KC-135 Stratotanker MPRS 12:
size: 1 - primary: Transport
- primary: CAS secondary: any
secondary: air-to-ground aircraft:
aircraft: - CH-47D
- A-10C Thunderbolt II (Suite 7) size: 20
size: 8 - primary: Air Assault
# Melez (30) secondary: any
5: aircraft:
- primary: CAS - UH-60L
secondary: air-to-ground - UH-60A
aircraft: size: 4
- Ka-50 Hokum (Blackshark 3) # Nevatim (106)
size: 4 8:
- primary: TARCAP - primary: AEW&C
secondary: air-to-air aircraft:
aircraft: - E-3A
- Mirage 2000C size: 2
size: 12 - primary: Refueling
- primary: Strike aircraft:
secondary: air-to-ground - KC-135 Stratotanker
aircraft: size: 2
- Mirage 2000C - primary: CAS
size: 12 secondary: air-to-ground
# Wadi al Jandali (72) aircraft:
13: - A-10C Thunderbolt II (Suite 7)
- primary: AEW&C size: 8
aircraft: # Melez (30)
- E-2C Hawkeye 5:
size: 2 - primary: CAS
- primary: SEAD secondary: air-to-ground
secondary: any aircraft:
aircraft: - Ka-50 Hokum (Blackshark 3)
- F-16CM Fighting Falcon (Block 50) size: 4
size: 20 - primary: BAI
- primary: DEAD secondary: any
secondary: any aircraft:
aircraft: - Mirage 2000C
- F-16CM Fighting Falcon (Block 50) size: 12
size: 20 - primary: Escort
- primary: Air Assault secondary: any
secondary: air-to-ground aircraft:
aircraft: - MiG-21bis Fishbed-N
- Mi-24P Hind-F size: 12
size: 4 # Wadi al Jandali (72)
- primary: OCA/Aircraft 13:
secondary: air-to-ground - primary: AEW&C
aircraft: aircraft:
- SA 342L Gazelle - E-2C Hawkeye
size: 4 size: 2
# Cairo West (95) - primary: SEAD
18: secondary: any
- primary: Transport aircraft:
aircraft: - F-4E Phantom II
- C-130 size: 20
size: 8 - primary: DEAD
- primary: Escort secondary: any
secondary: air-to-air aircraft:
aircraft: - F-16CM Fighting Falcon (Block 50)
- MiG-29S Fulcrum-C size: 20
size: 20 - primary: Air Assault
- primary: BARCAP secondary: any
secondary: any aircraft:
aircraft: - Mi-24P Hind-F
- J-7B size: 4
- primary: OCA/Aircraft
secondary: any
aircraft:
- SA 342L Gazelle
size: 4
# Cairo West (95)
18:
- primary: Transport
aircraft:
- C-130
size: 8
- primary: BARCAP
secondary: air-to-air
aircraft:
- MiG-29S Fulcrum-C
size: 20 size: 20

View File

@@ -1,108 +1,127 @@
--- ---
name: Nevada - Exercise Vegas Nerve name: Nevada - Exercise Vegas Nerve
theater: Nevada theater: Nevada
authors: Starfire authors: Starfire
recommended_player_faction: USA 2005 recommended_player_faction: USA 2005
recommended_enemy_faction: Redfor (China) 2010 recommended_enemy_faction: Redfor (China) 2010
description: <p>Welcome to Vegas Nerve, an asymmetrical Red Flag Exercise scenario. You are starting off in control of the two Tonopah airports, and will push south from there. For the duration of this exercise, Creech AFB has been cleared of all fixed wing aircraft and will function as a FARP for rotor ops. OPFOR has a substantial resource advantage and an extensive IADS. Reducing that resource advantage while degrading their IADS will be vital to a successful completion of this exercise. Good luck, Commander.</p> description:
miz: exercise_vegas_nerve.miz <p>Welcome to Vegas Nerve, an asymmetrical Red Flag Exercise scenario. You are
performance: 1 starting off in control of the two Tonopah airports, and will push south from
recommended_start_date: 2011-02-24 there. For the duration of this exercise, Creech AFB has been cleared of all
version: "10.7" fixed wing aircraft and will function as a FARP for rotor ops. OPFOR has a
squadrons: substantial resource advantage and an extensive IADS. Reducing that resource
# Tonopah Airport advantage while degrading their IADS will be vital to a successful completion
17: of this exercise. Good luck, Commander.</p>
- primary: BARCAP miz: exercise_vegas_nerve.miz
secondary: air-to-air performance: 1
aircraft: recommended_start_date: 2011-02-24
- F-15C Eagle version: "10.7"
size: 12 squadrons:
- primary: Strike Bombers from Minot AFB:
secondary: air-to-ground - primary: Strike
aircraft: secondary: air-to-ground
- F-15E Strike Eagle (AI) aircraft:
- F-15E Strike Eagle (Suite 4+) - B-52H Stratofortress
size: 12 size: 4
- primary: AEW&C Bombers from Ellsworth AFB:
aircraft: - primary: OCA/Runway
- E-3A secondary: air-to-ground
size: 1 aircraft:
# Tonopah Test Range - B-1B Lancer
18: size: 4
- primary: BAI # Tonopah Airport
secondary: air-to-ground 17:
aircraft: - primary: TARCAP
- A-10C Thunderbolt II (Suite 7) secondary: any
size: 8 aircraft:
- primary: CAS - F-15C Eagle
secondary: air-to-ground size: 12
aircraft: - primary: Strike
- AH-64D Apache Longbow secondary: air-to-ground
size: 10 aircraft:
- primary: DEAD - F-15E Strike Eagle (Suite 4+)
secondary: air-to-ground size: 12
aircraft: - primary: AEW&C
- F/A-18C Hornet (Lot 20) aircraft:
size: 24 - E-3A
- primary: SEAD size: 1
secondary: air-to-ground # Tonopah Test Range
aircraft: 18:
- F-16CM Fighting Falcon (Block 50) - primary: BAI
size: 24 secondary: air-to-ground
- primary: Air Assault aircraft:
secondary: air-to-ground - A-10C Thunderbolt II (Suite 7)
aircraft: size: 8
- UH-1H Iroquois - primary: CAS
size: 2 secondary: air-to-ground
# Groom Lake aircraft:
2: - AH-64D Apache Longbow
- primary: Escort size: 10
secondary: air-to-air - primary: DEAD
aircraft: secondary: air-to-ground
- J-11A Flanker-L aircraft:
size: 20 - F/A-18C Hornet (Lot 20)
- primary: BAI size: 24
secondary: air-to-ground - primary: SEAD
aircraft: secondary: air-to-ground
- Su-25T Frogfoot aircraft:
size: 20 - F-16CM Fighting Falcon (Block 50)
# Creech size: 24
Creech FARP: - primary: Air Assault
- primary: CAS secondary: air-to-ground
secondary: air-to-ground aircraft:
aircraft: - UH-60L
- Ka-50 Hokum (Blackshark 3) - UH-60A
size: 8 size: 2
- primary: Air Assault # Groom Lake
secondary: air-to-ground 2:
aircraft: - primary: Escort
- Mi-24P Hind-F secondary: air-to-air
size: 4 aircraft:
# Nellis AFB - J-11A Flanker-L
4: size: 20
- primary: Strike - primary: BAI
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- H-6J Badger - Su-25T Frogfoot
size: 20 size: 20
- primary: AEW&C # Creech
aircraft: 1:
- KJ-2000 - primary: CAS
size: 1 secondary: air-to-ground
- primary: SEAD aircraft:
secondary: air-to-ground - Ka-50 Hokum (Blackshark 3)
aircraft: size: 8
- Su-24M Fencer-D - primary: Air Assault
size: 20 secondary: air-to-ground
- primary: DEAD aircraft:
secondary: air-to-ground - Mi-24P Hind-F
aircraft: size: 4
- Su-34 Fullback # Nellis AFB
size: 20 4:
# Boulder City Airport - primary: Strike
6: secondary: air-to-ground
- primary: SEAD Escort aircraft:
secondary: any - H-6J Badger
aircraft: size: 20
- FC-1 Fierce Dragon - primary: AEW&C
size: 20 aircraft:
- KJ-2000
size: 1
- primary: SEAD
secondary: air-to-ground
aircraft:
- Su-24M Fencer-D
size: 20
- primary: DEAD
secondary: air-to-ground
aircraft:
- Su-34 Fullback
size: 20
# Boulder City Airport
6:
- primary: SEAD Escort
secondary: any
aircraft:
- FC-1 Fierce Dragon
size: 20

View File

@@ -1,119 +1,136 @@
--- ---
name: Normandy - The Final Countdown II name: Normandy - The Final Countdown II
theater: Normandy theater: Normandy
authors: Starfire authors: Starfire
recommended_player_faction: D-Day Allied Forces 1944 and 1990 recommended_player_faction: D-Day Allied Forces 1944 and 1990
recommended_enemy_faction: Germany 1944 recommended_enemy_faction: Germany 1944
description: description:
<p>While enroute to the Persian Gulf for Operation Desert Shield, the USS Theodore Roosevelt and its carrier strike group are engufled by an electrical vortex and transported through time and space to the English channel on the morning of the Normandy Landings - June 6th 1944. Seeking to reduce the cost in lives to the Allied Forces about to storm the beaches, the captain of the Roosevelt has elected to provide air support for the landings.</p><p><strong>Note:</strong> This campaign has a custom faction that combines modern US naval forces with WW2 Allied forces. To play it as intended, you should carefully ration your use of modern aircraft and not replenish them if shot down (as you cannot get new Tomcats and Hornets in 1944). You can also choose to play it as a purely WW2 campaign by switching to one of the WW2 Ally factions.</p> <p>While enroute to the Persian Gulf for Operation Desert Shield, the USS
miz: final_countdown_2.miz Theodore Roosevelt and its carrier strike group are engufled by an electrical
performance: 2 vortex and transported through time and space to the English channel on the
recommended_start_date: 1944-06-06 morning of the Normandy Landings - June 6th 1944. Seeking to reduce the cost
version: "10.7" in lives to the Allied Forces about to storm the beaches, the captain of the
squadrons: Roosevelt has elected to provide air support for the
#Blue CV (90) landings.</p><p><strong>Note:</strong> This campaign has a custom faction that
Blue-CV: combines modern US naval forces with WW2 Allied forces. To play it as
- primary: TARCAP intended, you should carefully ration your use of modern aircraft and not
secondary: any replenish them if shot down (as you cannot get new Tomcats and Hornets in
aircraft: 1944). You can also choose to play it as a purely WW2 campaign by switching to
- F-14B Tomcat one of the WW2 Ally factions.</p>
size: 24 miz: final_countdown_2.miz
- primary: DEAD performance: 2
secondary: any recommended_start_date: 1944-06-06
aircraft: version: "10.7"
- F/A-18C Hornet (Lot 20) squadrons:
size: 24 #Blue CV (90)
- primary: AEW&C Blue-CV:
aircraft: - primary: TARCAP
- E-2C Hawkeye secondary: any
size: 2 aircraft:
- primary: Refueling - F-14B Tomcat
aircraft: size: 24
- S-3B Tanker - primary: DEAD
size: 2 secondary: any
- primary: Air Assault aircraft:
secondary: any - F/A-18C Hornet (Lot 20)
aircraft: size: 24
- SH-60B Seahawk - primary: CAS
size: 4 secondary: air-to-ground
#Stoney Cross (39) aircraft:
58: - S-3B Viking
- primary: OCA/Runway size: 12
secondary: air-to-ground - primary: AEW&C
aircraft: aircraft:
- A-20G Havoc - E-2C Hawkeye
- Boston Mk.III size: 2
size: 20 - primary: Refueling
#Needs Oar Point (55) aircraft:
28: - S-3B Tanker
- primary: BARCAP size: 2
secondary: any - primary: Air Assault
aircraft: secondary: any
- Spitfire LF Mk IX aircraft:
size: 20 - UH-60L
- primary: DEAD - UH-60A
secondary: air-to-ground size: 6
aircraft: #Stoney Cross (39)
- MosquitoFBMkVI 58:
size: 20 - primary: OCA/Runway
#RAF Grafton Underwood (1000) secondary: air-to-ground
From RAF Grafton Underwood: aircraft:
- primary: Strike - A-20G Havoc
secondary: air-to-ground - Boston Mk.III
aircraft: size: 20
- B-17G Flying Fortress #Needs Oar Point (55)
- Fortress Mk.III 28:
size: 20 - primary: BARCAP
#Lymington (56) secondary: any
37: aircraft:
- primary: Escort - Spitfire LF Mk IX
secondary: any size: 20
aircraft: - primary: DEAD
- P-51D-30-NA Mustang secondary: air-to-ground
- Mustang Mk.IV (Late) aircraft:
size: 20 - MosquitoFBMkVI
- primary: BAI size: 20
secondary: any #RAF Grafton Underwood (1000)
aircraft: Bombers from RAF Grafton Underwood:
- P-47D-40 Thunderbolt - primary: Strike
- Thunderbolt Mk.II (Late) secondary: air-to-ground
size: 20 aircraft:
- B-17G Flying Fortress
#Carpiquet (47) - Fortress Mk.III
19: size: 20
- primary: TARCAP #Lymington (56)
secondary: air-to-air 37:
aircraft: - primary: Escort
- Fw 190 D-9 Dora secondary: any
size: 12 aircraft:
- primary: CAS - P-51D-30-NA Mustang
secondary: air-to-ground - Mustang Mk.IV (Late)
aircraft: size: 20
- Ju 88 A-4 - primary: BAI
size: 8 secondary: any
#Broglie (32) aircraft:
68: - P-47D-40 Thunderbolt
- primary: Escort - Thunderbolt Mk.II (Late)
secondary: any size: 20
aircraft:
- Bf 109 K-4 Kurfürst #Carpiquet (47)
size: 24 19:
#Saint-Andre-de-lEure (30) - primary: TARCAP
70: secondary: air-to-air
- primary: BAI aircraft:
secondary: air-to-ground - Fw 190 D-9 Dora
aircraft: size: 12
- Ju 88 A-4 - primary: CAS
size: 12 secondary: air-to-ground
- primary: Strike aircraft:
secondary: air-to-ground - Ju 88 A-4
aircraft: size: 8
- Ju 88 A-4 #Broglie (32)
size: 12 68:
#Vilacoublay (76) - primary: Escort
42: secondary: any
- primary: BARCAP aircraft:
secondary: any - Bf 109 K-4 Kurfürst
aircraft: size: 24
- Fw 190 A-8 Anton #Saint-Andre-de-lEure (30)
size: 20 70:
- primary: BAI
secondary: air-to-ground
aircraft:
- Ju 88 A-4
size: 12
- primary: Strike
secondary: air-to-ground
aircraft:
- Ju 88 A-4
size: 12
#Vilacoublay (76)
42:
- primary: BARCAP
secondary: any
aircraft:
- Fw 190 A-8 Anton
size: 20

View File

@@ -1,149 +1,155 @@
--- ---
name: Falklands - Operation Grabthar's Hammer name: Falklands - Operation Grabthar's Hammer
theater: Falklands theater: Falklands
authors: Starfire authors: Starfire
recommended_player_faction: USA 2005 recommended_player_faction: USA 2005
recommended_enemy_faction: Russia 2010 recommended_enemy_faction: Russia 2010
description: description:
<p>An Argentinean extremist group has contracted the Sons of Warvan (SoW), an <p>An Argentinean extremist group has contracted the Sons of Warvan (SoW), an
unusually well-equipped PMC with close ties to the Russian government, to unusually well-equipped PMC with close ties to the Russian government, to
construct a beryllium bomb at the secret Omega 13 production facility in Ushaia construct a beryllium bomb at the secret Omega 13 production facility in
for use in its ongoing conflict with Chile. United States military forces have Ushuaia for use in its ongoing conflict with Chile. United States military
established a foothold at San Julian. While the SoW are distracted up north, it forces have established a foothold at San Julian. While the SoW are distracted
is up to the Marines to launch an assault upon Ushaia from an LHA in order to up north, it is up to the Marines to launch an assault upon Ushuaia from an LHA
disable the bomb production facility. Fortunately, Ushaia is lightly defended as in order to disable the bomb production facility. Fortunately, Ushuaia is
the SoW are trying to avoid unwanted attention.</p> lightly defended as the SoW are trying to avoid unwanted attention.</p>
miz: grabthars_hammer.miz miz: grabthars_hammer.miz
performance: 2 performance: 2
recommended_start_date: 1999-12-25 recommended_start_date: 1999-12-25
version: "10.7" version: "10.7"
squadrons: squadrons:
#Mount Pleasant #Mount Pleasant
2: 2:
- primary: DEAD - primary: DEAD
secondary: any secondary: any
aircraft: aircraft:
- F-16CM Fighting Falcon (Block 50) - F-16CM Fighting Falcon (Block 50)
size: 16 size: 8
- primary: CAS - primary: CAS
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- A-10C Thunderbolt II (Suite 7) - A-10C Thunderbolt II (Suite 7)
size: 8 size: 8
- primary: Strike - primary: Escort
secondary: air-to-ground secondary: any
aircraft: aircraft:
- B-1B Lancer - F-15C Eagle
size: 12 size: 8
- primary: Refueling - primary: Refueling
aircraft: aircraft:
- KC-135 Stratotanker - KC-135 Stratotanker
size: 1 size: 2
#San Julian #San Julian
11: 11:
- primary: BAI - primary: BAI
secondary: air-to-ground secondary: any
aircraft: aircraft:
- F-15E Strike Eagle (AI) - F-15E Strike Eagle (Suite 4+)
- F-15E Strike Eagle (Suite 4+) size: 8
size: 8 #Blue CV
- primary: Air Assault Blue-CV:
secondary: any - primary: BARCAP
aircraft: secondary: any
- UH-1H Iroquois aircraft:
size: 1 - F-14B Tomcat
#Blue CV size: 20
Blue-CV: - primary: SEAD
- primary: BARCAP secondary: any
secondary: any aircraft:
aircraft: - F/A-18C Hornet (Lot 20)
- F-14B Tomcat size: 40
size: 20 - primary: DEAD
- primary: SEAD secondary: air-to-ground
secondary: any aircraft:
aircraft: - S-3B Viking
- F/A-18C Hornet (Lot 20) size: 20
size: 32 - primary: AEW&C
- primary: Escort aircraft:
secondary: any - E-2C Hawkeye
aircraft: size: 2
- F/A-18C Hornet (Lot 20) - primary: Refueling
size: 32 aircraft:
- primary: AEW&C - S-3B Tanker
aircraft: size: 4
- E-2C Hawkeye - primary: Air Assault
size: 1 secondary: any
- primary: Refueling aircraft:
aircraft: - UH-60L
- S-3B Tanker - UH-60A
size: 3 size: 4
- primary: Air Assault # Blue LHA
secondary: any Blue-LHA:
aircraft: - primary: DEAD
- SH-60B Seahawk secondary: air-to-ground
size: 2 aircraft:
# Blue LHA - AV-8B Harrier II Night Attack
Blue-LHA: size: 18
- primary: DEAD - primary: Air Assault
secondary: air-to-ground secondary: any
aircraft: aircraft:
- AV-8B Harrier II Night Attack - UH-1H Iroquois
size: 18 size: 2
- primary: Air Assault Bombers from Edwards AFB:
secondary: air-to-ground - primary: Strike
aircraft: secondary: air-to-ground
- UH-1H Iroquois aircraft:
size: 2 - B-52H Stratofortress
#El Calafate size: 12
14: - primary: OCA/Runway
- primary: Transport secondary: air-to-ground
aircraft: aircraft:
- Mi-8MTV2 Hip - B-1B Lancer
size: 10 size: 12
#Rio Gallegros #El Calafate
5: 14:
- primary: BARCAP - primary: Transport
secondary: air-to-air aircraft:
aircraft: - Mi-8MTV2 Hip
- Su-27 Flanker-B size: 10
size: 12 #Rio Gallegros
- primary: BAI 5:
secondary: air-to-ground - primary: Escort
aircraft: secondary: air-to-air
- Su-25T Frogfoot aircraft:
size: 12 - Su-27 Flanker-B
#Punta Arenas size: 12
9: - primary: BAI
- primary: SEAD secondary: air-to-ground
secondary: air-to-ground aircraft:
aircraft: - Su-25T Frogfoot
- Su-24M Fencer-D size: 12
size: 16 #Punta Arenas
- primary: DEAD 9:
secondary: air-to-ground - primary: SEAD
aircraft: secondary: air-to-ground
- Su-34 Fullback aircraft:
size: 16 - Su-24M Fencer-D
- primary: Strike size: 16
secondary: air-to-ground - primary: DEAD
aircraft: secondary: air-to-ground
- Tu-22M3 Backfire-C aircraft:
size: 16 - Su-34 Fullback
- primary: Refueling size: 16
aircraft: - primary: Strike
- IL-78M secondary: air-to-ground
size: 2 aircraft:
#Ushuaia - Tu-22M3 Backfire-C
7: size: 16
- primary: CAS - primary: Refueling
secondary: air-to-ground aircraft:
aircraft: - IL-78M
- Ka-50 Hokum (Blackshark 3) size: 2
size: 8 #Ushuaia
#Ushuaia Helo Port 7:
8: - primary: CAS
- primary: Air Assault secondary: air-to-ground
secondary: air-to-ground aircraft:
aircraft: - Ka-50 Hokum (Blackshark 3)
- Mi-24P Hind-F size: 8
#Ushuaia Helo Port
8:
- primary: Air Assault
secondary: air-to-ground
aircraft:
- Mi-24P Hind-F
size: 8 size: 8

Binary file not shown.

View File

@@ -0,0 +1,100 @@
---
name: Syria - Operation Aegean Aegis
theater: Syria
authors: Starfire
recommended_player_faction: USA 2005
recommended_enemy_faction: Turkey 2005
description:
<p><strong>Note:</strong> This fictional campaign was designed for the Apache
and Harrier. It requires manual flight planning. While enemy aircraft are present
at airfields, there will be no enemy flights as their aircraft are grounded.</p>
<p>
In a sudden and alarming escalation of tensions in Cyprus, the Anatolian Order,
a North Cypriot insurgent faction, has carried out a bold night-time assault on
three crucial airfields in the Republic of Cyprus; Paphos, Akrotiri, and Larnaca.
The insurgents, equipped with stolen surplus Turkish military hardware, used
chemical weapons in their attack, forcing the evacuation of all three airfields.
Notably, the capture of Akrotiri, a British Overseas Territory hosting a Royal
Air Force base, has drawn significant international attention and concern.</p>
<p>
The EU has strongly condemned this unprovoked attack against one of its member
states. Turkey, despite its historical connections with North Cyprus, has also
denounced the Anatolian Order's actions and is investigating how its aircraft,
ground vehicles, and weaponry held in storage ended up in insurgent hands.</p>
<p>
Amidst the crisis, a lone US Navy LHA, strategically positioned in the Aegean Sea,
is preparing a response to the crisis. Its mission is to deploy Apache helicopters
to neutralise the hastily erected air defenses around the captured airfields, before
Harrier jumpjets neutralise the Anatolian Order's aircraft. These aircraft, a
selection of mothballed Turkish F-4s and helicopters, are currently grounded due to
lack of suitable fuel and spare parts. It is imperative that they are dealt with
swiftly before ground troops are air-lifted in to reclaim the airfields.</p>
<p>
The operation's final phase involves targeting North Cyprus's only airport at Ercan.
The plan is to bomb its runway, preventing any further airborne reinforcements by the
insurgents. However, due to the air defenses established along the northern edge of
the Green Line (the UN-patrolled demilitarised zone) there are strict advisories against
overflying North Cyprus unless absolutely necessary, to minimise the risk of losses.
</p>
miz: operation_aegean_aegis.miz
performance: 1
recommended_start_date: 2017-04-20
recommended_player_money: 1000
recommended_enemy_money: 0
recommended_player_income_multiplier: 1.0
recommended_enemy_income_multiplier: 0.0
version: "10.7"
squadrons:
#Tarawa Class LHA
Blue-LHA:
- primary: DEAD
secondary: air-to-ground
aircraft:
- AH-64D Apache Longbow
size: 12
- primary: DEAD
secondary: air-to-ground
aircraft:
- AV-8B Harrier II Night Attack
size: 6
- primary: Air Assault
secondary: any
aircraft:
- UH-1H Iroquois
size: 2
#Paphos
46:
- primary: DEAD
secondary: air-to-ground
aircraft:
- F-4E Phantom II
size: 12
#Akrotiri
44:
- primary: BAI
secondary: air-to-ground
aircraft:
- AH-1W SuperCobra
size: 4
- primary: CAS
secondary: air-to-ground
aircraft:
- OH-58D Kiowa Warrior
size: 4
- primary: Air Assault
secondary: air-to-ground
aircraft:
- UH-60A
size: 4
#Larnaca
47:
- primary: Transport
aircraft:
- C-130
size: 6
#Ercan
49:
- primary: Transport
aircraft:
- CH-47D
size: 6

View File

@@ -1,146 +1,147 @@
--- ---
name: Persian Gulf - Operation Noisy Cricket name: Persian Gulf - Operation Noisy Cricket
theater: Persian Gulf theater: Persian Gulf
authors: Starfire authors: Starfire
recommended_player_faction: USA 2005 recommended_player_faction: USA 2005
recommended_enemy_faction: Iran 2015 recommended_enemy_faction: Iran 2015
description: description:
<p>In the face of mounting sanctions against their nuclear program, Iran has <p>In the face of mounting sanctions against their nuclear program, Iran has
barred all shipping from transiting the Strait of Hormuz. Three days ago, the barred all shipping from transiting the Strait of Hormuz. Three days ago, the
Iranian Vice-President ordered a series of missile attacks on commercial Iranian Vice-President ordered a series of missile attacks on commercial
vessels entering the Gulf of Oman through the highly strategic chokepoint, vessels entering the Gulf of Oman through the highly strategic chokepoint,
sinking a container ship and damaging two oil tankers. Operation Noisy Cricket sinking a container ship and damaging two oil tankers. Operation Noisy Cricket
is the American response to this threat to regional stability. The objective is the American response to this threat to regional stability. The objective
is to render inoperative Iran's array of coastal anti-ship missile sites, as is to render inoperative Iran's array of coastal anti-ship missile sites, as
well as disable the airfields from which maritime strike aircraft could be well as disable the airfields from which maritime strike aircraft could be
launched.</p><p>While officially intended only to deter any further attempts launched.</p><p>While officially intended only to deter any further attempts
to disrupt the flow of maritime traffic and and protect the interests of the to disrupt the flow of maritime traffic and and protect the interests of the
global economy, The USAF will also leverage the resultant degradation in global economy, The USAF will also leverage the resultant degradation in
Iranian air defences to launch a deep strike from airfields in the UAE in an Iranian air defences to launch a deep strike from airfields in the UAE in an
attempt to take out Iran's last combat-worthy F-14 Tomcats, currently attempt to take out Iran's last combat-worthy F-14 Tomcats, currently
stationed at Kerman. At the same time, a carrier-based Marine detachment will stationed at Kerman. At the same time, a carrier-based Marine detachment will
be inserted via helicopter to conduct an unscheduled inspection of the Bushehr be inserted via helicopter to conduct an unscheduled inspection of the Bushehr
Nuclear Power Plant, in order to verify Iran's compliance with international Nuclear Power Plant, in order to verify Iran's compliance with international
nuclear agreements and gather evidence of any ongoing nuclear weapons nuclear agreements and gather evidence of any ongoing nuclear weapons
development.</p> development.</p>
miz: operation_noisy_cricket.miz miz: operation_noisy_cricket.miz
performance: 1 performance: 1
recommended_start_date: 2019-07-13 recommended_start_date: 2019-07-13
recommended_player_money: 0 recommended_player_money: 0
recommended_enemy_money: 0 recommended_enemy_money: 0
recommended_player_income_multiplier: 0.2 recommended_player_income_multiplier: 0.2
recommended_enemy_income_multiplier: 0.2 recommended_enemy_income_multiplier: 0.2
version: "10.9" version: "10.7"
squadrons: squadrons:
Blue CV-1: Blue CV-1:
- primary: SEAD - primary: SEAD
secondary: any secondary: any
aircraft: aircraft:
- F/A-18C Hornet (Lot 20) - F/A-18C Hornet (Lot 20)
size: 40 size: 40
- primary: AEW&C - primary: AEW&C
aircraft: aircraft:
- E-2C Hawkeye - E-2D Advanced Hawkeye
size: 2 size: 2
- primary: Refueling - primary: Refueling
aircraft: aircraft:
- S-3B Tanker - S-3B Tanker
size: 4 size: 4
- primary: Air Assault - primary: Air Assault
secondary: any secondary: any
aircraft: aircraft:
- SH-60B Seahawk - UH-60L
size: 4 - UH-60A
#Al Minhad AFB (61) size: 4
12: #Al Minhad AFB (61)
- primary: DEAD 12:
secondary: any - primary: DEAD
aircraft: secondary: any
- F-16CM Fighting Falcon (Block 50) aircraft:
size: 32 - F-16CM Fighting Falcon (Block 50)
- primary: Escort size: 32
secondary: air-to-air - primary: Escort
aircraft: secondary: air-to-air
- F-15C Eagle aircraft:
size: 24 - F-15C Eagle
#Al Dhafra AFB (251) size: 24
4: #Al Dhafra AFB (251)
- primary: Strike 4:
secondary: air-to-ground - primary: Strike
aircraft: secondary: air-to-ground
- B-1B Lancer aircraft:
size: 4 - B-1B Lancer
- primary: Refueling size: 4
aircraft: - primary: Refueling
- KC-135 Stratotanker aircraft:
size: 1 - KC-135 Stratotanker
- primary: OCA/Runway size: 1
secondary: any - primary: OCA/Runway
aircraft: secondary: any
- F-15E Strike Eagle (Suite 4+) aircraft:
size: 8 - F-15E Strike Eagle (Suite 4+)
- primary: BAI size: 20
secondary: air-to-ground - primary: DEAD
aircraft: secondary: air-to-ground
- F-15E Strike Eagle aircraft:
size: 12 - AV-8B Harrier II Night Attack
#Bandar Abbas Intl (51) size: 20
2: #Bandar Abbas Intl (51)
- primary: SEAD 2:
secondary: air-to-ground - primary: SEAD
aircraft: secondary: air-to-ground
- F-4E Phantom II aircraft:
size: 20 - F-4E Phantom II
- primary: TARCAP size: 20
secondary: air-to-air - primary: TARCAP
aircraft: secondary: air-to-air
- F-5E Tiger II aircraft:
size: 16 - F-5E Tiger II
#Qeshm Island (12) size: 16
13: #Qeshm Island (12)
- primary: Air Assault 13:
secondary: air-to-ground - primary: Air Assault
aircraft: secondary: air-to-ground
- Mi-24P Hind-F aircraft:
size: 12 - Mi-24P Hind-F
#Abu Musa Island (8) size: 12
1: #Abu Musa Island (8)
- primary: DEAD 1:
secondary: air-to-ground - primary: DEAD
aircraft: secondary: air-to-ground
- Su-25T Frogfoot aircraft:
size: 8 - Su-25T Frogfoot
#Kish Intl (46) size: 8
24: #Kish Intl (46)
- primary: Strike 24:
secondary: air-to-ground - primary: Strike
aircraft: secondary: air-to-ground
- Su-24MK Fencer-D aircraft:
size: 20 - Su-24MK Fencer-D
- primary: Escort size: 20
secondary: any - primary: Escort
aircraft: secondary: any
- Mirage-F1EQ aircraft:
size: 16 - Mirage-F1EQ
#Shiraz Intl (122) size: 16
19: #Shiraz Intl (122)
- primary: Transport 19:
aircraft: - primary: Transport
- IL-76MD aircraft:
size: 5 - IL-76MD
- primary: BARCAP size: 5
secondary: air-to-air - primary: BARCAP
aircraft: secondary: air-to-air
- MiG-29A Fulcrum-A aircraft:
size: 12 - MiG-29A Fulcrum-A
#Kerman size: 12
18: #Kerman
- primary: AEW&C 18:
aircraft: - primary: AEW&C
- A-50 aircraft:
size: 1 - A-50
- primary: BARCAP size: 1
secondary: air-to-air - primary: BARCAP
aircraft: secondary: air-to-air
- F-14A Tomcat (Block 135-GR Late) aircraft:
size: 10 - F-14A Tomcat (Block 135-GR Late)
size: 10

View File

@@ -1,132 +1,160 @@
--- ---
name: Syria - Operation Peace Spring name: Syria - Operation Peace Spring
theater: Syria theater: Syria
authors: Starfire authors: Starfire
recommended_player_faction: Bluefor Modern recommended_player_faction: Bluefor Modern
recommended_enemy_faction: Iraq 1991 recommended_enemy_faction: Iraq 1991
description: <p>This is a semi-fictional what-if scenario for Operation Peace Spring, during which Turkish forces that crossed into Syria on an offensive against Kurdish militias were emboldened by early successes to continue pushing further southward. Attempts to broker a ceasefire have failed. Members of Operation Inherent Resolve have gathered at Ramat David Airbase in Israel to launch a counter-offensive.</p><p><strong>Note:</strong> The default faction is set as Iraq 1991 in order to provide an opponent with a wider variety of units. While Turkey 2005 would be the historical faction (and has preset squadrons included), they only have two jets available (F-4 and F-16).</p> description:
miz: operation_peace_spring.miz <p>This is a semi-fictional what-if scenario for Operation Peace Spring,
performance: 1 during which Turkish forces that crossed into Syria on an offensive against
recommended_start_date: 2019-12-23 Kurdish militias were emboldened by early successes to continue pushing
version: "10.7" further southward. Attempts to broker a ceasefire have failed. Members of
squadrons: Operation Inherent Resolve have gathered at Ramat David Airbase in Israel to
# Ramat David launch a counter-offensive.</p><p><strong>Note:</strong> The default faction
30: is set as Iraq 1991 in order to provide an opponent with a wider variety of
- primary: CAS units. While Turkey 2005 would be the historical faction (and has preset
secondary: air-to-ground squadrons included), they only have two jets available (F-4 and F-16).</p>
aircraft: miz: operation_peace_spring.miz
- A-10C Thunderbolt II (Suite 7) performance: 2
size: 8 recommended_start_date: 2019-12-23
- primary: SEAD version: "10.7"
secondary: any squadrons:
aircraft: Blue CV-1:
- F/A-18C Hornet (Lot 20) - primary: SEAD
size: 20 secondary: any
- primary: Strike aircraft:
secondary: air-to-ground - F/A-18C Hornet (Lot 20)
aircraft: size: 40
- F-15E Strike Eagle (AI) - primary: BAI
- F-15E Strike Eagle (Suite 4+) secondary: air-to-ground
size: 12 aircraft:
- primary: AEW&C - S-3B Viking
aircraft: size: 20
- E-3A - primary: AEW&C
size: 2 aircraft:
# King Hussein Air College - E-2D Advanced Hawkeye
19: size: 4
- primary: DEAD - primary: Refueling
secondary: any aircraft:
aircraft: - S-3B Tanker
- F-16CM Fighting Falcon (Block 50) size: 4
size: 20 Bombers from RAF Fairford:
- primary: BAI - primary: DEAD
secondary: air-to-ground secondary: air-to-ground
aircraft: aircraft:
- AV-8B Harrier II Night Attack - B-52H Stratofortress
size: 8 size: 8
- primary: BARCAP # Akrotiri
secondary: air-to-air 44:
aircraft: - primary: Strike
- F-15C Eagle secondary: air-to-ground
size: 12 aircraft:
- primary: CAS - B-1B Lancer
secondary: air-to-ground size: 8
aircraft: - primary: OCA/Runway
- AH-64D Apache Longbow secondary: any
size: 8 aircraft:
- primary: Refueling - F-15E Strike Eagle (Suite 4+)
aircraft: size: 12
- KC-135 Stratotanker - primary: TARCAP
size: 2 secondary: air-to-air
- primary: Air Assault aircraft:
secondary: air-to-ground - F-15C Eagle
aircraft: size: 20
- UH-1H Iroquois - primary: Air Assault
size: 2 secondary: any
# Damascus aircraft:
7: - UH-60L
- primary: TARCAP - UH-60A
secondary: air-to-air size: 4
aircraft: # Ramat David
- F-4E Phantom II 30:
- Mirage-F1EQ - primary: BAI
size: 12 secondary: air-to-ground
- primary: BAI aircraft:
secondary: air-to-ground - A-10C Thunderbolt II (Suite 7)
aircraft: size: 8
- AH-1W SuperCobra - primary: DEAD
- Su-25 Frogfoot secondary: any
size: 12 aircraft:
- primary: CAS - F-16CM Fighting Falcon (Block 50)
secondary: air-to-ground size: 28
aircraft: - primary: CAS
- OH-58D Kiowa Warrior secondary: air-to-ground
- Mi-24P Hind-F aircraft:
size: 8 - AH-64D Apache Longbow
# Tiyas size: 4
39: # Damascus
- primary: SEAD 7:
secondary: air-to-ground - primary: Strike
aircraft: secondary: air-to-ground
- F-16CM Fighting Falcon (Block 50) aircraft:
- Su-24M Fencer-D - F-4E Phantom II
size: 20 - H-6J Badger
# Abu Al Duhur size: 16
1: - primary: BAI
- primary: Strike secondary: air-to-ground
secondary: air-to-ground aircraft:
aircraft: - AH-1W SuperCobra
- F-4E Phantom II - Su-25 Frogfoot
- H-6J Badger size: 16
size: 20 - primary: CAS
# Gaziantep secondary: air-to-ground
11: aircraft:
- primary: BARCAP - OH-58D Kiowa Warrior
secondary: any - Mi-24P Hind-F
aircraft: size: 4
- F-16CM Fighting Falcon (Block 50) # Tiyas
- MiG-29A Fulcrum-A 39:
size: 12 - primary: SEAD
# Incirlik secondary: air-to-ground
16: aircraft:
- primary: Strike - F-16CM Fighting Falcon (Block 50)
secondary: air-to-ground - Su-24M Fencer-D
aircraft: size: 16
- F-4E Phantom II - primary: Escort
- Tu-22M3 Backfire-C secondary: air-to-air
size: 20 aircraft:
- primary: AEW&C - F-4E Phantom II
aircraft: - Mirage-F1EQ
- E-3A size: 16
- A-50 # Abu Al Duhur
size: 2 1:
- primary: Refueling - primary: Fighter sweep
aircraft: secondary: air-to-air
- KC-135 Stratotanker aircraft:
- IL-78M - F-4E Phantom II
size: 2 - MiG-23ML Flogger-G
- primary: Transport size: 8
aircraft: # Gaziantep
- C-130 11:
- IL-76MD - primary: BARCAP
size: 4 secondary: any
aircraft:
- F-16CM Fighting Falcon (Block 50)
- MiG-29A Fulcrum-A
size: 8
# Incirlik
16:
- primary: Strike
secondary: air-to-ground
aircraft:
- F-4E Phantom II
- Tu-22M3 Backfire-C
size: 16
- primary: AEW&C
aircraft:
- E-3A
- A-50
size: 1
- primary: Refueling
aircraft:
- KC-135 Stratotanker
- IL-78M
size: 1
- primary: Escort
secondary: any
aircraft:
- F-4E Phantom II
- MiG-21bis Fishbed-N
size: 16

View File

@@ -1,148 +1,156 @@
--- ---
name: Caucasus - Operation Vectron's Claw name: Caucasus - Operation Vectron's Claw
theater: Caucasus theater: Caucasus
authors: Starfire authors: Starfire
recommended_player_faction: USA 2005 recommended_player_faction: USA 2005
recommended_enemy_faction: Russia 2010 recommended_enemy_faction: Russia 2010
description: <p>United Nations Observer Mission in Georgia (UNOMIG) observers stationed in Georgia to monitor the ceasefire between Georgia and Abkhazia have been cut off from friendly forces by Russian troops backing the separatist state. The UNOMIG HQ at Sukhumi has been taken, and a small contingent of observers and troops at the Zugdidi Sector HQ will have to make a run for the coast, supported by offshore US naval aircraft. The contingent is aware that their best shot at survival is to swiftly retake Sukhumi before Russian forces have a chance to dig in, so that friendly ground forces can land and reinforce them.</p><p><strong>Note:</strong> Ground unit purchase will not be available past Turn 0 until Sukhumi is retaken, so it is imperative you reach Sukhumi with at least one surviving ground unit to capture it. Two Hueys are available at Zugdidi for some close air support. The player can either play the first leg of the scenario as an evacuation with a couple of light vehicles (e.g. Humvees) set on breakthrough (modifying waypoints in the mission editor so they are not charging head-on into enemy ground forces is suggested), or purchase heavier ground units if they wish to experience a more traditional frontline ground war. Once Sukhumi has been captured, squadrons based in Incirlik Turkey can be ferried in via the "From Incirlik" off-map spawn point.</p> description:
miz: operation_vectrons_claw.miz <p><strong>Background</strong> - The United Nations Observer Mission in Georgia (UNOMIG) has been actively monitoring the ceasefire agreement between Georgia and its breakaway region of Abkhazia. Recent developments have escalated tensions in the area, leading to a precarious situation for UN observers and affiliated personnel.
performance: 1 </p><p><strong>Current Situation</strong> - UNOMIG observers, along with a contingent of international troops, have found themselves isolated due to the intervention of Russian forces supporting the separatist ambitions of Abkhazia. The UNOMIG headquarters located in Sukhumi has fallen into enemy hands. A smaller group based at the Zugdidi Sector Headquarters now faces the daunting task of navigating to safety with the aid of offshore naval air support.
recommended_start_date: 2008-08-08 </p><p><strong>Objective</strong> - The immediate goal is to orchestrate a strategic withdrawal of UN forces to the coastline, leveraging support from US naval aircraft positioned offshore. The critical mission objective is the rapid recapture of Sukhumi. This action is essential to enable the landing of friendly ground forces and the ferrying in of land-based sqwuadrons from Incirlik.
version: "10.7" </p><p><strong>Operational Constraints</strong> - It is crucial to note that reinforcement of ground units will not be possible until Sukhumi is successfully recaptured. This recapture can either be performed using existing UN personnel and ground vehicles, or via heliborne assault troop insertion.
squadrons: </p><p><strong>Assets & Support</strong> - Available assets include two Huey helicopters for close air support. Commanders may opt to initiate the operation with light vehicles, such as Humvees, employing breakthrough tactics to avoid direct confrontations with enemy forces. Alternatively, the use of heavier ground units is an option for commanders seeking a more conventional combat engagement. Upon the recapture of Sukhumi, additional squadrons from Incirlik, Turkey, will become operational.
Blue CV-1: </p><p><strong>Secondary Objective</strong> - Consider prioritising the capture of the Batumi airfield, located to the south, for its strategic value as a forward operating base. Commanders should be aware of the inherent risks, as the airfield is relatively small and lacks air defence systems, posing a significant threat to any stationed aircraft.</p>
- primary: BARCAP miz: operation_vectrons_claw.miz
secondary: any performance: 1
aircraft: recommended_start_date: 2008-08-08
- F-14B Tomcat version: "10.7"
size: 20 control_points:
- primary: SEAD Squadrons from Incirlik:
secondary: any ferry_only: true
aircraft: squadrons:
- F/A-18C Hornet (Lot 20) Blue CV-1:
size: 32 - primary: BARCAP
- primary: Escort secondary: any
secondary: any aircraft:
aircraft: - F-14B Tomcat
- F/A-18C Hornet (Lot 20) size: 16
size: 32 - primary: SEAD
- primary: AEW&C secondary: any
aircraft: aircraft:
- E-2C Hawkeye - F/A-18C Hornet (Lot 20)
size: 1 size: 60
- primary: Refueling - primary: CAS
aircraft: secondary: air-to-ground
- S-3B Tanker aircraft:
size: 3 - S-3B Viking
- primary: Air Assault size: 8
secondary: any - primary: AEW&C
aircraft: aircraft:
- SH-60B Seahawk - E-2C Hawkeye
size: 2 size: 2
Blue LHA: - primary: Refueling
- primary: BAI aircraft:
secondary: air-to-ground - S-3B Tanker
aircraft: size: 2
- AV-8B Harrier II Night Attack - primary: Air Assault
size: 20 secondary: any
From Incirlik: aircraft:
- primary: CAS - UH-60L
secondary: air-to-ground - UH-60A
aircraft: size: 2
- AH-64D Apache Longbow Blue LHA:
size: 8 - primary: BAI
- primary: CAS secondary: air-to-ground
secondary: air-to-ground aircraft:
aircraft: - AV-8B Harrier II Night Attack
- A-10C Thunderbolt II (Suite 7) size: 20
size: 6 Squadrons from Incirlik:
- primary: DEAD - primary: CAS
secondary: any secondary: air-to-ground
aircraft: aircraft:
- F-16CM Fighting Falcon (Block 50) - AH-64D Apache Longbow
size: 16 size: 4
- primary: DEAD - primary: CAS
secondary: any secondary: air-to-ground
aircraft: aircraft:
- F-16CM Fighting Falcon (Block 50) - A-10C Thunderbolt II (Suite 7)
size: 16 size: 6
- primary: BAI - primary: DEAD
secondary: air-to-ground secondary: any
aircraft: aircraft:
- F-15E Strike Eagle (AI) - F-16CM Fighting Falcon (Block 50)
- F-15E Strike Eagle (Suite 4+) size: 16
size: 12 - primary: BAI
- primary: Strike secondary: any
secondary: air-to-ground aircraft:
aircraft: - F-15E Strike Eagle (Suite 4+)
- B-1B Lancer size: 8
size: 8 - primary: Refueling
- primary: Strike aircraft:
secondary: air-to-ground - KC-135 Stratotanker
aircraft: size: 1
- B-52H Stratofortress Bombers from RAF Fairford:
size: 8 - primary: Anti-ship
- primary: Refueling secondary: air-to-ground
aircraft: aircraft:
- KC-135 Stratotanker - B-52H Stratofortress
size: 1 size: 4
#FARPs Bombers from Base Aérea de Morón:
UNOMIG Sector HQ: - primary: OCA/Runway
- primary: Transport secondary: air-to-ground
secondary: any aircraft:
aircraft: - B-1B Lancer
- UH-1H Iroquois size: 4
size: 2 #FARPs
Dzhugba: UNOMIG Sector HQ:
- primary: CAS - primary: Transport
secondary: any secondary: any
aircraft: aircraft:
- Mi-24P Hind-F - UH-1H Iroquois
size: 8 size: 2
#Sukhumi-Babushara Dzhugba:
20: - primary: CAS
- primary: TARCAP secondary: any
secondary: air-to-air aircraft:
aircraft: - Mi-24P Hind-F
- MiG-29S Fulcrum-C size: 4
size: 8 #Sukhumi-Babushara
- primary: BAI 20:
secondary: air-to-ground - primary: TARCAP
aircraft: secondary: air-to-air
- Su-25T Frogfoot aircraft:
size: 12 - MiG-29S Fulcrum-C
#Sochi-Adler size: 8
18: - primary: BAI
- primary: Escort secondary: air-to-ground
secondary: air-to-air aircraft:
aircraft: - Su-25T Frogfoot
- Su-27 Flanker-B size: 12
size: 8 #Sochi-Adler
- primary: SEAD 18:
secondary: air-to-ground - primary: Escort
aircraft: secondary: air-to-air
- Su-24M Fencer-D aircraft:
size: 20 - Su-27 Flanker-B
- primary: DEAD size: 8
secondary: air-to-ground - primary: SEAD
aircraft: secondary: air-to-ground
- Su-34 Fullback aircraft:
size: 20 - Su-24M Fencer-D
#Anapa-Vityazevo size: 20
12: - primary: DEAD
- primary: Strike secondary: air-to-ground
secondary: air-to-ground aircraft:
aircraft: - Su-34 Fullback
- Tu-95MS Bear-H size: 20
size: 16 #Maykop-Khanskaya
Red CV: 16:
- primary: BARCAP - primary: Strike
secondary: any secondary: air-to-ground
aircraft: aircraft:
- SU-33 Flanker-D - Tu-22M3 Backfire-C
size: 18 size: 20
#I am aware there is no Russian LHA. This is just for campaign inversion. #Anapa-Vityazevo
Red LHA: 12:
- primary: BAI - primary: Strike
secondary: air-to-ground secondary: air-to-ground
size: 20 aircraft:
- Tu-95MS Bear-H
size: 16
Red CV:
- primary: BARCAP
secondary: any
aircraft:
- SU-33 Flanker-D
size: 16

Binary file not shown.

View File

@@ -0,0 +1,99 @@
---
name: Marianas - Operation Velvet Thunder
theater: MarianaIslands
authors: Starfire
recommended_player_faction: USA 1970
recommended_enemy_faction: NVA 1970
description:
<p>Operation Velvet Thunder is a high-intensity training exercise designed to
prepare fresh troops for the challenges they will face in Vietnam. The dense
jungle and rugged terrain of the Mariana Islands will provide a realistic
backdrop, allowing our forces to hone essential skills in jungle warfare,
unconventional tactics, and counterinsurgency operations. There are multiple
checkpoints scattered across the area of operations that will have to be
captured by Air Assault. Due to the limited size and availability of LZs, it
is vital to pay close attention to where you designate troop drop off zones.
</p><p><strong>Note:</strong> This campaign is intended to be played with the
A-4 Skyhawk and OV-10a aircraft mods active. The C-101CC has also been included
as a stand-in for the Cessna A-37 Dragonfly in order to provide a CAS platform
of roughly equivalent combat capability. This campaign will be updated to use
Heatblur's F-4 Phantom II once it is in early access.</p>
miz: operation_velvet_thunder.miz
performance: 1
recommended_start_date: 1970-11-29
version: "10.7"
settings:
a4_skyhawk: true
f4bc_phantom: true
ov10a_bronco: true
squadrons:
#Andersen AFB
6:
- primary: Escort
secondary: any
aircraft:
- F-5E Tiger II
size: 8
- primary: BAI
secondary: any
aircraft:
- C-101CC Aviojet
size: 8
- primary: CAS
secondary: any
aircraft:
- OV-10A Bronco
size: 8
- primary: SEAD
secondary: any
aircraft:
- F-4C Phantom II
- F-4E Phantom II
size: 8
- primary: Strike
secondary: any
aircraft:
- B-52H Stratofortress
size: 4
- primary: Air Assault
secondary: any
aircraft:
- UH-1H Iroquois
size: 4
- primary: Transport
secondary: any
aircraft:
- CH-47D
size: 4
#Blue CV
Blue-CV:
- primary: DEAD
secondary: any
aircraft:
- A-4E Skyhawk
size: 16
- primary: AEW&C
aircraft:
- E-2C Hawkeye
size: 2
#Rota Intl
1:
- primary: TARCAP
secondary: any
aircraft:
- MiG-19P Farmer-B
size: 8
#Tinian Intl
3:
- primary: Air Assault
secondary: any
aircraft:
- Mi-8MTV2 Hip
size: 4
#Saipan Intl
2:
- primary: BAI
secondary: any
aircraft:
- MiG-21bis Fishbed-N
size: 8

View File

@@ -14,6 +14,8 @@ recommended_player_money: 2000
recommended_enemy_money: 1000 recommended_enemy_money: 1000
recommended_player_income_multiplier: 1.5 recommended_player_income_multiplier: 1.5
recommended_enemy_income_multiplier: 0.7 recommended_enemy_income_multiplier: 0.7
settings:
airbase_threat_range: 300
squadrons: squadrons:
#BLUFOR CVN #BLUFOR CVN
Naval-3: Naval-3:

View File

@@ -2,30 +2,6 @@ local unitPayloads = {
["name"] = "AH-64D_BLK_II", ["name"] = "AH-64D_BLK_II",
["payloads"] = { ["payloads"] = {
[1] = { [1] = {
["name"] = "Retribution CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 4,
},
[3] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 2,
},
[4] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 31,
},
},
[2] = {
["displayName"] = "Retribution BAI", ["displayName"] = "Retribution BAI",
["name"] = "Retribution BAI", ["name"] = "Retribution BAI",
["pylons"] = { ["pylons"] = {
@@ -45,12 +21,16 @@ local unitPayloads = {
["CLSID"] = "{M299_4xAGM_114L}", ["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 1, ["num"] = 1,
}, },
[5] = {
["CLSID"] = "{AN_APG_78}",
["num"] = 6,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
}, },
}, },
[3] = { [2] = {
["name"] = "Retribution OCA/Aircraft", ["name"] = "Retribution OCA/Aircraft",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
@@ -69,14 +49,46 @@ local unitPayloads = {
["CLSID"] = "{M261_M229}", ["CLSID"] = "{M261_M229}",
["num"] = 1, ["num"] = 1,
}, },
[5] = {
["CLSID"] = "{AN_APG_78}",
["num"] = 6,
},
},
["tasks"] = {
[1] = 31,
},
},
[3] = {
["name"] = "Retribution CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 4,
},
[3] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 2,
},
[4] = {
["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 1,
},
[5] = {
["CLSID"] = "{AN_APG_78}",
["num"] = 6,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
}, },
}, },
[4] = { [4] = {
["displayName"] = "Retribution Escort", ["displayName"] = "Retribution DEAD",
["name"] = "Retribution Escort", ["name"] = "Retribution DEAD",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{M299_4xAGM_114L}", ["CLSID"] = "{M299_4xAGM_114L}",
@@ -94,6 +106,39 @@ local unitPayloads = {
["CLSID"] = "{M299_4xAGM_114L}", ["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 1, ["num"] = 1,
}, },
[5] = {
["CLSID"] = "{AN_APG_78}",
["num"] = 6,
},
},
["tasks"] = {
[1] = 31,
},
},
[5] = {
["displayName"] = "Retribution Escort",
["name"] = "Retribution Escort",
["pylons"] = {
[1] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 4,
},
[3] = {
["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}",
["num"] = 2,
},
[4] = {
["CLSID"] = "{M299_4xAGM_114L}",
["num"] = 1,
},
[5] = {
["CLSID"] = "{AN_APG_78}",
["num"] = 6,
},
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,

View File

@@ -2,84 +2,81 @@ local unitPayloads = {
["name"] = "B-52H", ["name"] = "B-52H",
["payloads"] = { ["payloads"] = {
[1] = { [1] = {
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "{46ACDCF8-5451-4E26-BDDB-E78D5830E93C}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 30,
},
},
[2] = {
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}",
["num"] = 1,
},
[2] = {
["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}",
["num"] = 3,
},
},
["tasks"] = {
[1] = 32,
[2] = 34,
},
},
[3] = {
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{8DCAF3A3-7FCF-41B8-BB88-58DEDA878EDE}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 33,
},
},
[4] = {
["name"] = "CAP",
["pylons"] = {
},
["tasks"] = {
},
},
[5] = {
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}",
["num"] = 1,
},
},
["tasks"] = {
},
},
[6] = {
["displayName"] = "Retribution OCA/Runway",
["name"] = "Retribution OCA/Runway", ["name"] = "Retribution OCA/Runway",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}", ["CLSID"] = "{585D626E-7F42-4073-AB70-41E728C333E2}",
["num"] = 1, ["num"] = 3,
}, },
[2] = { [2] = {
["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}", ["CLSID"] = "{6C47D097-83FF-4FB2-9496-EAB36DDF0B05}",
["num"] = 3, ["num"] = 2,
},
[3] = {
["CLSID"] = "{585D626E-7F42-4073-AB70-41E728C333E2}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 32,
},
},
[2] = {
["name"] = "Retribution DEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{45447F82-01B5-4029-A572-9AAD28AF0275}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{8DCAF3A3-7FCF-41B8-BB88-58DEDA878EDE}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{45447F82-01B5-4029-A572-9AAD28AF0275}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 32,
},
},
[3] = {
["displayName"] = "Retribution Anti-ship",
["name"] = "Retribution Anti-ship",
["pylons"] = {
[1] = {
["CLSID"] = "{HSAB-6xAGM-84}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{HSAB-6xAGM-84}",
["num"] = 1,
},
},
["tasks"] = {
[1] = 32,
},
},
[4] = {
["displayName"] = "Retribution Strike",
["name"] = "Retribution Strike",
["pylons"] = {
[1] = {
["CLSID"] = "{585D626E-7F42-4073-AB70-41E728C333E2}",
["num"] = 3,
},
[2] = {
["CLSID"] = "{6C47D097-83FF-4FB2-9496-EAB36DDF0B05}",
["num"] = 2,
},
[3] = {
["CLSID"] = "{585D626E-7F42-4073-AB70-41E728C333E2}",
["num"] = 1,
}, },
}, },
["tasks"] = { ["tasks"] = {
[1] = 32, [1] = 32,
[2] = 34,
}, },
}, },
}, },

View File

@@ -2,133 +2,127 @@ local unitPayloads = {
["name"] = "Ka-50", ["name"] = "Ka-50",
["payloads"] = { ["payloads"] = {
[1] = { [1] = {
["name"] = "CAS", ["name"] = "Retribution CAS",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1, ["num"] = 4,
}, },
[2] = { [2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 2, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "B_8V20A_OFP2",
["num"] = 3, ["num"] = 3,
}, },
[4] = { [4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "B_8V20A_OFP2",
["num"] = 4, ["num"] = 2,
}, },
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
[2] = 32,
[3] = 18,
}, },
}, },
[2] = { [2] = {
["name"] = "CAP", ["displayName"] = "Retribution BAI",
["name"] = "Retribution BAI",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1, ["num"] = 4,
}, },
[2] = { [2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 2, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "B_8V20A_OFP2",
["num"] = 3, ["num"] = 3,
}, },
[4] = { [4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "B_8V20A_OFP2",
["num"] = 4, ["num"] = 2,
}, },
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
[2] = 32,
[3] = 18,
}, },
}, },
[3] = { [3] = {
["name"] = "SEAD", ["displayName"] = "Retribution DEAD",
["name"] = "Retribution DEAD",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1, ["num"] = 4,
}, },
[2] = { [2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 2, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3, ["num"] = 3,
}, },
[4] = { [4] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 4, ["num"] = 2,
}, },
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
[2] = 32,
[3] = 18,
}, },
}, },
[4] = { [4] = {
["name"] = "ANTISHIP", ["displayName"] = "Retribution OCA/Aircraft",
["name"] = "Retribution OCA/Aircraft",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1, ["num"] = 4,
}, },
[2] = { [2] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 2, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 3, ["num"] = 3,
}, },
[4] = { [4] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 4, ["num"] = 2,
}, },
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
[2] = 32,
[3] = 18,
}, },
}, },
[5] = { [5] = {
["name"] = "STRIKE", ["displayName"] = "Retribution Escort",
["name"] = "Retribution Escort",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1, ["num"] = 4,
}, },
[2] = { [2] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 2, ["num"] = 1,
}, },
[3] = { [3] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3, ["num"] = 3,
}, },
[4] = { [4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 4, ["num"] = 2,
}, },
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
[2] = 32,
[3] = 18,
}, },
}, },
}, },

View File

@@ -2,7 +2,7 @@ local unitPayloads = {
["name"] = "Ka-50_3", ["name"] = "Ka-50_3",
["payloads"] = { ["payloads"] = {
[1] = { [1] = {
["name"] = "CAS", ["name"] = "Retribution CAS",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{9S846_2xIGLA}", ["CLSID"] = "{9S846_2xIGLA}",
@@ -34,8 +34,8 @@ local unitPayloads = {
}, },
}, },
[2] = { [2] = {
["displayName"] = "STRIKE", ["displayName"] = "Retribution BAI",
["name"] = "STRIKE", ["name"] = "Retribution BAI",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
["CLSID"] = "{9S846_2xIGLA}", ["CLSID"] = "{9S846_2xIGLA}",
@@ -54,20 +54,86 @@ local unitPayloads = {
["num"] = 1, ["num"] = 1,
}, },
[5] = { [5] = {
["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", ["CLSID"] = "B_8V20A_OFP2",
["num"] = 3, ["num"] = 3,
}, },
[6] = { [6] = {
["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", ["CLSID"] = "B_8V20A_OFP2",
["num"] = 2, ["num"] = 2,
}, },
}, },
["tasks"] = { ["tasks"] = {
[1] = 31, [1] = 31,
[2] = 32,
}, },
}, },
[3] = { [3] = {
["displayName"] = "Retribution OCA/Aircraft",
["name"] = "Retribution OCA/Aircraft",
["pylons"] = {
[1] = {
["CLSID"] = "{9S846_2xIGLA}",
["num"] = 6,
},
[2] = {
["CLSID"] = "{9S846_2xIGLA}",
["num"] = 5,
},
[3] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}",
["num"] = 1,
},
[5] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 3,
},
[6] = {
["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
},
},
[4] = {
["displayName"] = "Retribution DEAD",
["name"] = "Retribution DEAD",
["pylons"] = {
[1] = {
["CLSID"] = "{9S846_2xIGLA}",
["num"] = 6,
},
[2] = {
["CLSID"] = "{9S846_2xIGLA}",
["num"] = 5,
},
[3] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 4,
},
[4] = {
["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1,
},
[5] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3,
},
[6] = {
["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 2,
},
},
["tasks"] = {
[1] = 31,
},
},
[5] = {
["displayName"] = "Retribution Escort",
["name"] = "Retribution Escort", ["name"] = "Retribution Escort",
["pylons"] = { ["pylons"] = {
[1] = { [1] = {
@@ -79,19 +145,19 @@ local unitPayloads = {
["num"] = 5, ["num"] = 5,
}, },
[3] = { [3] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 4, ["num"] = 4,
}, },
[4] = { [4] = {
["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}",
["num"] = 1, ["num"] = 1,
}, },
[5] = { [5] = {
["CLSID"] = "B_8V20A_OFP2", ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 3, ["num"] = 3,
}, },
[6] = { [6] = {
["CLSID"] = "B_8V20A_OFP2", ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}",
["num"] = 2, ["num"] = 2,
}, },
}, },

View File

@@ -1,168 +1,174 @@
local unitPayloads = { local unitPayloads = {
["name"] = "S-3B", ["name"] = "S-3B",
["payloads"] = { ["payloads"] = {
[1] = { [1] = {
["name"] = "SEAD", ["displayName"] = "Retribution OCA/Aircraft",
["pylons"] = { ["name"] = "Retribution OCA/Aircraft",
[1] = { ["pylons"] = {
["CLSID"] = "{AF42E6DF-9A60-46D8-A9A0-1708B241AADB}", [1] = {
["num"] = 1, ["CLSID"] = "{B83CB620-5BBE-4BEA-910C-EB605A327EF9}",
}, ["num"] = 6,
[2] = { },
["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", [2] = {
["num"] = 2, ["CLSID"] = "{B83CB620-5BBE-4BEA-910C-EB605A327EF9}",
}, ["num"] = 1,
[3] = { },
["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", [3] = {
["num"] = 3, ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
}, ["num"] = 2,
[4] = { },
["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", [4] = {
["num"] = 4, ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
}, ["num"] = 3,
[5] = { },
["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", [5] = {
["num"] = 5, ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
}, ["num"] = 4,
[6] = { },
["CLSID"] = "{AF42E6DF-9A60-46D8-A9A0-1708B241AADB}", [6] = {
["num"] = 6, ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
}, ["num"] = 5,
}, },
["tasks"] = { },
[1] = 29, ["tasks"] = {
}, [1] = 30,
}, },
[2] = { },
["name"] = "ANTISHIP", [2] = {
["pylons"] = { ["displayName"] = "Retribution DEAD",
[1] = { ["name"] = "Retribution DEAD",
["CLSID"] = "{8B7CADF9-4954-46B3-8CFB-93F2F5B90B03}", ["pylons"] = {
["num"] = 1, [1] = {
}, ["CLSID"] = "{AF42E6DF-9A60-46D8-A9A0-1708B241AADB}",
[2] = { ["num"] = 6,
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", },
["num"] = 2, [2] = {
}, ["CLSID"] = "{AF42E6DF-9A60-46D8-A9A0-1708B241AADB}",
[3] = { ["num"] = 1,
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", },
["num"] = 3, },
}, ["tasks"] = {
[4] = { [1] = 30,
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", },
["num"] = 4, },
}, [3] = {
[5] = { ["displayName"] = "Retribution Anti-ship",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["name"] = "Retribution Anti-ship",
["num"] = 5, ["pylons"] = {
}, [1] = {
[6] = { ["CLSID"] = "{8B7CADF9-4954-46B3-8CFB-93F2F5B90B03}",
["CLSID"] = "{8B7CADF9-4954-46B3-8CFB-93F2F5B90B03}", ["num"] = 6,
["num"] = 6, },
}, [2] = {
}, ["CLSID"] = "{8B7CADF9-4954-46B3-8CFB-93F2F5B90B03}",
["tasks"] = { ["num"] = 1,
[1] = 30, },
}, },
}, ["tasks"] = {
[3] = { [1] = 30,
["name"] = "STRIKE", },
["pylons"] = { },
[1] = { [4] = {
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}", ["name"] = "Retribution CAS",
["num"] = 1, ["pylons"] = {
}, [1] = {
[2] = { ["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 6,
["num"] = 2, },
}, [2] = {
[3] = { ["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 1,
["num"] = 3, },
}, [3] = {
[4] = { ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 2,
["num"] = 4, },
}, [4] = {
[5] = { ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 3,
["num"] = 5, },
}, [5] = {
[6] = { ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}", ["num"] = 4,
["num"] = 6, },
}, [6] = {
}, ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["tasks"] = { ["num"] = 5,
[1] = 32, },
[1] = 33, },
}, ["tasks"] = {
}, [1] = 30,
[4] = { },
["name"] = "CAS", },
["pylons"] = { [5] = {
[1] = { ["displayName"] = "Retribution BAI",
["CLSID"] = "{A76344EB-32D2-4532-8FA2-0C1BDC00747E}", ["name"] = "Retribution BAI",
["num"] = 1, ["pylons"] = {
}, [1] = {
[2] = { ["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}",
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", ["num"] = 6,
["num"] = 2, },
}, [2] = {
[3] = { ["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}",
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", ["num"] = 1,
["num"] = 3, },
}, [3] = {
[4] = { ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", ["num"] = 5,
["num"] = 4, },
}, [4] = {
[5] = { ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", ["num"] = 4,
["num"] = 5, },
}, [5] = {
[6] = { ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["CLSID"] = "{A76344EB-32D2-4532-8FA2-0C1BDC00747E}", ["num"] = 3,
["num"] = 6, },
}, [6] = {
}, ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}",
["tasks"] = { ["num"] = 2,
[1] = 31, },
}, },
}, ["tasks"] = {
}, [1] = 30,
[5] = { },
["name"] = "RUNWAY_ATTACK", },
["pylons"] = { [6] = {
[1] = { ["displayName"] = "Retribution Strike",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["name"] = "Retribution Strike",
["num"] = 1, ["pylons"] = {
}, [1] = {
[2] = { ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 6,
["num"] = 2, },
}, [2] = {
[3] = { ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 1,
["num"] = 3, },
}, [3] = {
[4] = { ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 5,
["num"] = 4, },
}, [4] = {
[5] = { ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 4,
["num"] = 5, },
}, [5] = {
[6] = { ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", ["num"] = 3,
["num"] = 6, },
}, [6] = {
}, ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}",
["tasks"] = { ["num"] = 2,
[1] = 34, },
}, },
}, ["tasks"] = {
["unitType"] = "S-3B", [1] = 30,
} },
return unitPayloads },
},
["tasks"] = {
},
["unitType"] = "S-3B",
}
return unitPayloads

View File

@@ -21,6 +21,7 @@
"S-3B Viking", "S-3B Viking",
"F/A-18C Hornet (Lot 20)", "F/A-18C Hornet (Lot 20)",
"F-14B Tomcat", "F-14B Tomcat",
"F-14A Tomcat (Block 135-GR Late)",
"UH-1H Iroquois", "UH-1H Iroquois",
"B-1B Lancer" "B-1B Lancer"

View File

@@ -0,0 +1,96 @@
{
"country": "Egypt",
"name": "Egypt 2000",
"authors": "Starfire",
"description": "<p>Egyptian military in the 21st century.</p>",
"locales": [
"ar_SA"
],
"aircrafts": [
"MiG-29S Fulcrum-C",
"MiG-21bis Fishbed-N",
"Mirage 2000C",
"F-4E Phantom II",
"F-16CM Fighting Falcon (Block 50)",
"IL-76MD",
"C-130",
"C-130J-30 Super Hercules",
"AH-64D Apache Longbow",
"AH-64D Apache Longbow (AI)",
"SA 342L Gazelle",
"SA 342M Gazelle",
"CH-47D",
"Ka-50 Hokum",
"Ka-50 Hokum (Blackshark 3)",
"Mi-24V Hind-E",
"Mi-24P Hind-F",
"Mi-8MTV2 Hip"
],
"awacs": [
"E-2C Hawkeye"
],
"frontline_units": [
"M1A2 Abrams",
"M60A3 \"Patton\"",
"T-90A",
"T-55A",
"BMP-1",
"M113",
"BTR-80",
"M1043 HMMWV (M2 HMG)",
"M1045 HMMWV (BGM-71 TOW)",
"M1097 Heavy HMMWV Avenger",
"ZSU-23-4 Shilka",
"M163 Vulcan Air Defense System"
],
"artillery_units": [
"M109A6 Paladin",
"M270 Multiple Launch Rocket System"
],
"logistics_units": [
"Truck Ural-375",
"Truck Ural-4320T",
"Truck GAZ-66"
],
"infantry_units": [
"Infantry RPG",
"Infantry AK-74 Rus",
"MANPADS SA-18 Igla \"Grouse\"",
"MANPADS Stinger",
"Mortar 2B11 120mm",
"Paratrooper AKS",
"Paratrooper RPG-16"
],
"preset_groups": [
"SA-2/S-75",
"SA-6",
"SA-17",
"SA-10/S-300PS",
"SA-23/S-300VM",
"Patriot",
"Hawk"
],
"naval_units": [
"FFG Oliver Hazard Perry",
"Corvette 1241.1 Molniya",
"FAC La Combattante IIa"
],
"missiles": [
"SSM SS-1C Scud-B"
],
"air_defense_units": [
"EWR AN/FPS-117 Radar",
"EWR 55G6",
"M1097 Heavy HMMWV Avenger",
"M48 Chaparral",
"M163 Vulcan Air Defense System",
"SA-9 Strela",
"SA-15 Tor",
"ZSU-23-4 Shilka",
"AAA ZU-23 Closed Emplacement",
"ZU-23 on Ural-375",
"ZSU-57-2 'Sparka'"
],
"has_jtac": true,
"jtac_unit": "MQ-9 Reaper"
}

View File

@@ -1,73 +1,73 @@
{ {
"country": "Combined Joint Task Forces Blue", "country": "Combined Joint Task Forces Blue",
"name": "D-Day Allied Forces 1944 and 1990", "name": "D-Day Allied Forces 1944 and 1990",
"authors": "Starfire", "authors": "Starfire",
"description": "<p>Faction for Final Countdown II</p>", "description": "<p>Faction for Final Countdown II</p>",
"aircrafts": [ "locales": [
"Boston Mk.III", "en_US"
"Fortress Mk.III", ],
"Mustang Mk.IV (Late)", "aircrafts": [
"Spitfire LF Mk IX", "Boston Mk.III",
"Thunderbolt Mk.II (Late)", "Fortress Mk.III",
"MosquitoFBMkVI", "Mustang Mk.IV (Late)",
"F-14B Tomcat", "Spitfire LF Mk IX",
"F/A-18C Hornet (Lot 20)", "Thunderbolt Mk.II (Late)",
"SH-60B Seahawk" "MosquitoFBMkVI",
], "F-14B Tomcat",
"awacs": [ "F/A-18C Hornet (Lot 20)",
"E-2C Hawkeye" "S-3B Viking",
], "UH-60L",
"tankers": [ "UH-60A"
"S-3B Tanker" ],
], "awacs": [
"frontline_units": [ "E-2C Hawkeye"
"A17 Light Tank Mk VII Tetrarch", ],
"A22 Infantry Tank MK IV Churchill VII", "tankers": [
"A27L Cruiser Tank MK VIII Centaur IV", "S-3B Tanker"
"A27M Cruiser Tank MK VIII Cromwell IV", ],
"Daimler Armoured Car Mk I", "frontline_units": [
"M2A1 Half-Track", "A17 Light Tank Mk VII Tetrarch",
"QF 40 mm Mark III", "A22 Infantry Tank MK IV Churchill VII",
"Sherman Firefly VC", "A27L Cruiser Tank MK VIII Centaur IV",
"Sherman III" "A27M Cruiser Tank MK VIII Cromwell IV",
], "Daimler Armoured Car Mk I",
"artillery_units": [ "M2A1 Half-Track",
"M12 Gun Motor Carriage" "QF 40 mm Mark III",
], "Sherman Firefly VC",
"logistics_units": [ "Sherman III"
"Truck Bedford", ],
"Truck GMC \"Jimmy\" 6x6 Truck" "artillery_units": [
], "M12 Gun Motor Carriage"
"infantry_units": [ ],
"Infantry M1 Garand", "logistics_units": [
"Infantry SMLE No.4 Mk-1" "Truck Bedford",
], "Truck GMC \"Jimmy\" 6x6 Truck"
"missiles": [], ],
"air_defense_units": [ "infantry_units": [
"Bofors 40 mm Gun" "Infantry M1 Garand"
], ],
"preset_groups": [ "naval_units": [
"Ally Flak", "DDG Arleigh Burke IIa",
"WW2LST" "CG Ticonderoga",
], "CVN-74 John C. Stennis"
"locales": [ ],
"en_US" "missiles": [],
], "air_defense_units": [
"naval_units": [ "Bofors 40 mm Gun"
"DDG Arleigh Burke IIa", ],
"CG Ticonderoga", "preset_groups": [
"CVN-74 John C. Stennis" "Ally Flak"
], ],
"requirements": { "requirements": {
"WW2 Asset Pack": "https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/" "WW2 Asset Pack": "https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/"
}, },
"carrier_names": [ "carrier_names": [
"CVN-71 Theodore Roosevelt" "CVN-71 Theodore Roosevelt"
], ],
"helicopter_carrier_names": [], "has_jtac": true,
"has_jtac": true, "jtac_unit": "MQ-9 Reaper",
"doctrine": "ww2", "unrestricted_satnav": true,
"unrestricted_satnav": true, "doctrine": "ww2",
"building_set": "ww2ally", "building_set": "ww2ally",
"cargo_ship": "LST Mk.II" "cargo_ship": "LST Mk.II"
} }

View File

@@ -0,0 +1,55 @@
{
"country": "Vietnam",
"name": "NVA 1970",
"authors": "Starfire",
"description": "<p>North Vietnamese Army during the Vietnam War from 1965 to 1975</p>",
"locales": [
"vi_Vn"
],
"aircrafts": [
"Mi-8MTV2 Hip",
"MiG-19P Farmer-B",
"MiG-21bis Fishbed-N"
],
"awacs": [],
"tankers": [],
"frontline_units": [
"T-55A",
"PT-76",
"M2A1 Half-Track",
"Grad MRL FDDM (FC)"
],
"artillery_units": [
"BM-21 Grad"
],
"logistics_units": [
"LUV UAZ-469 Jeep",
"Truck Ural-375"
],
"infantry_units": [
"Infantry AK-74 Rus",
"Infantry RPG"
],
"missiles": [],
"preset_groups": [
"SA-2/S-75",
"SA-3/S-125",
"KS-19/SON-9",
"Cold-War-Flak"
],
"naval_units": [
"Boat Armed Hi-speed",
"Boat Schnellboot type S130"
],
"air_defense_units": [
"SAM P19 \"Flat Face\" SR (SA-2/3)",
"S-60 57mm",
"8.8 cm Flak 18",
"ZSU-57-2 'Sparka'",
"AAA ZU-23 Emplacement",
"ZU-23 on Ural-375",
"ZSU-23-4 Shilka"
],
"requirements": {},
"doctrine": "coldwar"
}

View File

@@ -1,120 +1,121 @@
{ {
"country": "China", "country": "China",
"name": "Redfor (China) 2010", "name": "Redfor (China) 2010",
"authors": "Robert Peary", "authors": "Robert Peary",
"description": "<p>Combined Redfor under China's leadership in the late 2000s, early 2010s.</p>", "description": "<p>Combined Redfor under China's leadership in the late 2000s, early 2010s.</p>",
"aircrafts": [ "aircrafts": [
"FC-1 Fierce Dragon", "FC-1 Fierce Dragon",
"IL-76MD", "IL-76MD",
"J-11A Flanker-L", "J-11A Flanker-L",
"J-15 Flanker X-2", "J-15 Flanker X-2",
"J-7B", "J-7B",
"Ka-50 Hokum", "Ka-50 Hokum",
"L-39ZA Albatros", "Ka-50 Hokum (Blackshark 3)",
"Mi-24V Hind-E", "L-39ZA Albatros",
"Mi-24P Hind-F", "Mi-24V Hind-E",
"Mi-28N Havoc", "Mi-24P Hind-F",
"Mi-8MTV2 Hip", "Mi-28N Havoc",
"MiG-29S Fulcrum-C", "Mi-8MTV2 Hip",
"MiG-31 Foxhound", "MiG-29S Fulcrum-C",
"Su-24M Fencer-D", "MiG-31 Foxhound",
"Su-25 Frogfoot", "Su-24M Fencer-D",
"Su-25T Frogfoot", "Su-25 Frogfoot",
"Su-27 Flanker-B", "Su-25T Frogfoot",
"Su-30MKK Flanker-G", "Su-27 Flanker-B",
"Su-34 Fullback", "Su-30MKK Flanker-G",
"Tu-22M3 Backfire-C", "Su-34 Fullback",
"H-6J Badger" "Tu-22M3 Backfire-C",
], "H-6J Badger"
"awacs": [ ],
"KJ-2000" "awacs": [
], "KJ-2000"
"tankers": [ ],
"IL-78M" "tankers": [
], "IL-78M"
"frontline_units": [ ],
"BMP-1", "frontline_units": [
"BMP-2", "BMP-1",
"BMP-3", "BMP-2",
"BTR-80", "BMP-3",
"BTR-82A", "BTR-80",
"HQ-7 Launcher", "BTR-82A",
"SA-19 Grison (2K22 Tunguska)", "HQ-7 Launcher",
"T-55A", "SA-19 Grison (2K22 Tunguska)",
"T-72B3 model 2011", "T-55A",
"T-80UD", "T-72B3 model 2011",
"T-90A", "T-80UD",
"Type 04A (ZBD-04A)", "T-90A",
"Type 96B (ZTZ-96B)" "Type 04A (ZBD-04A)",
], "Type 96B (ZTZ-96B)"
"artillery_units": [ ],
"2S19 Msta-S", "artillery_units": [
"2S9 Nona-S", "2S19 Msta-S",
"BM-27 Uragan", "2S9 Nona-S",
"BM-30 Smerch (9M55K5 HE Rockets)" "BM-27 Uragan",
], "BM-30 Smerch (9M55K5 HE Rockets)"
"logistics_units": [ ],
"LUV UAZ-469 Jeep", "logistics_units": [
"Truck Ural-375" "LUV UAZ-469 Jeep",
], "Truck Ural-375"
"infantry_units": [ ],
"Infantry AK-74 Rus", "infantry_units": [
"MANPADS SA-18 Igla \"Grouse\"", "Infantry AK-74 Rus",
"Mortar 2B11 120mm", "MANPADS SA-18 Igla \"Grouse\"",
"Paratrooper AKS", "Mortar 2B11 120mm",
"Paratrooper RPG-16" "Paratrooper AKS",
], "Paratrooper RPG-16"
"missiles": [], ],
"preset_groups": [ "missiles": [],
"SA-2/S-75", "preset_groups": [
"HQ-2", "SA-2/S-75",
"SA-6", "HQ-2",
"SA-11", "SA-6",
"HQ-7", "SA-11",
"SA-10/S-300PS", "HQ-7",
"SA-10B/S-300PS", "SA-10/S-300PS",
"SA-17", "SA-10B/S-300PS",
"SA-12/S-300V", "SA-17",
"SA-20/S-300PMU-1", "SA-12/S-300V",
"SA-20B/S-300PMU-2", "SA-20/S-300PMU-1",
"SA-23/S-300VM", "SA-20B/S-300PMU-2",
"Chinese Navy" "SA-23/S-300VM",
], "Chinese Navy"
"naval_units": [ ],
"Frigate 1135M Rezky", "naval_units": [
"Type 052B Destroyer", "Frigate 1135M Rezky",
"Type 052C Destroyer", "Type 052B Destroyer",
"Corvette 1241.1 Molniya", "Type 052C Destroyer",
"Type 054A Frigate", "Corvette 1241.1 Molniya",
"CV 1143.5 Admiral Kuznetsov", "Type 054A Frigate",
"Type 071 Amphibious Transport Dock" "CV 1143.5 Admiral Kuznetsov",
], "Type 071 Amphibious Transport Dock"
"air_defense_units": [ ],
"EWR 1L13", "air_defense_units": [
"EWR 55G6", "EWR 1L13",
"SAM SA-8 Osa \"Gecko\" TEL", "EWR 55G6",
"SA-9 Strela", "SAM SA-8 Osa \"Gecko\" TEL",
"SA-13 Gopher (9K35 Strela-10M3)", "SA-9 Strela",
"SA-15 Tor", "SA-13 Gopher (9K35 Strela-10M3)",
"SA-19 Grison (2K22 Tunguska)", "SA-15 Tor",
"AAA ZU-23 Closed Emplacement", "SA-19 Grison (2K22 Tunguska)",
"ZU-23 on Ural-375", "AAA ZU-23 Closed Emplacement",
"ZSU-23-4 Shilka" "ZU-23 on Ural-375",
], "ZSU-23-4 Shilka"
"carrier_names": [ ],
"001 Liaoning", "carrier_names": [
"002 Shandong" "001 Liaoning",
], "002 Shandong"
"helicopter_carrier_names": [ ],
"Kunlun Shan", "helicopter_carrier_names": [
"Jinggang Shan", "Kunlun Shan",
"Changbai Shan", "Jinggang Shan",
"Yimeng Shan", "Changbai Shan",
"Longhu Shan", "Yimeng Shan",
"Wuzhi Shan", "Longhu Shan",
"Wudang Shan" "Wuzhi Shan",
], "Wudang Shan"
"requirements": {}, ],
"has_jtac": true, "requirements": {},
"jtac_unit": "WingLoong-I" "has_jtac": true,
"jtac_unit": "WingLoong-I"
} }

View File

@@ -0,0 +1,71 @@
{
"country": "USA",
"name": "USA 1970",
"authors": "Starfire",
"description": "<p>US military during the Vietnam War from 1965 to 1975</p>",
"locales": [
"en_US"
],
"aircrafts": [
"F-14A Tomcat (Block 135-GR Late)",
"F-4C Phantom II",
"F-4B Phantom II",
"F-4E Phantom II",
"F-5E Tiger II",
"A-4E Skyhawk",
"OV-10A Bronco",
"C-101CC Aviojet",
"B-52H Stratofortress",
"C-47 Skytrain",
"C-130",
"UH-1H Iroquois",
"AH-1W SuperCobra",
"OH-58D Kiowa Warrior",
"CH-47D",
"CH-53E"
],
"awacs": [
"E-2C Hawkeye"
],
"tankers": [
"KC-130",
"KC-135 Stratotanker"
],
"frontline_units": [
"M113",
"M163 Vulcan Air Defense System",
"M60A3 \"Patton\""
],
"artillery_units": [
"M109A6 Paladin"
],
"logistics_units": [
"Truck M818 6x6",
"LARC-V"
],
"infantry_units": [
"Infantry M249",
"Infantry M4"
],
"missiles": [],
"preset_groups": [
"Hawk"
],
"naval_units": [
"FFG Oliver Hazard Perry",
"CV-59 Forrestal"
],
"air_defense_units": [
"SAM Hawk SR (AN/MPQ-50)",
"M163 Vulcan Air Defense System",
"M48 Chaparral"
],
"carrier_names": [
"CV-59 Forrestal",
"CV-60 Saratoga",
"CV-61 Ranger",
"CV-62 Independence"
],
"requirements": {},
"doctrine": "coldwar"
}

View File

@@ -106,7 +106,6 @@
"UH-1H Iroquois" "UH-1H Iroquois"
], ],
"awacs": [ "awacs": [
"E-2C Hawkeye",
"E-2D Advanced Hawkeye", "E-2D Advanced Hawkeye",
"E-3A" "E-3A"
], ],

View File

@@ -1,5 +1,5 @@
{ {
"nameInUI": "DCS Dismounts", "nameInUI": "DCS Dismounts (FPS-killer)",
"defaultValue": false, "defaultValue": false,
"specificOptions": [ "specificOptions": [
{ {

File diff suppressed because it is too large Load Diff

View File

@@ -574,10 +574,12 @@ function onWpnEvent(event)
end end
local player = event.initiator local player = event.initiator
targetName = event.target:getTypeName() local targetName = event.target:getTypeName()
local impactPoint = event.target:getPosition().p local impactPoint = event.target:getPosition().p
env.info(weapon.." hit "..targetName) if weapon and targetName then
debugMsg(weapon.." hit "..targetName) env.info(weapon.." hit "..targetName)
debugMsg(weapon.." hit "..targetName)
end
--env.info('Impact point was at: X: ' .. impactPoint.x .. ' Y: ' .. impactPoint.y .. ' Z: ' .. impactPoint.z) --env.info('Impact point was at: X: ' .. impactPoint.x .. ' Y: ' .. impactPoint.y .. ' Z: ' .. impactPoint.z)
if clusterWeaps[weapon] then if clusterWeaps[weapon] then
local ordnance = event.weapon local ordnance = event.weapon

View File

@@ -1,41 +1,42 @@
class: Helicopter class: Helicopter
always_keeps_gun: true always_keeps_gun: true
lha_capable: true lha_capable: true
cabin_size: 0 # Can not transport troops cabin_size: 0 # Can not transport troops
can_carry_crates: false # Can not carry crates can_carry_crates: false # Can not carry crates
description: description:
The legendary 'Apache' is an US twin-turboshaft attack helicopter for The legendary 'Apache' is an US twin-turboshaft attack helicopter for
a crew of two. It features a nose-mounted sensor suite for target acquisition and a crew of two. It features a nose-mounted sensor suite for target acquisition and
night vision systems. It is armed with a 30 mm (1.18 in) M230 chain gun carried night vision systems. It is armed with a 30 mm (1.18 in) M230 chain gun carried
between the main landing gear, under the aircraft's forward fuselage, and four hardpoints between the main landing gear, under the aircraft's forward fuselage, and four hardpoints
mounted on stub-wing pylons for carrying armament and stores, typically a mixture mounted on stub-wing pylons for carrying armament and stores, typically a mixture
of AGM-114 Hellfire missiles and Hydra 70 rocket pods. The AH-64 has significant of AGM-114 Hellfire missiles and Hydra 70 rocket pods. The AH-64 has significant
systems redundancy to improve combat survivability. American AH-64s have served systems redundancy to improve combat survivability. American AH-64s have served
in conflicts in Panama, the Persian Gulf, Kosovo, Afghanistan, and Iraq. Israel in conflicts in Panama, the Persian Gulf, Kosovo, Afghanistan, and Iraq. Israel
used the Apache in its military conflicts in Lebanon and the Gaza Strip. British used the Apache in its military conflicts in Lebanon and the Gaza Strip. British
and Dutch Apaches have seen deployments in wars in Afghanistan and Iraq. and Dutch Apaches have seen deployments in wars in Afghanistan and Iraq.
introduced: 2003 introduced: 2003
manufacturer: Boeing manufacturer: Boeing
origin: USA origin: USA
price: 20 price: 20
role: Attack role: Attack
variants: variants:
AH-64D Apache Longbow: {} AH-64D Apache Longbow: {}
radios: radios:
# DCS uses the 2nd Radio AN/ARC-164 (UHF) as the main intra flight for the Apache # DCS uses the 2nd Radio AN/ARC-164 (UHF) as the main intra flight for the Apache
# so we use this Radio for Intra and Inter Flight for now # so we use this Radio for Intra and Inter Flight for now
# The radio frequencies set in the mission editor are in the current state of Early # The radio frequencies set in the mission editor are in the current state of Early
# access not used for radio presets. Only the flight frequency is used. Any other # access not used for radio presets. Only the flight frequency is used. Any other
# frequency has to be entered manually atm. # frequency has to be entered manually atm.
intra_flight: AN/ARC-186(V) AM intra_flight: AN/ARC-186(V) AM
inter_flight: AN/ARC-164 inter_flight: AN/ARC-164
channels: channels:
type: common type: common
namer: apache namer: apache
intra_flight_radio_index: 1 intra_flight_radio_index: 1
inter_flight_radio_index: 2 inter_flight_radio_index: 2
tasks: tasks:
BAI: 510 BAI: 510
CAS: 510 CAS: 510
Escort: 100 DEAD: 115
OCA/Aircraft: 510 Escort: 100
OCA/Aircraft: 510

View File

@@ -1,31 +1,32 @@
class: Helicopter class: Helicopter
always_keeps_gun: true always_keeps_gun: true
carrier_capable: true carrier_capable: true
description: description:
"The Ka-50 Black Shark (NATO reporting name: Hokum) is a unique and deadly "The Ka-50 Black Shark (NATO reporting name: Hokum) is a unique and deadly
single-seat, Russian attack helicopter that has seen combat in the Northern Caucasus. single-seat, Russian attack helicopter that has seen combat in the Northern Caucasus.
It combines a high performance dual rotor system with a deadly weapons payload of It combines a high performance dual rotor system with a deadly weapons payload of
guided missiles, rockets, bombs, and a 30mm cannon. The Ka-50 is also unique in guided missiles, rockets, bombs, and a 30mm cannon. The Ka-50 is also unique in
that it has an ejection seat." that it has an ejection seat."
introduced: 1995 introduced: 1995
lha_capable: true lha_capable: true
cabin_size: 0 # Can not transport troops cabin_size: 0 # Can not transport troops
can_carry_crates: true can_carry_crates: true
manufacturer: Kamov manufacturer: Kamov
origin: USSR/Russia origin: USSR/Russia
price: 20 price: 20
role: Attack role: Attack
variants: variants:
Ka-50 Hokum: {} Ka-50 Hokum: {}
radios: radios:
intra_flight: R-800L1 intra_flight: R-800L1
inter_flight: R-800L1 inter_flight: R-800L1
# The R-800L1 doesn't have preset channels, and the other radio is for # The R-800L1 doesn't have preset channels, and the other radio is for
# communications with FAC and ground units, which don't currently have # communications with FAC and ground units, which don't currently have
# radios assigned, so no channels to configure. # radios assigned, so no channels to configure.
kneeboard_units: "metric" kneeboard_units: "metric"
tasks: tasks:
BAI: 430 BAI: 430
CAS: 430 CAS: 430
Escort: 90 DEAD: 113
OCA/Aircraft: 430 Escort: 90
OCA/Aircraft: 430

View File

@@ -1,32 +1,33 @@
class: Helicopter class: Helicopter
always_keeps_gun: true always_keeps_gun: true
carrier_capable: true carrier_capable: true
description: description:
"The Ka-50 Black Shark (NATO reporting name: Hokum) is a unique and deadly "The Ka-50 Black Shark (NATO reporting name: Hokum) is a unique and deadly
single-seat, Russian attack helicopter that has seen combat in the Northern Caucasus. single-seat, Russian attack helicopter that has seen combat in the Northern Caucasus.
It combines a high performance dual rotor system with a deadly weapons payload of It combines a high performance dual rotor system with a deadly weapons payload of
guided missiles, rockets, bombs, and a 30mm cannon. The Ka-50 is also unique in guided missiles, rockets, bombs, and a 30mm cannon. The Ka-50 is also unique in
that it has an ejection seat. The Black Shark III can also carry A-A Igla missiles." that it has an ejection seat. The Black Shark III can also carry A-A Igla missiles."
introduced: 1995 introduced: 1995
lha_capable: true lha_capable: true
cabin_size: 0 # Can not transport troops cabin_size: 0 # Can not transport troops
can_carry_crates: true can_carry_crates: true
manufacturer: Kamov manufacturer: Kamov
origin: USSR/Russia origin: USSR/Russia
price: 20 price: 20
role: Attack role: Attack
variants: variants:
Ka-50 Hokum III: {} Ka-50 Hokum III: {}
Ka-50 Hokum (Blackshark 3): {} # for compatibility with Liberation Ka-50 Hokum (Blackshark 3): {} # for compatibility with Liberation
radios: radios:
intra_flight: R-800L1 intra_flight: R-800L1
inter_flight: R-800L1 inter_flight: R-800L1
# The R-800L1 doesn't have preset channels, and the other radio is for # The R-800L1 doesn't have preset channels, and the other radio is for
# communications with FAC and ground units, which don't currently have # communications with FAC and ground units, which don't currently have
# radios assigned, so no channels to configure. # radios assigned, so no channels to configure.
kneeboard_units: "metric" kneeboard_units: "metric"
tasks: tasks:
BAI: 440 BAI: 440
CAS: 440 CAS: 440
Escort: 100 DEAD: 113
OCA/Aircraft: 440 Escort: 100
OCA/Aircraft: 440

View File

@@ -1,24 +1,27 @@
carrier_capable: true carrier_capable: true
description: description:
The Lockheed S-3 Viking is a 4-crew, twin-engine turbofan-powered jet The Lockheed S-3 Viking is a 4-crew, twin-engine turbofan-powered jet
aircraft that was used by the U.S. Navy (USN) primarily for anti-submarine warfare. aircraft that was used by the U.S. Navy (USN) primarily for anti-submarine warfare.
In the late 1990s, the S-3B's mission focus shifted to surface warfare and aerial In the late 1990s, the S-3B's mission focus shifted to surface warfare and aerial
refueling. The Viking also provided electronic warfare and surface surveillance refueling. The Viking also provided electronic warfare and surface surveillance
capabilities to a carrier battle group. A carrier-based, subsonic, all-weather, capabilities to a carrier battle group. A carrier-based, subsonic, all-weather,
long-range, multi-mission aircraft, it carried automated weapon systems and was long-range, multi-mission aircraft, it carried automated weapon systems and was
capable of extended missions with in-flight refueling. Because of its characteristic capable of extended missions with in-flight refueling. Because of its characteristic
sound, it was nicknamed the "War Hoover" after the vacuum cleaner brand. The S-3 sound, it was nicknamed the "War Hoover" after the vacuum cleaner brand. The S-3
was phased out from front-line fleet service aboard aircraft carriers in January was phased out from front-line fleet service aboard aircraft carriers in January
2009, with its missions taken over by aircraft like the P-3C Orion, P-8 Poseidon, 2009, with its missions taken over by aircraft like the P-3C Orion, P-8 Poseidon,
Sikorsky SH-60 Seahawk and Boeing F/A-18E/F Super Hornet Sikorsky SH-60 Seahawk and Boeing F/A-18E/F Super Hornet
introduced: 1984 introduced: 1984
manufacturer: Lockheed manufacturer: Lockheed
origin: USA origin: USA
price: 10 price: 10
role: Carrier-based Attack role: Carrier-based Attack
variants: variants:
S-3B Viking: {} S-3B Viking: {}
tasks: tasks:
Anti-ship: 350 Anti-ship: 350
OCA/Aircraft: 330 BAI: 570
Strike: 370 CAS: 570
DEAD: 200
OCA/Aircraft: 330
Strike: 370