Merge remote-tracking branch 'khopa/develop' into helipads

This commit is contained in:
Khopa 2021-06-10 13:01:24 +02:00
commit e00951e5b9
96 changed files with 2054 additions and 281 deletions

View File

@ -4,6 +4,10 @@ Saves from 3.x are not compatible with 4.0.
## Features/Improvements
* **[Flight Planner]** Added ability to plan Tankers.
* **[Campaign AI]** AI will plan Tanker flights.
* **[Factions]** Added more tankers to factions.
## Fixes
# 3.0.0

View File

@ -129,19 +129,6 @@ from dcs.ships import (
Tanker_Elnya_160,
ship_map,
)
from dcs.task import (
AWACS,
CAP,
CAS,
CargoTransportation,
Embarking,
MainTask,
Nothing,
PinpointStrike,
Reconnaissance,
Refueling,
Transport,
)
from dcs.terrain.terrain import Airport
from dcs.unit import Ship, Unit, Vehicle
from dcs.unitgroup import ShipGroup, StaticGroup
@ -150,7 +137,6 @@ from dcs.vehicles import (
AirDefence,
Armor,
Artillery,
Carriage,
Infantry,
Unarmed,
vehicle_map,
@ -164,6 +150,7 @@ from game.factions.faction_loader import FactionLoader
from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.hercules.hercules import Hercules
from pydcs_extensions.jas39.jas39 import JAS39Gripen, JAS39Gripen_AG
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.su57.su57 import Su_57
@ -174,6 +161,8 @@ plane_map["F-22A"] = F_22A
plane_map["MB-339PAN"] = MB_339PAN
plane_map["Su-57"] = Su_57
plane_map["Hercules"] = Hercules
plane_map["JAS39Gripen"] = JAS39Gripen
plane_map["JAS39Gripen_AG"] = JAS39Gripen_AG
vehicle_map["FieldHL"] = frenchpack._FIELD_HIDE
vehicle_map["HARRIERH"] = frenchpack._FIELD_HIDE_SMALL
@ -405,6 +394,7 @@ PRICES = {
F_22A: 40,
Tornado_IDS: 20,
Tornado_GR4: 20,
JAS39Gripen: 26,
# bomber
Su_17M4: 10,
Su_25: 15,
@ -418,6 +408,7 @@ PRICES = {
A_10C: 22,
A_10C_2: 24,
S_3B: 10,
JAS39Gripen_AG: 26,
# heli
Ka_50: 13,
SA342M: 8,
@ -560,6 +551,12 @@ PRICES = {
Armor.Car_Daimler_Armored: 8,
Armor.LT_Mk_VII_Tetrarch: 8,
Unarmed.Tractor_M4_Hi_Speed: 2,
Unarmed.Carrier_Sd_Kfz_7_Tractor: 1,
Unarmed.LUV_Kettenrad: 1,
Unarmed.LUV_Kubelwagen_82: 1,
Unarmed.Truck_Opel_Blitz: 1,
Unarmed.Truck_Bedford: 1,
Unarmed.Truck_GMC_Jimmy_6x6_Truck: 1,
# ship
CV_1143_5_Admiral_Kuznetsov: 100,
CVN_74_John_C__Stennis: 100,
@ -801,6 +798,7 @@ CARRIER_CAPABLE = [
Su_33,
A_4E_C,
S_3B,
S_3B_Tanker,
E_2C,
UH_1H,
Mi_8MT,

View File

@ -167,7 +167,9 @@ class Faction:
faction.awacs = load_all_aircraft(json.get("awacs", []))
faction.tankers = load_all_aircraft(json.get("tankers", []))
faction.aircrafts = list(set(faction.aircrafts + faction.awacs))
faction.aircrafts = list(
set(faction.aircrafts + faction.awacs + faction.tankers)
)
faction.frontline_units = load_all_vehicles(json.get("frontline_units", []))
faction.artillery_units = load_all_vehicles(json.get("artillery_units", []))

View File

@ -375,6 +375,7 @@ class Operation:
cls.game.settings,
cls.game,
cls.radio_registry,
cls.tacan_registry,
cls.unit_map,
air_support=cls.airsupportgen.air_support,
)
@ -399,6 +400,7 @@ class Operation:
@classmethod
def _generate_ground_conflicts(cls) -> None:
"""For each frontline in the Operation, generate the ground conflicts and JTACs"""
cls.jtacs = []
for front_line in cls.game.theater.conflicts():
player_cp = front_line.blue_cp
enemy_cp = front_line.red_cp

View File

@ -44,6 +44,7 @@ class Settings:
automate_aircraft_reinforcements: bool = False
restrict_weapons_by_date: bool = False
disable_legacy_aewc: bool = True
disable_legacy_tanker: bool = True
generate_dark_kneeboard: bool = False
invulnerable_player_pilots: bool = True
auto_ato_behavior: AutoAtoBehavior = AutoAtoBehavior.Default

View File

@ -850,6 +850,7 @@ class Airfield(ControlPoint):
if self.is_friendly(for_player):
yield from [
FlightType.AEWC,
FlightType.REFUELING,
# TODO: FlightType.INTERCEPTION
# TODO: FlightType.LOGISTICS
]
@ -999,7 +1000,10 @@ class Carrier(NavalControlPoint):
yield from super().mission_types(for_player)
if self.is_friendly(for_player):
yield FlightType.AEWC
yield from [
FlightType.AEWC,
FlightType.REFUELING,
]
def capture(self, game: Game, for_player: bool) -> None:
raise RuntimeError("Carriers cannot be captured")

View File

@ -81,6 +81,7 @@ class FrontLine(MissionTarget):
yield from [
FlightType.CAS,
FlightType.AEWC,
FlightType.REFUELING
# TODO: FlightType.TROOP_TRANSPORT
# TODO: FlightType.EVAC
]

View File

@ -39,10 +39,12 @@ from dcs.planes import (
Su_33,
Tu_22M3,
)
from dcs.planes import IL_78M
from dcs.point import MovingPoint, PointAction
from dcs.task import (
AWACS,
AWACSTaskAction,
ActivateBeaconCommand,
AntishipStrike,
AttackGroup,
Bombing,
@ -61,8 +63,10 @@ from dcs.task import (
OptReactOnThreat,
OptRestrictJettison,
OrbitAction,
Refueling,
RunwayAttack,
StartCommand,
Tanker,
Targets,
Transport,
WeaponType,
@ -80,7 +84,7 @@ from game.data.weapons import Pylon
from game.db import GUN_RELIANT_AIRFRAMES
from game.factions.faction import Faction
from game.settings import Settings
from game.squadrons import Pilot, Squadron
from game.squadrons import Pilot
from game.theater.controlpoint import (
Airfield,
ControlPoint,
@ -103,13 +107,15 @@ from gen.flights.flight import (
)
from gen.radios import MHz, Radio, RadioFrequency, RadioRegistry, get_radio
from gen.runways import RunwayData
from .airsupportgen import AirSupport, AwacsInfo
from gen.tacan import TacanBand, TacanRegistry
from .airsupportgen import AirSupport, AwacsInfo, TankerInfo
from .callsigns import callsign_for_support_unit
from .flights.flightplan import (
AwacsFlightPlan,
CasFlightPlan,
LoiterFlightPlan,
PatrollingFlightPlan,
RefuelingFlightPlan,
SweepFlightPlan,
)
from .flights.traveltime import GroundSpeed, TotEstimator
@ -665,10 +671,16 @@ AIRCRAFT_DATA: Dict[str, AircraftData] = {
channel_allocator=None,
channel_namer=SCR522ChannelNamer,
),
"JAS39Gripen": AircraftData(
inter_flight_radio=get_radio("R&S Series 6000"),
intra_flight_radio=get_radio("R&S Series 6000"),
channel_allocator=None,
),
}
AIRCRAFT_DATA["A-10C_2"] = AIRCRAFT_DATA["A-10C"]
AIRCRAFT_DATA["P-51D-30-NA"] = AIRCRAFT_DATA["P-51D"]
AIRCRAFT_DATA["P-47D-30"] = AIRCRAFT_DATA["P-51D"]
AIRCRAFT_DATA["JAS39Gripen_AG"] = AIRCRAFT_DATA["JAS39Gripen"]
class AircraftConflictGenerator:
@ -678,6 +690,7 @@ class AircraftConflictGenerator:
settings: Settings,
game: Game,
radio_registry: RadioRegistry,
tacan_registry: TacanRegistry,
unit_map: UnitMap,
air_support: AirSupport,
) -> None:
@ -685,6 +698,7 @@ class AircraftConflictGenerator:
self.game = game
self.settings = settings
self.radio_registry = radio_registry
self.tacan_registy = tacan_registry
self.unit_map = unit_map
self.flights: List[FlightData] = []
self.air_support = air_support
@ -818,7 +832,10 @@ class AircraftConflictGenerator:
OptReactOnThreat(OptReactOnThreat.Values.EvadeFire)
)
if flight.flight_type == FlightType.AEWC:
if (
flight.flight_type == FlightType.AEWC
or flight.flight_type == FlightType.REFUELING
):
channel = self.radio_registry.alloc_uhf()
else:
channel = self.get_intra_flight_channel(unit_type)
@ -873,6 +890,24 @@ class AircraftConflictGenerator:
)
)
if isinstance(flight.flight_plan, RefuelingFlightPlan):
callsign = callsign_for_support_unit(group)
tacan = self.tacan_registy.alloc_for_band(TacanBand.Y)
variant = db.unit_type_name(flight.flight_plan.flight.unit_type)
self.air_support.tankers.append(
TankerInfo(
group_name=str(group.name),
callsign=callsign,
variant=variant,
freq=channel,
tacan=tacan,
start_time=flight.flight_plan.patrol_start_time,
end_time=flight.flight_plan.patrol_end_time,
blue=flight.departure.captured,
)
)
def _generate_at_airport(
self,
name: str,
@ -1477,6 +1512,32 @@ class AircraftConflictGenerator:
group.points[0].tasks.append(AWACSTaskAction())
def configure_refueling(
self,
group: FlyingGroup,
package: Package,
flight: Flight,
dynamic_runways: Dict[str, RunwayData],
) -> None:
group.task = Refueling.name
if not isinstance(flight.flight_plan, RefuelingFlightPlan):
logging.error(
f"Cannot configure racetrack refueling tasks for {flight} because it "
"does not have an racetrack refueling flight plan."
)
return
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.WeaponHold,
restrict_jettison=True,
)
def configure_escort(
self,
group: FlyingGroup,
@ -1555,6 +1616,8 @@ class AircraftConflictGenerator:
self.configure_sweep(group, package, flight, dynamic_runways)
elif flight_type == FlightType.AEWC:
self.configure_awacs(group, package, flight, dynamic_runways)
elif flight_type == FlightType.REFUELING:
self.configure_refueling(group, package, flight, dynamic_runways)
elif flight_type in [FlightType.CAS, FlightType.BAI]:
self.configure_cas(group, package, flight, dynamic_runways)
elif flight_type == FlightType.DEAD:
@ -1622,7 +1685,7 @@ class AircraftConflictGenerator:
for idx, point in enumerate(filtered_points):
PydcsWaypointBuilder.for_waypoint(
point, group, package, flight, self.m
point, group, package, flight, self.m, self.air_support
).build()
# Set here rather than when the FlightData is created so they waypoints
@ -1696,12 +1759,14 @@ class PydcsWaypointBuilder:
package: Package,
flight: Flight,
mission: Mission,
air_support: AirSupport,
) -> None:
self.waypoint = waypoint
self.group = group
self.package = package
self.flight = flight
self.mission = mission
self.air_support = air_support
def build(self) -> MovingPoint:
waypoint = self.group.add_waypoint(
@ -1737,6 +1802,7 @@ class PydcsWaypointBuilder:
package: Package,
flight: Flight,
mission: Mission,
air_support: AirSupport,
) -> PydcsWaypointBuilder:
builders = {
FlightWaypointType.DROP_OFF: CargoStopBuilder,
@ -1756,7 +1822,7 @@ class PydcsWaypointBuilder:
FlightWaypointType.PICKUP: CargoStopBuilder,
}
builder = builders.get(waypoint.waypoint_type, DefaultWaypointBuilder)
return builder(waypoint, group, package, flight, mission)
return builder(waypoint, group, package, flight, mission, air_support)
def _viggen_client_tot(self) -> bool:
"""Viggen player aircraft consider any waypoint with a TOT set to be a target ("M") waypoint.
@ -2139,6 +2205,8 @@ class RaceTrackBuilder(PydcsWaypointBuilder):
# is their first priority and they will not engage any targets because
# they're fully focused on orbiting. If the STE task is first, they will
# engage targets if available and orbit if they find nothing to shoot.
if self.flight.flight_type is FlightType.REFUELING:
self.configure_refueling_actions(waypoint)
# TODO: Move the properties of this task into the flight plan?
# CAP is the only current user of this so it's not a big deal, but might
@ -2153,17 +2221,48 @@ class RaceTrackBuilder(PydcsWaypointBuilder):
)
)
racetrack = ControlledTask(
OrbitAction(
# TODO: Set orbit speeds for all race tracks and remove this special case.
if isinstance(flight_plan, RefuelingFlightPlan):
orbit = OrbitAction(
altitude=waypoint.alt,
pattern=OrbitAction.OrbitPattern.RaceTrack,
speed=int(flight_plan.patrol_speed.kph),
)
else:
orbit = OrbitAction(
altitude=waypoint.alt, pattern=OrbitAction.OrbitPattern.RaceTrack
)
)
racetrack = ControlledTask(orbit)
self.set_waypoint_tot(waypoint, flight_plan.patrol_start_time)
racetrack.stop_after_time(int(flight_plan.patrol_end_time.total_seconds()))
waypoint.add_task(racetrack)
return waypoint
def configure_refueling_actions(self, waypoint: MovingPoint) -> None:
waypoint.add_task(Tanker())
if self.flight.unit_type != IL_78M:
tanker_info = self.air_support.tankers[-1]
tacan = tanker_info.tacan
tacan_callsign = {
"Texaco": "TEX",
"Arco": "ARC",
"Shell": "SHL",
}.get(tanker_info.callsign)
waypoint.add_task(
ActivateBeaconCommand(
tacan.number,
tacan.band.value,
tacan_callsign,
bearing=True,
unit_id=self.group.units[0].id,
aa=True,
)
)
class RaceTrackEndBuilder(PydcsWaypointBuilder):
def build(self) -> MovingPoint:

View File

@ -674,7 +674,7 @@ AIRFIELD_DATA = {
vor=("DAN", MHz(108, 400)),
atc=AtcData(MHz(3, 900), MHz(38, 700), MHz(122, 100), MHz(360, 100)),
ils={
"50": ("IDAN", MHz(109, 300)),
"05": ("IDAN", MHz(109, 300)),
"23": ("DANM", MHz(111, 700)),
},
),

View File

@ -54,6 +54,8 @@ class TankerInfo:
variant: str
freq: RadioFrequency
tacan: TacanChannel
start_time: Optional[timedelta]
end_time: Optional[timedelta]
blue: bool
@ -100,6 +102,8 @@ class AirSupportConflictGenerator:
else self.conflict.red_cp
)
if not self.game.settings.disable_legacy_tanker:
fallback_tanker_number = 0
for i, tanker_unit_type in enumerate(

View File

@ -168,9 +168,10 @@ class Package:
# likely to be the main task than others. For example, a package with
# only CAP flights is a CAP package, a flight with CAP and strike is a
# strike package, a flight with CAP and DEAD is a DEAD package, and a
# flight with strike and SEAD is an OCA/Strike package. The type of
# package is determined by the highest priority flight in the package.
task_priorities = [
# flight with strike and SEAD is an OCA/Strike package. This list defines the
# priority order for package task names. The package's primary task will be the
# first task in this list that matches a flight in the package.
tasks_by_priority = [
FlightType.CAS,
FlightType.STRIKE,
FlightType.ANTISHIP,
@ -183,10 +184,11 @@ class Package:
FlightType.TARCAP,
FlightType.BARCAP,
FlightType.AEWC,
FlightType.REFUELING,
FlightType.SWEEP,
FlightType.ESCORT,
]
for task in task_priorities:
for task in tasks_by_priority:
if flight_counts[task]:
return task

View File

@ -1,6 +1,7 @@
from __future__ import annotations
import logging
import math
import operator
import random
from collections import defaultdict
@ -524,6 +525,24 @@ class ObjectiveFinder:
raise RuntimeError("Found no friendly control points. You probably lost.")
return farthest
def closest_friendly_control_point(self) -> ControlPoint:
"""Finds the friendly control point that is closest to any threats."""
threat_zones = self.game.threat_zone_for(not self.is_player)
closest = None
min_distance = meters(math.inf)
for cp in self.friendly_control_points():
if isinstance(cp, OffMapSpawn):
continue
distance = threat_zones.distance_to_threat(cp.position)
if distance < min_distance:
closest = cp
min_distance = distance
if closest is None:
raise RuntimeError("Found no friendly control points. You probably lost.")
return closest
def enemy_control_points(self) -> Iterator[ControlPoint]:
"""Iterates over all enemy control points."""
return (
@ -582,6 +601,7 @@ class CoalitionMissionPlanner:
MAX_SEAD_RANGE = nautical_miles(150)
MAX_STRIKE_RANGE = nautical_miles(150)
MAX_AWEC_RANGE = nautical_miles(200)
MAX_TANKER_RANGE = nautical_miles(200)
def __init__(self, game: Game, is_player: bool) -> None:
self.game = game
@ -628,6 +648,11 @@ class CoalitionMissionPlanner:
asap=True,
)
yield ProposedMission(
self.objective_finder.closest_friendly_control_point(),
[ProposedFlight(FlightType.REFUELING, 1, self.MAX_TANKER_RANGE)],
)
# Find friendly CPs within 100 nmi from an enemy airfield, plan CAP.
for cp in self.objective_finder.vulnerable_control_points():
# Plan CAP in such a way, that it is established during the whole desired mission length

View File

@ -51,10 +51,13 @@ from dcs.planes import (
F_5E_3,
F_86F_Sabre,
IL_76MD,
I_16,
IL_78M,
JF_17,
J_11A,
Ju_88A4,
KC130,
KC135MPRS,
KC_135,
KJ_2000,
L_39ZA,
MQ_9_Reaper,
@ -77,6 +80,7 @@ from dcs.planes import (
P_51D_30_NA,
RQ_1A_Predator,
S_3B,
S_3B_Tanker,
SpitfireLFMkIX,
SpitfireLFMkIXCW,
Su_17M4,
@ -104,6 +108,7 @@ from gen.flights.flight import FlightType
from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.hercules.hercules import Hercules
from pydcs_extensions.jas39.jas39 import JAS39Gripen, JAS39Gripen_AG
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.su57.su57 import Su_57
@ -134,6 +139,7 @@ CAP_CAPABLE = [
FA_18C_hornet,
F_16A,
F_4E,
JAS39Gripen,
JF_17,
MiG_23MLD,
MiG_21Bis,
@ -174,6 +180,7 @@ CAS_CAPABLE = [
FA_18C_hornet,
Tornado_GR4,
Tornado_IDS,
JAS39Gripen_AG,
JF_17,
AV8BNA,
A_10A,
@ -242,6 +249,7 @@ SEAD_CAPABLE = [
A_4E_C,
F_14B,
F_14A_135_GR,
JAS39Gripen_AG,
AV8BNA,
Su_24M,
Su_17M4,
@ -257,6 +265,7 @@ DEAD_CAPABLE = [
AJS37,
F_14B,
F_14A_135_GR,
JAS39Gripen_AG,
B_1B,
B_52H,
Tu_160,
@ -292,6 +301,7 @@ STRIKE_CAPABLE = [
F_16A,
F_14B,
F_14A_135_GR,
JAS39Gripen_AG,
Tornado_IDS,
Su_17M4,
Su_24MR,
@ -342,6 +352,7 @@ ANTISHIP_CAPABLE = [
AJS37,
Tu_22M3,
FA_18C_hornet,
JAS39Gripen_AG,
Su_24M,
Su_17M4,
JF_17,
@ -394,6 +405,15 @@ AEWC_CAPABLE = [
KJ_2000,
]
# Priority is given to the tankers that can carry the most fuel.
REFUELING_CAPABALE = [
KC_135,
KC135MPRS,
IL_78M,
KC130,
S_3B_Tanker,
]
def aircraft_for_task(task: FlightType) -> List[Type[FlyingType]]:
cap_missions = (FlightType.BARCAP, FlightType.TARCAP, FlightType.SWEEP)
@ -421,6 +441,8 @@ def aircraft_for_task(task: FlightType) -> List[Type[FlyingType]]:
return CAP_CAPABLE
elif task == FlightType.AEWC:
return AEWC_CAPABLE
elif task == FlightType.REFUELING:
return REFUELING_CAPABALE
elif task == FlightType.TRANSPORT:
return TRANSPORT_CAPABLE
else:

View File

@ -69,6 +69,7 @@ class FlightType(Enum):
AEWC = "AEW&C"
TRANSPORT = "Transport"
SEAD_ESCORT = "SEAD Escort"
REFUELING = "Refueling"
def __str__(self) -> str:
return self.value

View File

@ -16,12 +16,21 @@ from functools import cached_property
from typing import Iterator, List, Optional, Set, TYPE_CHECKING, Tuple
from dcs.mapping import Point
from dcs.planes import E_3A, E_2C, A_50, KJ_2000
from dcs.planes import (
E_3A,
E_2C,
A_50,
IL_78M,
KC130,
KC135MPRS,
KC_135,
KJ_2000,
S_3B_Tanker,
)
from dcs.unit import Unit
from shapely.geometry import Point as ShapelyPoint
from game.data.doctrine import Doctrine
from game.squadrons import Pilot
from game.theater import (
Airfield,
ControlPoint,
@ -31,7 +40,7 @@ from game.theater import (
TheaterGroundObject,
)
from game.theater.theatergroundobject import EwrGroundObject
from game.utils import Distance, Speed, feet, meters, nautical_miles
from game.utils import Distance, Speed, feet, meters, nautical_miles, knots
from .closestairfields import ObjectiveDistanceCache
from .flight import Flight, FlightType, FlightWaypoint, FlightWaypointType
from .traveltime import GroundSpeed, TravelTime
@ -769,6 +778,28 @@ class AwacsFlightPlan(LoiterFlightPlan):
return self.push_time
@dataclass(frozen=True)
class RefuelingFlightPlan(PatrollingFlightPlan):
takeoff: FlightWaypoint
land: FlightWaypoint
divert: Optional[FlightWaypoint]
bullseye: FlightWaypoint
#: Racetrack speed.
patrol_speed: Speed
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.takeoff
yield from self.nav_to
yield self.patrol_start
yield self.patrol_end
yield from self.nav_from
yield self.land
if self.divert is not None:
yield self.divert
yield self.bullseye
@dataclass(frozen=True)
class AirliftFlightPlan(FlightPlan):
takeoff: FlightWaypoint
@ -919,6 +950,8 @@ class FlightPlanBuilder:
return self.generate_aewc(flight)
elif task == FlightType.TRANSPORT:
return self.generate_transport(flight)
elif task == FlightType.REFUELING:
return self.generate_refueling_racetrack(flight)
raise PlanningError(f"{task} flight plan generation not implemented")
def regenerate_package_waypoints(self) -> None:
@ -1612,6 +1645,88 @@ class FlightPlanBuilder:
bullseye=builder.bullseye(),
)
def generate_refueling_racetrack(self, flight: Flight) -> RefuelingFlightPlan:
location = self.package.target
closest_boundary = self.threat_zones.closest_boundary(location.position)
heading_to_threat_boundary = location.position.heading_between_point(
closest_boundary
)
distance_to_threat = meters(
location.position.distance_to_point(closest_boundary)
)
orbit_heading = heading_to_threat_boundary
# Station 70nm outside the threat zone.
threat_buffer = nautical_miles(70)
if self.threat_zones.threatened(location.position):
orbit_distance = distance_to_threat + threat_buffer
else:
orbit_distance = distance_to_threat - threat_buffer
racetrack_center = location.position.point_from_heading(
orbit_heading, orbit_distance.meters
)
racetrack_half_distance = Distance.from_nautical_miles(20).meters
racetrack_start = racetrack_center.point_from_heading(
orbit_heading + 90, racetrack_half_distance
)
racetrack_end = racetrack_center.point_from_heading(
orbit_heading - 90, racetrack_half_distance
)
builder = WaypointBuilder(flight, self.game, self.is_player)
tanker_type = flight.unit_type
if tanker_type is KC_135:
# ~300 knots IAS.
speed = knots(445)
altitude = feet(24000)
elif tanker_type is KC135MPRS:
# ~300 knots IAS.
speed = knots(440)
altitude = feet(23000)
elif tanker_type is KC130:
# ~210 knots IAS, roughly the max for the KC-130 at altitude.
speed = knots(370)
altitude = feet(22000)
elif tanker_type is S_3B_Tanker:
# ~265 knots IAS.
speed = knots(320)
altitude = feet(12000)
elif tanker_type is IL_78M:
# ~280 knots IAS.
speed = knots(400)
altitude = feet(21000)
else:
# ~280 knots IAS.
speed = knots(400)
altitude = feet(21000)
racetrack = builder.race_track(racetrack_start, racetrack_end, altitude)
return RefuelingFlightPlan(
package=self.package,
flight=flight,
takeoff=builder.takeoff(flight.departure),
nav_to=builder.nav_path(
flight.departure.position, racetrack_start, altitude
),
nav_from=builder.nav_path(racetrack_end, flight.arrival.position, altitude),
patrol_start=racetrack[0],
patrol_end=racetrack[1],
land=builder.land(flight.arrival),
divert=builder.divert(flight.divert),
bullseye=builder.bullseye(),
patrol_duration=timedelta(hours=1),
patrol_speed=speed,
# TODO: Factor out a common base of the combat and non-combat race-tracks.
# No harm in setting this, but we ought to clean up a bit.
engagement_distance=meters(0),
)
@staticmethod
def target_waypoint(
flight: Flight, builder: WaypointBuilder, target: StrikeTarget

View File

@ -22,17 +22,19 @@ class CombatGroupRole(Enum):
LOGI = 6
INFANTRY = 7
ATGM = 8
RECON = 9
DISTANCE_FROM_FRONTLINE = {
CombatGroupRole.TANK: (2200, 3200),
CombatGroupRole.APC: (7500, 8500),
CombatGroupRole.APC: (2700, 3700),
CombatGroupRole.IFV: (2700, 3700),
CombatGroupRole.ARTILLERY: (16000, 18000),
CombatGroupRole.SHORAD: (12000, 13000),
CombatGroupRole.SHORAD: (5000, 8000),
CombatGroupRole.LOGI: (18000, 20000),
CombatGroupRole.INFANTRY: (2800, 3300),
CombatGroupRole.ATGM: (5200, 6200),
CombatGroupRole.RECON: (2000, 3000),
}
GROUP_SIZES_BY_COMBAT_STANCE = {
@ -74,6 +76,7 @@ class GroundPlanner:
self.atgm_group: List[CombatGroup] = []
self.logi_groups: List[CombatGroup] = []
self.shorad_groups: List[CombatGroup] = []
self.recon_groups: List[CombatGroup] = []
self.units_per_cp: Dict[int, List[CombatGroup]] = {}
for cp in self.connected_enemy_cp:
@ -115,6 +118,9 @@ class GroundPlanner:
elif unit_type in GroundUnitClass.Shorads:
collection = self.shorad_groups
role = CombatGroupRole.SHORAD
elif unit_type in GroundUnitClass.Recon:
collection = self.recon_groups
role = CombatGroupRole.RECON
else:
logging.warning(
f"Unused front line vehicle at base {unit_type}: unknown unit class"

View File

@ -134,6 +134,7 @@ RADIOS: List[Radio] = [
Radio("AN/ARC-51BX", MHz(225), MHz(400), step=kHz(50)),
Radio("AN/ARC-131", MHz(30), MHz(76), step=kHz(50)),
Radio("AN/ARC-134", MHz(116), MHz(150), step=kHz(25)),
Radio("R&S Series 6000", MHz(100), MHz(156), step=kHz(25)),
]

View File

@ -0,0 +1,476 @@
from dcs import task
from dcs.planes import PlaneType
from dcs.weapons_data import Weapons
from pydcs_extensions.weapon_injector import inject_weapons
class JAS39GripenWeapons:
JAS_ARAKM70BAP = {
"clsid": "JAS_ARAKM70BAP",
"name": "ARAK M70B AP",
"weight": 372.2,
}
JAS_ARAKM70BHE = {
"clsid": "JAS_ARAKM70BHE",
"name": "ARAK M70B HE",
"weight": 372.2,
}
JAS_BK90 = {
"clsid": "JAS_BK90",
"name": "BK-90 Unguided Cluster Munition",
"weight": 605,
}
JAS_BRIMSTONE = {
"clsid": "JAS_BRIMSTONE",
"name": "Brimstone Laser Guided Missile",
"weight": 195.5,
}
JAS_GBU10_TV = {
"clsid": "JAS_GBU10_TV",
"name": "GBU-10 2000 lb TV-guided Bomb",
"weight": 934,
}
JAS_GBU12 = {
"clsid": "JAS_GBU12",
"name": "GBU-12 500 lb Laser-guided Bomb",
"weight": 275,
}
JAS_GBU16_TV = {
"clsid": "JAS_GBU16_TV",
"name": "GBU-16 1000lb TV Guided Bomb",
"weight": 934,
}
JAS_GBU31 = {
"clsid": "JAS_GBU31",
"name": "GBU-31 2000lb TV Guided Glide-Bomb",
"weight": 934,
}
JAS_GBU49_TV = {
"clsid": "JAS_GBU49_TV",
"name": "GBU-49 500lb TV Guided Bomb",
"weight": 275,
}
JAS_IRIS_T = {
"clsid": "JAS_IRIS-T",
"name": "Rb98 IRIS-T Sidewinder IR AAM",
"weight": 88.4,
}
JAS_Litening = {
"clsid": "JAS_Litening",
"name": "Litening III POD (LLTV)",
"weight": 295,
}
JAS_MAR_1 = {
"clsid": "JAS_MAR-1",
"name": "MAR-1 High Speed Anti-Radiation Missile",
"weight": 350,
}
JAS_Meteor = {
"clsid": "JAS_Meteor",
"name": "Rb101 Meteor BVRAAM Active Rdr AAM",
"weight": 191,
}
JAS_RB15F = {
"clsid": "JAS_RB15F",
"name": "RBS-15 Mk. IV Gungnir Radiation Seeking Anti-ship Missile ",
"weight": None,
}
JAS_RB75T = {
"clsid": "JAS_RB75T",
"name": "Rb-75T (AGM-65E Maverick) (Laser ASM Lg Whd)",
"weight": 210,
}
JAS_Rb74 = {
"clsid": "JAS_Rb74",
"name": "Rb74 AIM-9L Sidewinder IR AAM",
"weight": 90,
}
JAS_Rb99 = {
"clsid": "JAS_Rb99",
"name": "Rb99 AIM-120B AMRAAM Active Rdr AAM",
"weight": 157,
}
JAS_Rb99_DUAL = {
"clsid": "JAS_Rb99_DUAL",
"name": "Rb99 AIM-120B AMRAAM Active Rdr AAM x 2",
"weight": 313,
}
JAS_Stormshadow = {
"clsid": "JAS_Stormshadow",
"name": "Storm Shadow Long Range Anti-Radiation Cruise-missile",
"weight": None,
}
JAS_TANK1100 = {
"clsid": "JAS_TANK1100",
"name": "External drop tank 1100 litre",
"weight": 1019,
}
JAS_TANK1700 = {
"clsid": "JAS_TANK1700",
"name": "External drop tank 1700 litre",
"weight": 1533,
}
inject_weapons(JAS39GripenWeapons)
class JAS39Gripen(PlaneType):
id = "JAS39Gripen"
flyable = True
height = 4.5
width = 8.4
length = 14.1
fuel_max = 2550
max_speed = 2649.996
chaff = 90
flare = 45
charge_total = 180
chaff_charge_size = 1
flare_charge_size = 2
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
radio_frequency = 127.5
class Pylon1:
JAS_IRIS_T = (1, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (1, JAS39GripenWeapons.JAS_Rb74)
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
Smokewinder___red = (1, Weapons.Smokewinder___red)
Smokewinder___green = (1, Weapons.Smokewinder___green)
Smokewinder___blue = (1, Weapons.Smokewinder___blue)
Smokewinder___white = (1, Weapons.Smokewinder___white)
Smokewinder___yellow = (1, Weapons.Smokewinder___yellow)
Smokewinder___orange = (1, Weapons.Smokewinder___orange)
class Pylon2:
JAS_IRIS_T = (2, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (2, JAS39GripenWeapons.JAS_Rb74)
JAS_Meteor = (2, JAS39GripenWeapons.JAS_Meteor)
JAS_Rb99 = (2, JAS39GripenWeapons.JAS_Rb99)
JAS_Rb99_DUAL = (2, JAS39GripenWeapons.JAS_Rb99_DUAL)
LAU_115_2_LAU_127_AIM_120C = (2, Weapons.LAU_115_2_LAU_127_AIM_120C)
AIM_120C_5_AMRAAM___Active_Rdr_AAM = (
2,
Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM,
)
# ERRR <CLEAN>
class Pylon3:
JAS_Meteor = (3, JAS39GripenWeapons.JAS_Meteor)
JAS_Rb99 = (3, JAS39GripenWeapons.JAS_Rb99)
AIM_120C_5_AMRAAM___Active_Rdr_AAM = (
3,
Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM,
)
JAS_TANK1100 = (3, JAS39GripenWeapons.JAS_TANK1100)
JAS_TANK1700 = (3, JAS39GripenWeapons.JAS_TANK1700)
# ERRR <CLEAN>
class Pylon4:
L_081_Fantasmagoria_ELINT_pod = (4, Weapons.L_081_Fantasmagoria_ELINT_pod)
class Pylon5:
JAS_TANK1100 = (5, JAS39GripenWeapons.JAS_TANK1100)
JAS_Meteor = (5, JAS39GripenWeapons.JAS_Meteor)
AIM_120C_5_AMRAAM___Active_Rdr_AAM = (
5,
Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM,
)
JAS_Rb99 = (5, JAS39GripenWeapons.JAS_Rb99)
JAS_Rb99_DUAL = (5, JAS39GripenWeapons.JAS_Rb99_DUAL)
# ERRR <CLEAN>
class Pylon6:
L005_Sorbtsiya_ECM_pod__left_ = (6, Weapons.L005_Sorbtsiya_ECM_pod__left_)
class Pylon7:
JAS_Litening = (7, JAS39GripenWeapons.JAS_Litening)
# ERRR <CLEAN>
class Pylon8:
JAS_Meteor = (8, JAS39GripenWeapons.JAS_Meteor)
JAS_Rb99 = (8, JAS39GripenWeapons.JAS_Rb99)
AIM_120C_5_AMRAAM___Active_Rdr_AAM = (
8,
Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM,
)
JAS_TANK1100 = (8, JAS39GripenWeapons.JAS_TANK1100)
JAS_TANK1700 = (8, JAS39GripenWeapons.JAS_TANK1700)
# ERRR <CLEAN>
class Pylon9:
JAS_IRIS_T = (9, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (9, JAS39GripenWeapons.JAS_Rb74)
JAS_Meteor = (9, JAS39GripenWeapons.JAS_Meteor)
JAS_Rb99 = (9, JAS39GripenWeapons.JAS_Rb99)
JAS_Rb99_DUAL = (9, JAS39GripenWeapons.JAS_Rb99_DUAL)
LAU_115_2_LAU_127_AIM_120C = (9, Weapons.LAU_115_2_LAU_127_AIM_120C)
AIM_120C_5_AMRAAM___Active_Rdr_AAM = (
9,
Weapons.AIM_120C_5_AMRAAM___Active_Rdr_AAM,
)
# ERRR <CLEAN>
class Pylon10:
JAS_IRIS_T = (10, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (10, JAS39GripenWeapons.JAS_Rb74)
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (10, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
Smokewinder___red = (10, Weapons.Smokewinder___red)
Smokewinder___green = (10, Weapons.Smokewinder___green)
Smokewinder___blue = (10, Weapons.Smokewinder___blue)
Smokewinder___white = (10, Weapons.Smokewinder___white)
Smokewinder___yellow = (10, Weapons.Smokewinder___yellow)
Smokewinder___orange = (10, Weapons.Smokewinder___orange)
pylons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
tasks = [
task.Intercept,
task.CAP,
task.Reconnaissance,
task.Escort,
task.FighterSweep,
]
task_default = task.FighterSweep
class JAS39Gripen_AG(PlaneType):
id = "JAS39Gripen_AG"
flyable = True
height = 4.5
width = 8.4
length = 14.1
fuel_max = 2550
max_speed = 2649.996
chaff = 90
flare = 45
charge_total = 180
chaff_charge_size = 1
flare_charge_size = 1
category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F}
radio_frequency = 127.5
class Pylon1:
JAS_IRIS_T = (1, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (1, JAS39GripenWeapons.JAS_Rb74)
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
Smokewinder___red = (1, Weapons.Smokewinder___red)
Smokewinder___green = (1, Weapons.Smokewinder___green)
Smokewinder___blue = (1, Weapons.Smokewinder___blue)
Smokewinder___white = (1, Weapons.Smokewinder___white)
Smokewinder___yellow = (1, Weapons.Smokewinder___yellow)
Smokewinder___orange = (1, Weapons.Smokewinder___orange)
class Pylon2:
JAS_IRIS_T = (2, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (2, JAS39GripenWeapons.JAS_Rb74)
JAS_RB75T = (2, JAS39GripenWeapons.JAS_RB75T)
AGM_65K___Maverick_K__CCD_Imp_ASM_ = (
2,
Weapons.AGM_65K___Maverick_K__CCD_Imp_ASM_,
)
JAS_BK90 = (2, JAS39GripenWeapons.JAS_BK90)
JAS_RB15F = (2, JAS39GripenWeapons.JAS_RB15F)
JAS_MAR_1 = (2, JAS39GripenWeapons.JAS_MAR_1)
JAS_GBU12 = (2, JAS39GripenWeapons.JAS_GBU12)
JAS_GBU49_TV = (2, JAS39GripenWeapons.JAS_GBU49_TV)
# ERRR JAS_GBU16
JAS_GBU16_TV = (2, JAS39GripenWeapons.JAS_GBU16_TV)
# ERRR GBU12_TEST
Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD)
Mk_83___1000lb_GP_Bomb_LD = (2, Weapons.Mk_83___1000lb_GP_Bomb_LD)
BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_ = (
2,
Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_,
)
_4x_SB_M_71_120kg_GP_Bomb_Low_drag = (
2,
Weapons._4x_SB_M_71_120kg_GP_Bomb_Low_drag,
)
JAS_ARAKM70BHE = (2, JAS39GripenWeapons.JAS_ARAKM70BHE)
JAS_ARAKM70BAP = (2, JAS39GripenWeapons.JAS_ARAKM70BAP)
JAS_BRIMSTONE = (2, JAS39GripenWeapons.JAS_BRIMSTONE)
# ERRR <CLEAN>
class Pylon3:
JAS_RB75T = (3, JAS39GripenWeapons.JAS_RB75T)
AGM_65K___Maverick_K__CCD_Imp_ASM_ = (
3,
Weapons.AGM_65K___Maverick_K__CCD_Imp_ASM_,
)
JAS_Stormshadow = (3, JAS39GripenWeapons.JAS_Stormshadow)
JAS_BK90 = (3, JAS39GripenWeapons.JAS_BK90)
JAS_GBU31 = (3, JAS39GripenWeapons.JAS_GBU31)
JAS_RB15F = (3, JAS39GripenWeapons.JAS_RB15F)
JAS_MAR_1 = (3, JAS39GripenWeapons.JAS_MAR_1)
JAS_GBU12 = (3, JAS39GripenWeapons.JAS_GBU12)
JAS_GBU49_TV = (3, JAS39GripenWeapons.JAS_GBU49_TV)
# ERRR JAS_GBU16
JAS_GBU16_TV = (3, JAS39GripenWeapons.JAS_GBU16_TV)
GBU_10___2000lb_Laser_Guided_Bomb = (
3,
Weapons.GBU_10___2000lb_Laser_Guided_Bomb,
)
Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD)
Mk_83___1000lb_GP_Bomb_LD = (3, Weapons.Mk_83___1000lb_GP_Bomb_LD)
Mk_84___2000lb_GP_Bomb_LD = (3, Weapons.Mk_84___2000lb_GP_Bomb_LD)
BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_ = (
3,
Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_,
)
_4x_SB_M_71_120kg_GP_Bomb_Low_drag = (
3,
Weapons._4x_SB_M_71_120kg_GP_Bomb_Low_drag,
)
JAS_TANK1100 = (3, JAS39GripenWeapons.JAS_TANK1100)
JAS_TANK1700 = (3, JAS39GripenWeapons.JAS_TANK1700)
JAS_ARAKM70BHE = (3, JAS39GripenWeapons.JAS_ARAKM70BHE)
JAS_ARAKM70BAP = (3, JAS39GripenWeapons.JAS_ARAKM70BAP)
JAS_BRIMSTONE = (3, JAS39GripenWeapons.JAS_BRIMSTONE)
# ERRR <CLEAN>
class Pylon4:
L_081_Fantasmagoria_ELINT_pod = (4, Weapons.L_081_Fantasmagoria_ELINT_pod)
class Pylon5:
JAS_Stormshadow = (5, JAS39GripenWeapons.JAS_Stormshadow)
JAS_GBU12 = (5, JAS39GripenWeapons.JAS_GBU12)
JAS_GBU49_TV = (5, JAS39GripenWeapons.JAS_GBU49_TV)
# ERRR JAS_GBU16
JAS_GBU16_TV = (5, JAS39GripenWeapons.JAS_GBU16_TV)
GBU_10___2000lb_Laser_Guided_Bomb = (
5,
Weapons.GBU_10___2000lb_Laser_Guided_Bomb,
)
Mk_82___500lb_GP_Bomb_LD = (5, Weapons.Mk_82___500lb_GP_Bomb_LD)
Mk_83___1000lb_GP_Bomb_LD = (5, Weapons.Mk_83___1000lb_GP_Bomb_LD)
Mk_84___2000lb_GP_Bomb_LD = (5, Weapons.Mk_84___2000lb_GP_Bomb_LD)
BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_ = (
5,
Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_,
)
_4x_SB_M_71_120kg_GP_Bomb_Low_drag = (
5,
Weapons._4x_SB_M_71_120kg_GP_Bomb_Low_drag,
)
JAS_TANK1100 = (5, JAS39GripenWeapons.JAS_TANK1100)
# ERRR JAS_WMD7
JAS_BRIMSTONE = (5, JAS39GripenWeapons.JAS_BRIMSTONE)
# ERRR {INV-SMOKE-RED}
# ERRR {INV-SMOKE-GREEN}
# ERRR {INV-SMOKE-BLUE}
# ERRR {INV-SMOKE-WHITE}
# ERRR {INV-SMOKE-YELLOW}
# ERRR {INV-SMOKE-ORANGE}
# ERRR <CLEAN>
class Pylon6:
L005_Sorbtsiya_ECM_pod__left_ = (6, Weapons.L005_Sorbtsiya_ECM_pod__left_)
class Pylon7:
JAS_Litening = (7, JAS39GripenWeapons.JAS_Litening)
# ERRR <CLEAN>
class Pylon8:
JAS_RB75T = (8, JAS39GripenWeapons.JAS_RB75T)
AGM_65K___Maverick_K__CCD_Imp_ASM_ = (
8,
Weapons.AGM_65K___Maverick_K__CCD_Imp_ASM_,
)
JAS_Stormshadow = (8, JAS39GripenWeapons.JAS_Stormshadow)
JAS_BK90 = (8, JAS39GripenWeapons.JAS_BK90)
JAS_GBU31 = (8, JAS39GripenWeapons.JAS_GBU31)
JAS_RB15F = (8, JAS39GripenWeapons.JAS_RB15F)
JAS_MAR_1 = (8, JAS39GripenWeapons.JAS_MAR_1)
JAS_GBU12 = (8, JAS39GripenWeapons.JAS_GBU12)
JAS_GBU49_TV = (8, JAS39GripenWeapons.JAS_GBU49_TV)
# ERRR JAS_GBU16
JAS_GBU16_TV = (8, JAS39GripenWeapons.JAS_GBU16_TV)
GBU_10___2000lb_Laser_Guided_Bomb = (
8,
Weapons.GBU_10___2000lb_Laser_Guided_Bomb,
)
Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD)
Mk_83___1000lb_GP_Bomb_LD = (8, Weapons.Mk_83___1000lb_GP_Bomb_LD)
Mk_84___2000lb_GP_Bomb_LD = (8, Weapons.Mk_84___2000lb_GP_Bomb_LD)
BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_ = (
8,
Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_,
)
_4x_SB_M_71_120kg_GP_Bomb_Low_drag = (
8,
Weapons._4x_SB_M_71_120kg_GP_Bomb_Low_drag,
)
JAS_TANK1100 = (8, JAS39GripenWeapons.JAS_TANK1100)
JAS_TANK1700 = (8, JAS39GripenWeapons.JAS_TANK1700)
JAS_ARAKM70BHE = (8, JAS39GripenWeapons.JAS_ARAKM70BHE)
JAS_ARAKM70BAP = (8, JAS39GripenWeapons.JAS_ARAKM70BAP)
JAS_BRIMSTONE = (8, JAS39GripenWeapons.JAS_BRIMSTONE)
# ERRR <CLEAN>
class Pylon9:
JAS_IRIS_T = (9, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (9, JAS39GripenWeapons.JAS_Rb74)
JAS_RB75T = (9, JAS39GripenWeapons.JAS_RB75T)
AGM_65K___Maverick_K__CCD_Imp_ASM_ = (
9,
Weapons.AGM_65K___Maverick_K__CCD_Imp_ASM_,
)
JAS_BK90 = (9, JAS39GripenWeapons.JAS_BK90)
JAS_RB15F = (9, JAS39GripenWeapons.JAS_RB15F)
JAS_MAR_1 = (9, JAS39GripenWeapons.JAS_MAR_1)
JAS_GBU12 = (9, JAS39GripenWeapons.JAS_GBU12)
JAS_GBU49_TV = (9, JAS39GripenWeapons.JAS_GBU49_TV)
# ERRR JAS_GBU16
JAS_GBU16_TV = (9, JAS39GripenWeapons.JAS_GBU16_TV)
# ERRR GBU12_TEST
Mk_82___500lb_GP_Bomb_LD = (9, Weapons.Mk_82___500lb_GP_Bomb_LD)
Mk_83___1000lb_GP_Bomb_LD = (9, Weapons.Mk_83___1000lb_GP_Bomb_LD)
BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_ = (
9,
Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD_,
)
_4x_SB_M_71_120kg_GP_Bomb_Low_drag = (
9,
Weapons._4x_SB_M_71_120kg_GP_Bomb_Low_drag,
)
JAS_ARAKM70BHE = (9, JAS39GripenWeapons.JAS_ARAKM70BHE)
JAS_ARAKM70BAP = (9, JAS39GripenWeapons.JAS_ARAKM70BAP)
JAS_BRIMSTONE = (9, JAS39GripenWeapons.JAS_BRIMSTONE)
# ERRR <CLEAN>
class Pylon10:
JAS_IRIS_T = (10, JAS39GripenWeapons.JAS_IRIS_T)
JAS_Rb74 = (10, JAS39GripenWeapons.JAS_Rb74)
AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (10, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod)
Smokewinder___red = (10, Weapons.Smokewinder___red)
Smokewinder___green = (10, Weapons.Smokewinder___green)
Smokewinder___blue = (10, Weapons.Smokewinder___blue)
Smokewinder___white = (10, Weapons.Smokewinder___white)
Smokewinder___yellow = (10, Weapons.Smokewinder___yellow)
Smokewinder___orange = (10, Weapons.Smokewinder___orange)
pylons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
tasks = [
task.SEAD,
task.AntishipStrike,
task.CAS,
task.GroundAttack,
task.PinpointStrike,
task.RunwayAttack,
]
task_default = task.CAS

View File

@ -2,6 +2,7 @@ from pydcs_extensions.a4ec.a4ec import A_4E_C
from pydcs_extensions.f22a.f22a import F_22A
from pydcs_extensions.hercules.hercules import Hercules
from pydcs_extensions.highdigitsams import highdigitsams
from pydcs_extensions.jas39.jas39 import JAS39Gripen, JAS39Gripen_AG
from pydcs_extensions.mb339.mb339 import MB_339PAN
from pydcs_extensions.su57.su57 import Su_57
import pydcs_extensions.frenchpack.frenchpack as frenchpack
@ -12,6 +13,8 @@ MODDED_AIRPLANES = [
Su_57,
F_22A,
Hercules,
JAS39Gripen,
JAS39Gripen_AG,
]
MODDED_VEHICLES = [
frenchpack._FIELD_HIDE,

View File

@ -220,7 +220,7 @@ class QWeatherWidget(QGroupBox):
precipitation = self.conditions.weather.clouds.precipitation
if not cloud_density:
self.forecastClouds.setText("Sunny")
self.forecastClouds.setText("Clear")
weather_type = "clear"
elif cloud_density < 3:
self.forecastClouds.setText("Partly Cloudy")

View File

@ -11,7 +11,6 @@ from dcs.vehicles import vehicle_map
from shapely.geometry import LineString, Point as ShapelyPoint, Polygon, MultiPolygon
from game import Game, db
from game.factions.faction import Faction
from game.navmesh import NavMesh
from game.profiling import logged_duration
from game.theater import (
@ -27,7 +26,7 @@ from game.transfers import MultiGroupTransport, TransportMap
from game.utils import meters, nautical_miles
from gen.ato import AirTaskingOrder
from gen.flights.flight import Flight, FlightWaypoint, FlightWaypointType
from gen.flights.flightplan import FlightPlan, PatrollingFlightPlan
from gen.flights.flightplan import FlightPlan, PatrollingFlightPlan, CasFlightPlan
from qt_ui.dialogs import Dialog
from qt_ui.models import GameModel, AtoModel
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
@ -508,14 +507,12 @@ class FlightJs(QObject):
flight: Flight,
selected: bool,
theater: ConflictTheater,
faction: Faction,
ato_model: AtoModel,
) -> None:
super().__init__()
self.flight = flight
self._selected = selected
self.theater = theater
self.faction = faction
self.ato_model = ato_model
self._waypoints = self.make_waypoints()
@ -556,14 +553,19 @@ class FlightJs(QObject):
return []
start = self.flight.flight_plan.patrol_start
end = self.flight.flight_plan.patrol_end
line = LineString(
if isinstance(self.flight.flight_plan, CasFlightPlan):
center = self.flight.flight_plan.target.position
commit_center = ShapelyPoint(center.x, center.y)
else:
commit_center = LineString(
[
ShapelyPoint(start.x, start.y),
ShapelyPoint(end.x, end.y),
]
)
doctrine = self.faction.doctrine
bubble = line.buffer(doctrine.cap_engagement_range.meters)
bubble = commit_center.buffer(
self.flight.flight_plan.engagement_distance.meters
)
return shapely_poly_to_leaflet_points(bubble, self.theater)
@ -855,7 +857,6 @@ class MapModel(QObject):
flight,
selected=blue and (p_idx, f_idx) == self._selected_flight_index,
theater=self.game.theater,
faction=self.game.faction_for(blue),
ato_model=self.game_model.ato_model_for(blue),
)
)

View File

@ -143,4 +143,6 @@ class QUnitInfoWindow(QDialog):
aircraft_tasks = aircraft_tasks + f"{FlightType.OCA_RUNWAY}, "
if self.unit_type in gen.flights.ai_flight_planner_db.STRIKE_CAPABLE:
aircraft_tasks = aircraft_tasks + f"{FlightType.STRIKE}, "
if self.unit_type in gen.flights.ai_flight_planner_db.REFUELING_CAPABALE:
aircraft_tasks = aircraft_tasks + f"{FlightType.REFUELING}, "
return aircraft_tasks[:-2]

View File

@ -1,5 +1,5 @@
import logging
from typing import Optional, Set, Type
from typing import Set, Type
from PySide2.QtCore import Qt
from PySide2.QtWidgets import (
@ -13,7 +13,6 @@ from PySide2.QtWidgets import (
QWidget,
)
from dcs.helicopters import helicopter_map
from dcs.task import CAP, CAS, AWACS, Transport
from dcs.unittype import FlyingType, UnitType
from game import db
@ -45,8 +44,6 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
def init_ui(self):
main_layout = QVBoxLayout()
tasks = [CAP, CAS, AWACS, Transport]
scroll_content = QWidget()
task_box_layout = QGridLayout()
row = 0

View File

@ -16,13 +16,13 @@ from PySide2.QtWidgets import (
QVBoxLayout,
)
from dcs import Point
from dcs import vehicles
from game import Game, db
from game.data.building_data import FORTIFICATION_BUILDINGS
from game.db import PRICES, PinpointStrike, REWARDS, unit_type_of
from game.db import PRICES, REWARDS, unit_type_of
from game.theater import ControlPoint, TheaterGroundObject
from game.theater.theatergroundobject import (
NavalGroundObject,
VehicleGroupGroundObject,
SamGroundObject,
EwrGroundObject,
@ -35,7 +35,6 @@ from qt_ui.uiconstants import EVENT_ICONS
from qt_ui.widgets.QBudgetBox import QBudgetBox
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from qt_ui.windows.groundobject.QBuildingInfo import QBuildingInfo
from dcs import vehicles
class QGroundObjectMenu(QDialog):

View File

@ -123,6 +123,7 @@ class PilotControls(QHBoxLayout):
def enable_and_reset(self) -> None:
self.selector.rebuild()
self.player_checkbox.setEnabled(True)
self.on_pilot_changed(self.selector.currentIndex())
def disable_and_clear(self) -> None:

View File

@ -494,6 +494,28 @@ class QSettingsWindow(QDialog):
general_layout.addWidget(old_awac_label, 1, 0)
general_layout.addWidget(old_awac, 1, 1, Qt.AlignRight)
def set_old_tanker(value: bool) -> None:
self.game.settings.disable_legacy_tanker = not value
old_tanker = QCheckBox()
old_tanker.setChecked(not self.game.settings.disable_legacy_tanker)
old_tanker.toggled.connect(set_old_tanker)
old_tanker_info = (
"If checked, an invulnerable friendly Tanker aircraft that begins the "
"mission on station will be be spawned. This behavior will be removed in a "
"future release."
)
old_tanker.setToolTip(old_tanker_info)
old_tanker_label = QLabel(
"Spawn invulnerable, always-available Tanker aircraft (deprecated)."
)
old_tanker_label.setToolTip(old_tanker_info)
general_layout.addWidget(old_tanker_label, 2, 0)
general_layout.addWidget(old_tanker, 2, 1, Qt.AlignRight)
campaign_layout.addWidget(HqAutomationSettingsBox(self.game))
def initGeneratorLayout(self):

View File

@ -17,7 +17,7 @@ nodeenv==1.5.0
packaging==20.9
pathspec==0.8.1
pefile==2019.4.18
Pillow==8.1.1
Pillow==8.2.0
pre-commit==2.10.1
pyinstaller==4.3
pyinstaller-hooks-contrib==2021.1

View File

@ -0,0 +1,11 @@
{
"name": "Caucasus - Full",
"theater": "Caucasus",
"authors": "Doc_of_Mur",
"recommended_player_faction": "Bluefor Modern",
"recommended_enemy_faction": "Russia 2010",
"description": "<p>This is a complete map of every airbase in the Caucasus Region, all bases are fully defended by Air, Land and/or Sea. The player starts by invading southern Georgia and works their way through Russia. The Strike and SAM targets are limited for performance reasons. If this Scenario is too taxing for your computer you may use the Multi-Part Scenarios. They are copied from this Campaign and are catered toward less powerful machines.</p>",
"version": "6.0",
"miz": "Caucasus_Multi_Full.miz",
"performance": 3
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"name": "Caucasus - Multi-Part Georgia",
"theater": "Caucasus",
"authors": "Doc_of_Mur",
"recommended_player_faction": "Bluefor Modern",
"recommended_enemy_faction": "Georgia 2008",
"description": "<p>This is Part 1 of the Caucasus Multi-Part Campaign. This is the invasion of Georgia starting from the southwest (Batumi) and ending in both Gudauta and Tiblisi. This is a straightforward campaign that is smaller and simpler than most. However, it acts great as either a stand alone campaign for beginners, or as a lead into the Caucasus Multi-Part Russia campaign.</p>",
"version": "6.0",
"miz": "Caucasus_Multi_Georgia.miz",
"performance": 1
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"name": "Caucasus - Multi-Part Russia",
"theater": "Caucasus",
"authors": "Doc_of_Mur",
"recommended_player_faction": "Bluefor Modern",
"recommended_enemy_faction": "Russia 2010",
"description": "<p>This is part 2 of the Caucasus Multi-part campaign. After completing Multi-Part Georgia, play this campaign to invade Russia and finish the theater. As this is now Russia the recommended enemy faction has changed. To simulate still owning Georgia the player income has been supplemented through an increased number of blue strike targets at the starting bases. This is a more difficult scenario with a higher concentration of Redfor SAMs and Strike targets than usual.</p>",
"version": "6.0",
"miz": "Caucasus_Multi_Russia.miz",
"performance": 2
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"name": "Persian Gulf - Road To Dubai",
"theater": "Persian Gulf",
"authors": "Doc_of_Mur",
"description": "<p>Small beginner friendly map</p><p><strong>Note:</strong> This scenario is based around Iran invading the UAE and you are trying to take it back. It is small and beginner friendly.</p>",
"version": "6.0",
"recommended_player_faction": "USA 2005",
"recommended_enemy_faction": "Iran 2015",
"miz": "Road_to_Dubai.miz",
"performance": 1
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"name": "Caucasus - Around The Mountain",
"theater": "Caucasus",
"authors": "Dillie",
"recommended_player_faction": "Russia 2010",
"recommended_enemy_faction": "USA 1990",
"description": "<p>Scenario from Russia to Georgia in two Frontlines.</p>",
"version": "6.0",
"miz": "around_the_mountain.miz",
"performance": 2
}

Binary file not shown.

View File

@ -1,10 +0,0 @@
{
"name": "The Channel - Battle of Britain",
"theater": "The Channel",
"authors": "Khopa",
"recommended_player_faction": "United Kingdom 1944",
"recommended_enemy_faction": "Germany 1942",
"description": "<p>Experience the Battle of Britain on the Channel map !<br/></p><p><strong>Note:</strong> It is not possible to cross the channel to capture enemy bases yet, but you can consider you won if you manage to destroy all the ennemy targets</p>",
"miz": "battle_of_britain.miz",
"performance": 1
}

View File

@ -1,8 +0,0 @@
{
"name": "Caucasus - Black Sea Lite",
"theater": "Caucasus",
"authors": "Starfire",
"description": "<p>A Small sized theater with bases along the coast of the Black Sea, lite version of ColonelPanic's Black Sea campaign scenario.</p>",
"miz": "black_sea_lite.miz",
"performance": 1
}

View File

@ -1,10 +0,0 @@
{
"name": "Persian Gulf - Desert War",
"theater": "Persian Gulf",
"authors": "Khopa",
"recommended_player_faction": "USA 2005",
"recommended_enemy_faction": "Iran 2015",
"description": "<p>This is a simple scenario in the Desert near Dubai and Abu-Dhabi. Progress from Liwa airbase to Al-Minhad.</p><p>This scenario shouldn't require too much performance.</p>",
"miz": "desert_war.miz",
"performance": 1
}

Binary file not shown.

View File

@ -1,10 +0,0 @@
{
"name": "The Channel - Dunkirk",
"theater": "The Channel",
"authors": "Khopa",
"recommended_player_faction": "Allies 1944",
"recommended_enemy_faction": "Germany 1942",
"description": "<p>In this scenario, your forces starts in Dunkirk and can be supported by the airfields on the other side of the Channel.</p><p>If you select the inverted configuration, you can play a German invasion of England.</p><p><strong>Note:</strong> B-17 should be operated from Manston airfield</p>",
"miz": "dunkirk.miz",
"performance": 1
}

Binary file not shown.

View File

@ -1,10 +0,0 @@
{
"name": "Persian Gulf - Emirates",
"theater": "Persian Gulf",
"authors": "Khopa",
"recommended_player_faction": "USA 2005",
"recommended_enemy_faction": "Iran 2015",
"description": "<p>In this scenario, you can play an invasion of the Emirates and Oman, where your forces starts in Fujairah.</p><p><strong>Note:</strong> Fujairah airfield has very few slots for aircrafts, so it recommended to operate from carriers at the start of the campaign. Thus, a carrier-capable faction is recommended.</p>",
"miz": "emirates.miz",
"performance": 1
}

Binary file not shown.

View File

@ -1,8 +0,0 @@
{
"name": "Caucasus - Full Map",
"theater": "Caucasus",
"authors": "george",
"description": "<p>Full map of the Caucasus</p><p><strong>Note:</strong> This scenario is heavy on performance, enabling \"culling\" in settings is highly recommended.</p>",
"miz": "full_caucasus.miz",
"performance": 3
}

View File

@ -0,0 +1,11 @@
{
"name": "Syria - Humble Helper",
"theater": "Syria",
"authors": "Headiii",
"recommended_player_faction": "Israel 2012'ish",
"recommended_enemy_faction": "Syria 2012'ish",
"description": "<p>In this scenario, you start in Israel in an high intensity conflict with Syria, backed by a Russian Expeditiary Force. Your goal is to take the heavily fortified city of Damascus, as fast as you can. The longer you wait, the more resources the enemy can pump into the defense of the city or even might try to take chunks of Israel. ATTENTION: CAMPAIGN INVERTING IS NOT YET IMPLEMENTED!!! Feedback: @Headiii in the DCSLiberation Discord</p>",
"miz": "humble_helper.miz",
"performance": 1,
"version": "6.0"
}

Binary file not shown.

View File

@ -1,10 +0,0 @@
{
"name": "Syria - Invasion from Turkey",
"theater": "Syria",
"authors": "Khopa",
"recommended_player_faction": "Turkey 2005",
"recommended_enemy_faction": "Insurgents (Hard)",
"description": "<p>In this scenario, you start from Turkey and have to invade territories in northern Syria.</p>",
"miz": "invasion_from_turkey.miz",
"performance": 1
}

View File

@ -1,10 +0,0 @@
{
"name": "Persian Gulf - Invasion of Iran",
"theater": "Persian Gulf",
"authors": "Khopa",
"recommended_player_faction": "USA 2005",
"recommended_enemy_faction": "Iran 2015",
"description": "<p>In this scenario, you start in Bandar Abbas, and must invade Iran.</p>",
"miz": "invasion_of_iran.miz",
"performance": 3
}

View File

@ -1,10 +0,0 @@
{
"name": "Persian Gulf - Invasion of Iran [Lite]",
"theater": "Persian Gulf",
"authors": "Khopa",
"recommended_player_faction": "USA 2005",
"recommended_enemy_faction": "Iran 2015",
"description": "<p>This is lighter version of the invasion of Iran scenario.</p>",
"miz": "invasion_of_iran_lite.miz",
"performance": 1
}

View File

@ -1,10 +0,0 @@
{
"name": "Normandy - Normandy",
"theater": "Normandy",
"authors": "Khopa",
"recommended_player_faction": "Allies 1944",
"recommended_enemy_faction": "Germany 1944",
"description": "<p>Normandy 1944 D-Day scenario.</p>",
"miz":"normandy.miz",
"performance": 3
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"name": "Caucasus - Northern Russia",
"theater": "Caucasus",
"authors": "Plob",
"recommended_player_faction": "USA 2005",
"recommended_enemy_faction": "Russia 1990",
"description": "<p>A medium campaign through the north eastern part of the Caucasus map.</p><p>Russia has invaded Georgia through the eastern mountains. Mount a counter offense and push them back!",
"miz": "northern_russia.miz",
"performance": 2,
"version": "6.0"
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"name": "Syria - Operation Allied Sword",
"theater": "Syria",
"authors": "Fuzzle",
"recommended_player_faction": "Israel-USN 2005 (Allied Sword)",
"recommended_enemy_faction": "Syria-Lebanon 2005 (Allied Sword)",
"description": "<p>In this fictional scenario, a US/Israeli coalition must push north from the Israeli border, through Syria and Lebanon to Aleppo.</p><p><strong>Backstory:</strong> A Syrian-Lebanese joint force (with Russian materiel support) has attacked Israel, attmepting to cross the northern border. With the arrival of a US carrier group, Israel prepares its counterattack. The US Navy will handle the Beirut region's coastal arena, while the IAF will push through Damascus and the inland mountain ranges.</p>",
"version": "6.0",
"miz": "operation_allied_sword.miz",
"performance": 2
}

Binary file not shown.

View File

@ -1,11 +0,0 @@
{
"name": "The Channel - Operation Dynamo",
"theater": "The Channel",
"authors": "Khopa",
"recommended_player_faction": "Allies 1940",
"recommended_enemy_faction": "Germany 1940",
"description": "<p>The Battle of Dunkirk (French: Bataille de Dunkerque) was fought around the French port of Dunkirk (Dunkerque) during the Second World War, between the Allies and Nazi Germany. As the Allies were losing the Battle of France on the Western Front, the Battle of Dunkirk was the defence and evacuation of British and other Allied forces to Britain from 26 May to 4 June 1940..</p>",
"version": 4.2,
"miz": "operation_dynamo.miz",
"performance": 1
}

View File

@ -1,8 +0,0 @@
{
"name": "Persian Gulf - Full Map",
"theater": "Persian Gulf",
"authors": "Plob",
"description": "<p>Full map of the Persian Gulf</p><p><strong>Note:</strong> This scenario is heavy on performance, enabling \"culling\" in settings is highly recommended.</p>",
"miz": "persian_gulf_full_map.miz",
"performance": 3
}

View File

@ -1,10 +0,0 @@
{
"name": "Syria - Syrian Civil War",
"theater": "Syria",
"authors": "Khopa",
"recommended_player_faction": "Russia 2010",
"recommended_enemy_faction": "Insurgents (Hard)",
"description": "<p>This scenario can be used to simulate parts of the Syrian Civil War.<br/><br/>You start on the coast with an airbase in Latakia, and ground forces in Tartus.<br/><br/>This scenario can also be used to simulate a western invasion of Syria.<br/><br/>In inverted configuration you start in Aleppo.</p>",
"miz": "syrian_civil_war.miz",
"performance": 2
}

View File

@ -0,0 +1,54 @@
local unitPayloads = {
["name"] = "JAS39Gripen",
["payloads"] = {
[1] = {
["displayName"] = "CAP",
["name"] = "CAP",
["pylons"] = {
[1] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 10,
},
[2] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 1,
},
[3] = {
["CLSID"] = "JAS_Meteor",
["num"] = 2,
},
[4] = {
["CLSID"] = "JAS_Meteor",
["num"] = 9,
},
[5] = {
["CLSID"] = "JAS_Meteor",
["num"] = 8,
},
[6] = {
["CLSID"] = "JAS_Meteor",
["num"] = 3,
},
[7] = {
["CLSID"] = "JAS_TANK1100",
["num"] = 5,
},
[8] = {
["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}",
["num"] = 6,
},
[9] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 4,
},
},
["tasks"] = {
[1] = 11,
},
},
},
["tasks"] = {
},
["unitType"] = "JAS39Gripen",
}
return unitPayloads

View File

@ -0,0 +1,291 @@
local unitPayloads = {
["name"] = "JAS39Gripen_AG",
["payloads"] = {
[1] = {
["displayName"] = "ANTISHIP",
["name"] = "ANTISHIP",
["pylons"] = {
[1] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 10,
},
[2] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 1,
},
[3] = {
["CLSID"] = "JAS_TANK1100",
["num"] = 5,
},
[4] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}",
["num"] = 6,
},
[6] = {
["CLSID"] = "JAS_RB15F",
["num"] = 3,
},
[7] = {
["CLSID"] = "JAS_RB15F",
["num"] = 8,
},
[8] = {
["CLSID"] = "JAS_RB15F",
["num"] = 2,
},
[9] = {
["CLSID"] = "JAS_RB15F",
["num"] = 9,
},
},
["tasks"] = {
[1] = 19,
},
},
[2] = {
["displayName"] = "SEAD",
["name"] = "SEAD",
["pylons"] = {
[1] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 10,
},
[2] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 1,
},
[3] = {
["CLSID"] = "JAS_TANK1100",
["num"] = 5,
},
[4] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}",
["num"] = 6,
},
[6] = {
["CLSID"] = "JAS_MAR-1",
["num"] = 3,
},
[7] = {
["CLSID"] = "JAS_MAR-1",
["num"] = 8,
},
[8] = {
["CLSID"] = "JAS_MAR-1",
["num"] = 2,
},
[9] = {
["CLSID"] = "JAS_MAR-1",
["num"] = 9,
},
},
["tasks"] = {
[1] = 19,
},
},
[3] = {
["displayName"] = "DEAD",
["name"] = "DEAD",
["pylons"] = {
[1] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 10,
},
[2] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 1,
},
[3] = {
["CLSID"] = "JAS_TANK1100",
["num"] = 5,
},
[4] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}",
["num"] = 6,
},
[6] = {
["CLSID"] = "JAS_Stormshadow",
["num"] = 3,
},
[7] = {
["CLSID"] = "JAS_Stormshadow",
["num"] = 8,
},
[8] = {
["CLSID"] = "JAS_MAR-1",
["num"] = 2,
},
[9] = {
["CLSID"] = "JAS_MAR-1",
["num"] = 9,
},
},
["tasks"] = {
[1] = 19,
},
},
[4] = {
["displayName"] = "CAS",
["name"] = "CAS",
["pylons"] = {
[1] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 10,
},
[2] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 1,
},
[3] = {
["CLSID"] = "JAS_TANK1100",
["num"] = 5,
},
[4] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}",
["num"] = 6,
},
[6] = {
["CLSID"] = "JAS_BRIMSTONE",
["num"] = 3,
},
[7] = {
["CLSID"] = "JAS_BRIMSTONE",
["num"] = 8,
},
[8] = {
["CLSID"] = "JAS_BRIMSTONE",
["num"] = 2,
},
[9] = {
["CLSID"] = "JAS_BRIMSTONE",
["num"] = 9,
},
[10] = {
["CLSID"] = "JAS_Litening",
["num"] = 7,
},
},
["tasks"] = {
[1] = 19,
},
},
[5] = {
["displayName"] = "STRIKE",
["name"] = "STRIKE",
["pylons"] = {
[1] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 10,
},
[2] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 1,
},
[3] = {
["CLSID"] = "JAS_TANK1100",
["num"] = 5,
},
[4] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}",
["num"] = 6,
},
[6] = {
["CLSID"] = "JAS_GBU31",
["num"] = 3,
},
[7] = {
["CLSID"] = "JAS_GBU31",
["num"] = 8,
},
[8] = {
["CLSID"] = "JAS_GBU49_TV",
["num"] = 2,
},
[9] = {
["CLSID"] = "JAS_GBU49_TV",
["num"] = 9,
},
[10] = {
["CLSID"] = "JAS_Litening",
["num"] = 7,
},
},
["tasks"] = {
[1] = 19,
},
},
[6] = {
["displayName"] = "OCA",
["name"] = "OCA",
["pylons"] = {
[1] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 10,
},
[2] = {
["CLSID"] = "JAS_IRIS-T",
["num"] = 1,
},
[3] = {
["CLSID"] = "JAS_TANK1100",
["num"] = 5,
},
[4] = {
["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}",
["num"] = 4,
},
[5] = {
["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}",
["num"] = 6,
},
[6] = {
["CLSID"] = "JAS_BK90",
["num"] = 3,
},
[7] = {
["CLSID"] = "JAS_BK90",
["num"] = 8,
},
[8] = {
["CLSID"] = "JAS_ARAKM70BHE",
["num"] = 2,
},
[9] = {
["CLSID"] = "JAS_ARAKM70BHE",
["num"] = 9,
},
[10] = {
["CLSID"] = "JAS_Litening",
["num"] = 7,
},
},
["tasks"] = {
[1] = 19,
},
},
},
["tasks"] = {
},
["unitType"] = "JAS39Gripen_AG",
}
return unitPayloads

View File

@ -0,0 +1,109 @@
{
"country": "Israel",
"name": "Israel-USN 2005 (Allied Sword)",
"authors": "Fuzzle",
"description": "<p>A joint US Navy/Israeli modern faction for use with the Operation Allied Sword scenario.</p>",
"aircrafts": [
"F_4E",
"F_15C",
"F_15E",
"F_16C_50",
"F_14B",
"FA_18C_hornet",
"AV8BNA",
"AH_1W",
"AH_64D",
"S_3B",
"SH_60B",
"UH_1H"
],
"awacs": [
"E_2C"
],
"tankers": [
"KC_135",
"KC130",
"S_3B_Tanker"
],
"frontline_units": [
"APC_M113",
"APC_HMMWV__Scout",
"ATGM_HMMWV",
"MBT_Merkava_IV",
"SPAAA_Vulcan_M163"
],
"artillery_units": [
"SPH_M109_Paladin_155mm",
"MLRS_M270_227mm"
],
"logistics_units": [
"Truck_M818_6x6"
],
"infantry_units": [
"Infantry_M4",
"Infantry_M249",
"MANPADS_Stinger"
],
"air_defenses": [
"ChaparralGenerator",
"HawkGenerator",
"VulcanGenerator",
"PatriotGenerator"
],
"ewrs": [
"HawkEwrGenerator"
],
"aircraft_carrier": [
"CVN_74_John_C__Stennis"
],
"helicopter_carrier": [
"LHA_1_Tarawa"
],
"destroyers": [
"DDG_Arleigh_Burke_IIa"
],
"cruisers": [
"CG_Ticonderoga"
],
"requirements": {
},
"carrier_names": [
"CVN-71 Theodore Roosevelt",
"CVN-72 Abraham Lincoln",
"CVN-73 George Washington",
"CVN-74 John C. Stennis",
"CVN-75 Harry S. Truman"
],
"helicopter_carrier_names": [
"LHA-1 Tarawa",
"LHA-2 Saipan",
"LHA-3 Belleau Wood",
"LHA-4 Nassau",
"LHA-5 Peleliu"
],
"navy_generators": [
"ArleighBurkeGroupGenerator",
"OliverHazardPerryGroupGenerator"
],
"has_jtac": true,
"jtac_unit": "MQ_9_Reaper",
"doctrine": "modern",
"liveries_overrides": {
"F_14B": [
"VF-142 Ghostriders"
],
"FA_18C_hornet": [
"VMFA-251 high visibility"
],
"AV8BNA": [
"VMAT-542"
],
"AH_1W": [
"Marines"
],
"UH_1H": [
"US NAVY"
]
}
}

View File

@ -32,7 +32,8 @@
],
"tankers": [
"KC_135",
"KC130"
"KC130",
"S-3B Tanker"
],
"frontline_units": [
"MBT_M1A2_Abrams",

View File

@ -0,0 +1,105 @@
{
"country": "Combined Joint Task Forces Red",
"name": "Syria-Lebanon 2005 (Allied Sword)",
"authors": "Fuzzle",
"description": "<p>Syria-Lebanon alliance in a modern setting with several imported Russian assets. Designed for use with the Allied Sword scenario.</p>",
"aircrafts": [
"MiG_23MLD",
"MiG_25PD",
"MiG_29S",
"Su_17M4",
"Su_24M",
"Su_30",
"Su_34",
"L_39ZA",
"Tu_22M3",
"Mi_24V",
"Mi_8MT",
"SA342M",
"SA342L"
],
"awacs": [
"A_50"
],
"tankers": [
"IL_78M"
],
"frontline_units": [
"IFV_BMP_1",
"IFV_BMP_2",
"APC_BTR_80",
"IFV_BRDM_2",
"APC_MTLB",
"APC_Cobra__Scout",
"MBT_T_55",
"MBT_T_72B",
"MBT_T_90",
"SPAAA_ZSU_57_2"
],
"artillery_units": [
"MLRS_BM_27_Uragan_220mm",
"SPH_2S9_Nona_120mm_M",
"MLRS_BM_21_Grad_122mm",
"SPH_2S1_Gvozdika_122mm"
],
"logistics_units": [
"Truck_Ural_375",
"LUV_UAZ_469_Jeep"
],
"infantry_units": [
"Paratrooper_AKS",
"Infantry_AK_74_Rus",
"Paratrooper_RPG_16",
"MANPADS_SA_18_Igla_S_Grouse"
],
"air_defenses": [
"ColdWarFlakGenerator",
"SA2Generator",
"SA3Generator",
"SA6Generator",
"SA8Generator",
"SA9Generator",
"SA10Generator",
"SA11Generator",
"SA13Generator",
"SA19Generator",
"ZSU23Generator",
"ZU23Generator",
"ZU23UralGenerator",
"ZSU57Generator"
],
"ewrs": [
"BoxSpringGenerator",
"TallRackGenerator"
],
"missiles": [
"ScudGenerator"
],
"missiles_group_count": 2,
"coastal_defenses": [
"SilkwormGenerator"
],
"coastal_group_count": 4,
"aircraft_carrier": [
],
"helicopter_carrier": [
],
"helicopter_carrier_names": [
],
"destroyers": [
"Frigate_1135M_Rezky",
"Corvette_1241_1_Molniya"
],
"cruisers": [
],
"requirements": {},
"carrier_names": [
],
"coastal_group_count": 8,
"navy_generators": [
"GrishaGroupGenerator",
"MolniyaGroupGenerator",
"RussianNavyGroupGenerator",
"LaCombattanteIIGroupGenerator"
]
}

View File

@ -33,7 +33,9 @@
],
"tankers": [
"KC_135",
"KC130"
"KC135MPRS",
"KC130",
"S-3B Tanker"
],
"frontline_units": [
"MBT_M1A2_Abrams",

View File

@ -0,0 +1,100 @@
{
"country": "Israel",
"name": "Israel 2012'ish",
"authors": "Headiii",
"description": "<p>A more modern Israeli faction with fictional Imports.</p>",
"locales": ["he_IL"],
"aircrafts": [
"A_10C",
"F_15C",
"F_15E",
"F_16C_50",
"FA_18C_hornet",
"M_2000C",
"UH_1H",
"AH_64D"
],
"awacs": [
"E_2C"
],
"tankers": [
"KC_135",
"KC130"
],
"frontline_units": [
"APC_M113",
"Scout_HMMWV",
"ATGM_HMMWV",
"MBT_Merkava_IV",
"SPAAA_Vulcan_M163"
],
"artillery_units": [
"SPH_M109_Paladin_155mm",
"MLRS_M270_227mm"
],
"logistics_units": [
"Truck_M818_6x6"
],
"infantry_units": [
"Infantry_M4",
"Infantry_M249",
"MANPADS_Stinger"
],
"air_defenses": [
"ChaparralGenerator",
"HawkGenerator",
"PatriotGenerator",
"VulcanGenerator"
],
"ewrs": [
"HawkEwrGenerator"
],
"aircraft_carrier": [
],
"helicopter_carrier": [
],
"destroyers": [
],
"cruisers": [
],
"requirements": {
},
"carrier_names": [
],
"helicopter_carrier_names": [
],
"navy_generators": [
"ArleighBurkeGroupGenerator"
],
"has_jtac": true,
"jtac_unit": "MQ_9_Reaper",
"liveries_overrides": {
"A_10C": [
"Fictional Israel 115 Sqn Flying Dragon"
],
"F_15C": [
"390th Fighter SQN"
],
"F_15E":[
"IDF No 69 Hammers Squadron"
],
"F_16C_50": [
"IAF_101st_squadron",
"IAF_110th_Squadron",
"IAF_115th_Aggressors_Squadron",
"IAF_117th_Squadron"
],
"UH_1H": [
"Israel Army"
],
"AH_64D":[
"ah-64_d_isr"
],
"FA_18C_hornet": [
"Fictional Israel Air Force"
],
"M_2000C": [
"UAE Air Force"
]
}
}

View File

@ -0,0 +1,51 @@
{
"country": "Sweden",
"name": "Sweden 2002",
"authors": "Khopa (updated with Gripen by bgreman)",
"description": "<p>Sweden in 2002 after the addition of the Gripen-C.</p>",
"locales": ["sv_SE"],
"aircrafts": [
"AJS37",
"JAS39Gripen",
"JAS39Gripen_AG",
"UH_1H"
],
"awacs": [
"E_3A"
],
"tankers": [
"KC_135",
"KC130"
],
"frontline_units": [
"IFV_Warrior",
"MBT_Leopard_2A4",
"IFV_M1126_Stryker_ICV",
"SAM_Avenger__Stinger"
],
"artillery_units": [
],
"logistics_units": [
"Truck_M818_6x6"
],
"infantry_units": [
"Infantry_M4",
"Infantry_M249",
"MANPADS_Stinger"
],
"air_defenses": [
"AvengerGenerator",
"HawkGenerator"
],
"ewrs": [
"HawkEwrGenerator"
],
"navy_generators": [
"OliverHazardPerryGroupGenerator"
],
"requirements": {
"JAS39 Gripen Mod by Community": "https://github.com/whisky-actual/Community-JAS-39-C"
},
"has_jtac": true,
"jtac_unit": "MQ_9_Reaper"
}

View File

@ -0,0 +1,96 @@
{
"country": "Combined Joint Task Forces Red",
"name": "Syria 2012'ish",
"authors": "Headiii",
"description": "<p>Syrian Army with more modern Imports and supported by a Russian Expeditionary Force.</p>",
"aircrafts": [
"MiG_23MLD",
"MiG_25PD",
"MiG_29S",
"Su_24M",
"Su_25",
"Su_30",
"Su_34",
"L_39ZA",
"Mi_24V",
"Mi_8MT",
"SA342M",
"SA342L"
],
"awacs": [
"A_50"
],
"tankers": [
"IL_78M"
],
"frontline_units": [
"IFV_BMP_1",
"IFV_BMP_2",
"APC_BTR_80",
"Scout_BRDM_2",
"LT_PT_76",
"APC_MTLB",
"Scout_Cobra",
"MBT_T_55",
"MBT_T_72B",
"MBT_T_90",
"SPAAA_ZSU_57_2"
],
"artillery_units": [
"MLRS_9K57_Uragan_BM_27_220mm",
"SPM_2S9_Nona_120mm_M",
"MLRS_BM_21_Grad_122mm",
"SPH_2S1_Gvozdika_122mm"
],
"logistics_units": [
"Truck_Ural_375",
"LUV_UAZ_469_Jeep"
],
"infantry_units": [
"Paratrooper_AKS",
"Infantry_AK_74_Rus",
"Paratrooper_RPG_16",
"MANPADS_SA_18_Igla_S_Grouse"
],
"air_defenses": [
"ColdWarFlakGenerator",
"SA2Generator",
"SA3Generator",
"SA6Generator",
"SA8Generator",
"SA8Generator",
"SA9Generator",
"SA10Generator",
"SA11Generator",
"SA13Generator",
"SA19Generator",
"ZSU23Generator",
"ZU23Generator",
"ZU23UralGenerator"
],
"ewrs": [
"BoxSpringGenerator",
"TallRackGenerator"
],
"missiles": [
"ScudGenerator"
],
"missiles_group_count": 1,
"aircraft_carrier": [
],
"helicopter_carrier": [
],
"helicopter_carrier_names": [
],
"destroyers": [
],
"cruisers": [
],
"requirements": {},
"carrier_names": [
],
"navy_generators": [
"GrishaGroupGenerator",
"MolniyaGroupGenerator"
]
}

View File

@ -28,7 +28,9 @@
],
"tankers": [
"KC_135",
"KC130"
"KC135MPRS",
"KC130",
"S-3B Tanker"
],
"frontline_units": [
"MBT_M1A2_Abrams",

View File

@ -15,6 +15,10 @@
"awacs": [
"E_2C"
],
"tankers": [
"KC_135",
"KC130"
],
"frontline_units": [
"MBT_M60A3_Patton",
"APC_M113",

View File

@ -18,6 +18,10 @@
"awacs": [
"E_2C"
],
"tankers": [
"KC_135",
"KC130"
],
"frontline_units": [
"MBT_M60A3_Patton",
"APC_M113",

View File

@ -32,7 +32,8 @@
],
"tankers": [
"KC_135",
"KC130"
"KC130",
"S-3B Tanker"
],
"frontline_units": [
"MBT_M1A2_Abrams",

View File

@ -32,7 +32,9 @@
],
"tankers": [
"KC_135",
"KC130"
"KC135MPRS",
"KC130",
"S-3B Tanker"
],
"frontline_units": [
"MBT_M1A2_Abrams",

View File

@ -33,7 +33,9 @@
],
"tankers": [
"KC_135",
"KC130"
"KC135MPRS",
"KC130",
"S-3B Tanker"
],
"frontline_units": [
"MBT_M1A2_Abrams",

View File

@ -28,7 +28,9 @@
],
"tankers": [
"KC_135",
"KC130"
"KC135MPRS",
"KC130",
"S-3B Tanker"
],
"frontline_units": [
"MBT_M1A2_Abrams",

View File

@ -17,7 +17,7 @@
"E_2C"
],
"tankers": [
"S_3B_Tanker"
"S-3B Tanker"
],
"frontline_units": [
"MBT_M60A3_Patton",

View File

@ -2,8 +2,8 @@
<p>
Some player flights may be delayed to start. For such flights, it will not be
possible to enter the cockpit for a delayed flight until its mission start
time, shown in the flight information window.
possible to enter the cockpit until its mission start time, shown in the flight
information window.
</p>
<p>
@ -20,34 +20,30 @@
</p>
<p>
For more information, see the mission planning documentation on
<a href="https://github.com/dcs-liberation/dcs_liberation/wiki/Mission-planning">
the wiki</a>.
For more information, see the
<a
href="https://github.com/dcs-liberation/dcs_liberation/wiki/Mission-planning"
style="color: #ffffff"
>mission planning documentation</a> on our wiki.
</p>
<h2>For Singleplayer:</h2>
<h2>Launching the mission:</h2>
<p>
In DCS, open the Mission Editor and load the file: <i>liberation_nextturn</i>.
Launch the <code>liberation_nextturn</code> mission as you normally would for single-
or multi-player. Note that even for single-player, running the mission with the
dedicated server, <em>even on the same machine</em>, can significantly improve frame
rates, but may cause AI wingmen to behave strangely during taxi.
</p>
<p>
Once the mission is loaded in the ME, use the "FLY" option in the "Flight"
menu to launch.
For advice on using a dedicated server to play DCS Liberation, see
<a
style="color: #ffffff"
href="https://github.com/dcs-liberation/dcs_liberation/wiki/Dedicated-Server-Guide"
>the guide</a> on our wiki.
</p>
<h2>For Multiplayer:</h2>
<p>
In DCS, open the Mission Editor, and load the file: <i>liberation_nextturn</i>
</p>
<p>Select File/Save, exit the mission editor, and then select Multiplayer.</p>
<p>Then host a server with the mission, and tell your friends to join!</p>
<i>(The step in the mission editor is important, and fix a game breaking bug.)</i>
<h2>Finishing</h2>
<p>Once you have played the mission, click on the \"Accept Results\" button.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because it is too large Load Diff