mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-17 03:11:28 +00:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d13ceb847e | |||
| 0f9921f16b | |||
| 82282ad2e4 | |||
| b33f17d3df | |||
| d4b0afa635 | |||
| 9820c26d4b | |||
| d1d94a99dc | |||
| 4767ad45cd | |||
| 7d4432fa47 | |||
| 4b6e860512 | |||
| 2332440f81 | |||
| 5f64ac30f0 | |||
| b5e4846fb1 | |||
| 2146e92154 | |||
| 6b1903466e | |||
| b430a3450e | |||
| 22ae3cf796 | |||
| 62cdcf5536 | |||
| ff55fd5a99 | |||
| 8ee86d3128 | |||
| 2ab3d7150d | |||
| 957b72ab67 | |||
| d4a00e30e1 | |||
| 74174906f3 | |||
| 4e8efc19ac | |||
| 21920f9d2e | |||
| 9a938080b8 | |||
| dae4dc2d40 | |||
| 85bb9a0566 | |||
| 338d38d2a2 | |||
| dde08f2bbe | |||
| 55224c96ab | |||
| 257801edca | |||
| de71c1d903 | |||
| 6863398d52 | |||
| a019a511b1 | |||
| 85ee0ae38e | |||
| f26cbc5b13 | |||
| 23d142a4c9 | |||
| 4956809c3f | |||
| 04befd1b61 | |||
| 5facdd9363 | |||
| 04bea41400 | |||
| a4c4913ead | |||
| 1405e10257 | |||
| d042c778f4 | |||
| d136470149 | |||
| 29dfbbf314 | |||
| c54bd793f2 | |||
| fddac77c79 | |||
| 044a49a61a | |||
| 44aeed0cbd | |||
| 84e20dae29 | |||
| 0806d822ff | |||
| b577b3db29 | |||
| 64433394f5 | |||
| 9fb9b6378e | |||
| a66290ab63 | |||
| 58eeabe3fa | |||
| 2cc7356520 | |||
| c335881b2d | |||
| 993fc45e83 |
@@ -736,12 +736,6 @@ do -- Event Handling
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an option is changed for an AI group.
|
||||
-- The event identifies the initiating group, but does not provide the option ID or value.
|
||||
-- @function [parent=#BASE] OnEventGroupChangeOption
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a player creates a dynamic cargo object from the F8 ground crew menu.
|
||||
-- *** NOTE *** this is a workarounf for DCS not creating these events as of Aug 2024.
|
||||
-- @function [parent=#BASE] OnEventNewDynamicCargo
|
||||
@@ -887,22 +881,6 @@ end
|
||||
world.onEvent(Event)
|
||||
end
|
||||
|
||||
--- Creation of a `S_EVENT_GROUP_CHANGE_OPTION` event.
|
||||
-- @param #BASE self
|
||||
-- @param DCS#Time EventTime The time stamp of the event.
|
||||
-- @param DCS#Group Initiator The initiating group of the event.
|
||||
function BASE:CreateEventGroupChangeOption( EventTime, Initiator )
|
||||
self:F( { EventTime, Initiator } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.GroupChangeOption,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a S_EVENT_NEW_DYNAMIC_CARGO event.
|
||||
-- @param #BASE self
|
||||
-- @param Wrapper.DynamicCargo#DYNAMICCARGO DynamicCargo the dynamic cargo object
|
||||
|
||||
@@ -1663,10 +1663,8 @@ function EVENT:onEvent( Event )
|
||||
self:T( { EventMeta.Text, Event } )
|
||||
end
|
||||
else
|
||||
if Event.id ~= 61 then --- TODO Event 61 is new, but seems to have no real data to be useable, something like option changed.
|
||||
self:E(string.format("WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring(Event.id)))
|
||||
end
|
||||
end
|
||||
|
||||
Event = nil
|
||||
end
|
||||
|
||||
@@ -87,8 +87,7 @@ do -- world
|
||||
-- @field S_EVENT_SIMULATION_UNFREEZE = 58
|
||||
-- @field S_EVENT_HUMAN_AIRCRAFT_REPAIR_START = 59
|
||||
-- @field S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH = 60
|
||||
-- @field S_EVENT_GROUP_CHANGE_OPTION = 61
|
||||
-- @field S_EVENT_MAX = 62
|
||||
-- @field S_EVENT_MAX = 61
|
||||
|
||||
--- The birthplace enumerator is used to define where an aircraft or helicopter has spawned in association with birth events.
|
||||
-- @type world.BirthPlace
|
||||
@@ -615,6 +614,7 @@ do -- Object
|
||||
-- @field SCENERY
|
||||
-- @field CARGO
|
||||
|
||||
---
|
||||
-- @type Object.Desc
|
||||
-- @extends #Desc
|
||||
-- @field #number life initial life level
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4068,8 +4068,8 @@ end
|
||||
-- @param #RAT self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function RAT:_OnBirth(EventData)
|
||||
self:F2(EventData)
|
||||
self:T2(self.lid.."Captured event birth!")
|
||||
self:F3(EventData)
|
||||
self:T3(self.lid.."Captured event birth!")
|
||||
|
||||
local SpawnGroup = EventData.IniGroup --Wrapper.Group#GROUP
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,760 @@
|
||||
--- **Functional** - Enhanced Warsaw Pact GCI Controller.
|
||||
--
|
||||
-- ## Main Features:
|
||||
--
|
||||
-- * Guide AI and human pilots in Warsaw Pact Style. GCI Kernel Functions.
|
||||
-- * Advanced Tactics for Groups.
|
||||
-- * Many additional events that the mission designer can hook into.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Applevangelist**
|
||||
--
|
||||
-- ===
|
||||
-- @module Functional.REDGCI_KERNEL
|
||||
-- @image Func_RedGCI.png
|
||||
-- @version 1.0.0
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--- REDGCI_KERNEL class
|
||||
-- @type REDGCI_KERNEL
|
||||
|
||||
|
||||
---
|
||||
-- # RedGCI — Soviet GCI Doctrine & Player Guide
|
||||
--
|
||||
-- ## Philosophy: Централизованное управление (Centralized Control)
|
||||
--
|
||||
-- The fundamental difference between Soviet and NATO GCI is **who makes the tactical decision**.
|
||||
--
|
||||
-- In NATO doctrine, the GCI controller provides situational awareness — bearing, range, altitude, aspect — and the pilot decides how to prosecute the intercept. The pilot is an autonomous tactician. GCI is an advisor.
|
||||
--
|
||||
-- In Soviet doctrine, the GCI controller **directs**. The pilot executes. The controller selects the intercept geometry, assigns the heading, manages the radar, calls weapons free, and coordinates multi-ship tactics. The pilot's job is to fly the numbers and shoot when told. This is not a flaw — it is the system working as designed. Soviet fighter pilots were trained to be precise executors of GCI instructions, not independent tacticians. The ground radar network (PVO) was the brain; the aircraft was the weapon.
|
||||
--
|
||||
-- RedGCI models this philosophy faithfully.
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
-- ## What to Expect as a Player
|
||||
--
|
||||
-- ### You will not be asked what you want to do.
|
||||
--
|
||||
-- There are no "recommend a vector" calls, no "at your discretion" callouts. The controller tells you your heading, your altitude, and your task. Your acknowledgement is assumed.
|
||||
--
|
||||
-- ### The controller manages your radar.
|
||||
--
|
||||
-- You do not decide when to turn your radar on. The GCI will tell you when to switch on (`локатор` / `Radar on`). Before that call, you fly cold and silent. This preserves your emissions discipline and prevents the target from getting an early RWR spike.
|
||||
--
|
||||
-- ### Weapons free is a controlled event.
|
||||
--
|
||||
-- You do not engage until the controller clears you (`цель разрешена` / `WEAPONS FREE`). The controller determines when geometry, range, and aspect are favorable. Shooting early breaks the coordinated intercept and may compromise your wingman's attack.
|
||||
--
|
||||
-- ### Radio calls are short and military.
|
||||
--
|
||||
-- Soviet GCI brevity is terse by design. Expect calls like:
|
||||
--
|
||||
-- - `"Сокол, курс 170, высота 4500."` — vector, altitude
|
||||
-- - `"Сокол, цель, пара, истребитель. Локатор."` — picture call on commit: count, type, radar on
|
||||
-- - `"Сокол, захват. Дальность 20. Цель разрешена."` — lock confirmed, range, weapons free
|
||||
-- - `"Сокол, молодец. Домой."` — good kill, RTB
|
||||
--
|
||||
-- There are no "BOGEY DOPE" requests, no "BRAA" calls, no "DECLARE" queries. The controller has already done that work. You fly the vector.
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
-- ## State Flow — What the GCI is Doing Behind the Scenes
|
||||
--
|
||||
-- RedGCI manages a state machine that progresses through six phases. Understanding these phases helps you anticipate what call is coming next.
|
||||
--
|
||||
-- ```
|
||||
-- VECTOR → COMMIT → RADAR_CONTACT → VISUAL → MERGE → (SPLASH / ABORT / RTB)
|
||||
-- ```
|
||||
--
|
||||
-- ### VECTOR
|
||||
-- The controller has a track. You are being vectored onto an intercept geometry. Your radar is off. The controller is solving a collision course and updating your heading every tick. Altitude calls reflect the intercept geometry — you may be sent below the target (classic Soviet shoot-up doctrine for radar-limited types) or level/above (MiG-29/Su-27 lookdown geometry). Expect heading updates every 10–15 seconds.
|
||||
--
|
||||
-- **What you should do:** Fly the heading. Don't deviate. Don't turn your radar on yet. Speed is expected at 900kph TAS (depending on airframe)
|
||||
--
|
||||
-- ### COMMIT
|
||||
-- Range has closed to approximately 30km. The controller calls the picture: count and type. Your radar comes on. You are now committed to the intercept — turning away is no longer the default option. The controller is building your radar geometry toward a lock.
|
||||
--
|
||||
-- **What you should do:** Activate your radar. Acquire the target. Do not fire yet.
|
||||
--
|
||||
-- ### RADAR_CONTACT
|
||||
-- You have radar lock (or the AI has achieved it). The controller confirms lock and calls range. If geometry and range are favorable, weapons free follows immediately. If not — for example if aspect angle is unfavorable for a stern conversion — the controller holds fire and waits for better geometry.
|
||||
--
|
||||
-- **What you should do:** Maintain lock. Track the target. Wait for the weapons free call.
|
||||
--
|
||||
-- ### VISUAL
|
||||
-- Range has closed to approximately 5km — visual conditions. Weapons free is automatic at this point. You are now in the merge envelope.
|
||||
--
|
||||
-- **What you should do:** Engage.
|
||||
--
|
||||
-- ### MERGE
|
||||
-- Inside 2km. The GCI transitions to merge control: bearing to target, overshoot calls, separation instructions, reattack vectors. At this range the controller cannot see fine-grained geometry — merge calls are based on relative bearing and closure.
|
||||
--
|
||||
-- **What you should do:** Fight. Listen for overshoot, separation, and reattack calls.
|
||||
--
|
||||
-- ### SPLASH / ABORT / RTB
|
||||
-- - `SPLASH` — kill confirmed, RTB
|
||||
-- - `ABORT (THREAT)` — your RWR is spiked or a threat geometry has developed; break off immediately on the given heading
|
||||
-- - `ABORT (BINGO)` — fuel state critical; break off and return
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
-- ## Multi-Ship (2v2) Tactics (REDGCI2v2)
|
||||
--
|
||||
-- When two fighters are dispatched against a threat, the GCI selects a tactic automatically based on the tactical situation. The tactic is applied at COMMIT — until then, both fighters are vectored together toward the intercept midpoint.
|
||||
--
|
||||
-- | Tactic | Description |
|
||||
-- |--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
-- | **PINCER** | Classic bracket. F1 and F2 split left and right, attacking from opposite angles simultaneously. Forces the target to choose which threat to react to. |
|
||||
-- | **HIGH-LOW** | Vertical split. One fighter attacks from below (radar up, clean sky background), one from above. Degrades the target's ability to acquire both simultaneously. |
|
||||
-- | **STAGGER** | BVR timing offset. F1 fires first at long range, F2 follows 8–13km behind to engage a maneuvering or defending target. |
|
||||
-- | **TRAIL** | Close trail. F1 is the shooter, F2 is support — ready to engage if F1 overshoots or is defeated. |
|
||||
-- | **GIRAFFE** | *(Historical — Iraq/Iran War, Mirage F1 vs F-14A)* F1 attacks at normal altitude, binding the AWG-9 radar. F2 flies nap-of-earth |
|
||||
-- | | (300–600m AGL) using ground clutter to degrade radar detection, then pulls up and fires from close range. |
|
||||
--
|
||||
-- During a tactic split, you may receive a heading that seems unusual — a large lateral offset or an unexpected altitude change. **Trust the vector.** The controller is positioning you for the tactic geometry. The merge point will bring you back onto the target.
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
-- ## Dispatcher & CAP Flow (REDGCI_DISPATCHER)
|
||||
--
|
||||
-- When using the dispatcher layer, the full operational flow is:
|
||||
--
|
||||
-- ```
|
||||
-- Spawn at homeplate
|
||||
-- → Taxi and takeoff (template-controlled)
|
||||
-- → Transit to CAP zone
|
||||
-- → Orbit in assigned zone (radar cold, weapons safe)
|
||||
-- ↓ INTEL detects threat cluster
|
||||
-- → "Attention, radar contact. Pair, fighter, 45 kilometers." (all CAP fighters)
|
||||
-- ↓ Dispatcher assigns pair
|
||||
-- → "101 102, intercept. Pair, fighter." (dispatched pair)
|
||||
-- → VECTOR → COMMIT → RADAR_CONTACT → VISUAL → MERGE → SPLASH
|
||||
-- ↓ Engagement complete
|
||||
-- → AI: RTB waypoint → land → despawn → respawn after delay
|
||||
-- → Human: "101, mission complete. RTB, refuel and rearm."
|
||||
-- ↓ After RespawnDelay
|
||||
-- → New AI pair spawns into same CAP zone
|
||||
-- ```
|
||||
--
|
||||
-- Human players are dispatched first when available. If a human and AI are both in the CAP pool, the human is always assigned to the next intercept. AI fills gaps. The dispatcher does not send a single fighter if a pair is available — pairing is always preferred.
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
-- ## Key Differences from NATO GCI at a Glance
|
||||
--
|
||||
-- | | Soviet (RedGCI) | NATO |
|
||||
-- |--------------------|--------------------------------------|------------------------------------|
|
||||
-- | Tactical decision | Controller | Pilot |
|
||||
-- | Radar management | Controller-commanded | Pilot-initiated |
|
||||
-- | Weapons free | Controller-called | Pilot-discretion (after WF) |
|
||||
-- | Heading calls | Prescriptive | Advisory |
|
||||
-- | Brevity style | Terse, military, positional | Standardized (BRAA, DECLARE, etc.) |
|
||||
-- | Multi-ship tactics | Centrally planned, applied at COMMIT | Mutually briefed, pilot-executed |
|
||||
-- | Pilot autonomy | Low (by design) | High |
|
||||
--
|
||||
-- **The Soviet system is not inferior** — it is optimized for a different kind of pilot and a different operational context. Mass interception of large NATO strike packages over defended Soviet airspace demanded centralized, efficient, high-throughput GCI control. RedGCI brings that experience to DCS.
|
||||
--
|
||||
-- @field #REDGCI_KERNEL
|
||||
REDGCI_KERNEL = {}
|
||||
REDGCI_KERNEL.version = "1.0.0"
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- Konstanten (aus gci_types.h)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
REDGCI_KERNEL.C = {
|
||||
RANGE_VECTOR_START = 60000.0,
|
||||
RANGE_COMMIT = 30000.0,
|
||||
RANGE_RADAR_FLOOR = 20000.0,
|
||||
RANGE_VISUAL = 5000.0,
|
||||
RANGE_MERGE = 2000.0,
|
||||
WF_RANGE_MAX = 25000.0,
|
||||
ALT_OFFSET_LOOKDOWN = 0.0,
|
||||
ASPECT_NOTCH_MIN = 80.0,
|
||||
ASPECT_NOTCH_MAX = 100.0,
|
||||
ASPECT_REAR_ATTACK = 120.0,
|
||||
MAX_TTI = 600.0,
|
||||
TICK_INTERVAL = 15.0,
|
||||
FUEL_BINGO = 0.25,
|
||||
DELAY_MIN = 3.0,
|
||||
DELAY_MAX = 8.0,
|
||||
DELAY_MERGE_MIN = 2.0,
|
||||
DELAY_MERGE_MAX = 4.0,
|
||||
TACTIC_PINCER = 0,
|
||||
TACTIC_HIGH_LOW = 1,
|
||||
TACTIC_STAGGER = 2,
|
||||
TACTIC_TRAIL = 3,
|
||||
TACTIC_GIRAFFE = 4, -- Irak/Iran-Doktrin: F1=Decoy normal, F2=Nap-of-Earth im Groundclutter
|
||||
PURSUIT_COLLISION = 0,
|
||||
PURSUIT_LEAD = 1,
|
||||
PURSUIT_PURE = 2,
|
||||
PURSUIT_NO_SOLUTION = 3,
|
||||
}
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- Hilfsfunktionen
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.clamp(v, lo, hi)
|
||||
if v < lo then return lo end
|
||||
if v > hi then return hi end
|
||||
return v
|
||||
end
|
||||
|
||||
function REDGCI_KERNEL.vec2len(x, z)
|
||||
return math.sqrt(x*x + z*z)
|
||||
end
|
||||
|
||||
function REDGCI_KERNEL.bearing(dx, dz)
|
||||
local b = math.deg(math.atan2(dx, dz))
|
||||
return b < 0.0 and b + 360.0 or b
|
||||
end
|
||||
|
||||
function REDGCI_KERNEL.randDelay(lo, hi)
|
||||
return lo + UTILS.LCGRandom() * (hi - lo)
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- Aspect Angle (0=Nose-on, 90=Beam, 180=Tail)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.aspectAngle(target, observer)
|
||||
local dx = observer.x - target.x
|
||||
local dz = observer.z - target.z
|
||||
local range = REDGCI_KERNEL.vec2len(dx, dz)
|
||||
if range < 1.0 then return 0.0 end
|
||||
local nx = dx / range
|
||||
local nz = dz / range
|
||||
local spd = (target.speed or 1.0) + 1e-6
|
||||
local tvx = (target.vx or 0.0) / spd
|
||||
local tvz = (target.vz or 0.0) / spd
|
||||
local dot = REDGCI_KERNEL.clamp(tvx*nx + tvz*nz, -1.0, 1.0)
|
||||
return math.deg(math.acos(dot))
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- Closure Rate (positiv = Annäherung)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.closureRate(f, t)
|
||||
local dx = t.x - f.x
|
||||
local dz = t.z - f.z
|
||||
local range = REDGCI_KERNEL.vec2len(dx, dz)
|
||||
if range < 1.0 then return 0.0 end
|
||||
local nx = dx / range
|
||||
local nz = dz / range
|
||||
local dvx = (t.vx or 0.0) - (f.vx or 0.0)
|
||||
local dvz = (t.vz or 0.0) - (f.vz or 0.0)
|
||||
return -(dvx*nx + dvz*nz)
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- _solveCollision (intern, GCI-Koordinaten)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL._solveCollision(f, t)
|
||||
local C = REDGCI_KERNEL.C
|
||||
local dx = t.x - f.x
|
||||
local dz = t.z - f.z
|
||||
local vtx = t.vx or 0.0
|
||||
local vtz = t.vz or 0.0
|
||||
local vf = f.speed or 1.0
|
||||
local a = vtx*vtx + vtz*vtz - vf*vf
|
||||
local b = 2.0 * (dx*vtx + dz*vtz)
|
||||
local c = dx*dx + dz*dz
|
||||
local sol_t = -1.0
|
||||
if math.abs(a) < 1.0 then
|
||||
if math.abs(b) > 0.01 then
|
||||
sol_t = -c / b
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
local disc = b*b - 4.0*a*c
|
||||
if disc < 0.0 then return false end
|
||||
local sq = math.sqrt(disc)
|
||||
local t1 = (-b - sq) / (2.0 * a)
|
||||
local t2 = (-b + sq) / (2.0 * a)
|
||||
if t1 > 0.0 and t2 > 0.0 then sol_t = math.min(t1, t2)
|
||||
elseif t1 > 0.0 then sol_t = t1
|
||||
elseif t2 > 0.0 then sol_t = t2
|
||||
else return false
|
||||
end
|
||||
end
|
||||
if sol_t < 0.0 or sol_t > C.MAX_TTI then return false end
|
||||
local ip = {
|
||||
x = t.x + vtx * sol_t,
|
||||
z = t.z + vtz * sol_t,
|
||||
y = math.max(t.y + C.ALT_OFFSET_LOOKDOWN, 300.0),
|
||||
}
|
||||
local hdg = REDGCI_KERNEL.bearing(ip.x - f.x, ip.z - f.z)
|
||||
return true, hdg, sol_t, ip
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- _solveLead (intern, GCI-Koordinaten)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL._solveLead(f, t)
|
||||
local C = REDGCI_KERNEL.C
|
||||
local dx = t.x - f.x
|
||||
local dz = t.z - f.z
|
||||
local range = REDGCI_KERNEL.vec2len(dx, dz)
|
||||
if range < 1.0 then return 0.0, 0.0 end
|
||||
local base_bearing = REDGCI_KERNEL.bearing(dx, dz)
|
||||
local aspect_rad = math.rad(REDGCI_KERNEL.aspectAngle(t, f))
|
||||
local speed_ratio = (t.speed or 1.0) / ((f.speed or 1.0) + 1e-6)
|
||||
local sin_lead = REDGCI_KERNEL.clamp(speed_ratio * math.sin(aspect_rad), -1.0, 1.0)
|
||||
local lead_deg = math.deg(math.asin(sin_lead))
|
||||
local hdg
|
||||
if math.abs(lead_deg) < 45.0 then
|
||||
hdg = (base_bearing + lead_deg + 360.0) % 360.0
|
||||
else
|
||||
hdg = base_bearing
|
||||
end
|
||||
local closing = REDGCI_KERNEL.closureRate(f, t)
|
||||
if closing < 50.0 then closing = 50.0 end
|
||||
local tti = math.min(range / closing, C.MAX_TTI)
|
||||
return hdg, tti
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- computeIntercept (GCI-Koordinaten intern)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.computeIntercept(fighter, target)
|
||||
local C = REDGCI_KERNEL.C
|
||||
local dx = target.x - fighter.x
|
||||
local dz = target.z - fighter.z
|
||||
local sol = {
|
||||
heading_deg = 0.0,
|
||||
time_to_intercept = C.MAX_TTI,
|
||||
intercept_point = { x=target.x, z=target.z, y=target.y },
|
||||
target_alt = target.y,
|
||||
solution_found = false,
|
||||
aspect_angle = REDGCI_KERNEL.aspectAngle(target, fighter),
|
||||
range = REDGCI_KERNEL.vec2len(dx, dz),
|
||||
mode = C.PURSUIT_NO_SOLUTION,
|
||||
weapons_free = false,
|
||||
}
|
||||
local closure = REDGCI_KERNEL.closureRate(fighter, target)
|
||||
local projected_range = sol.range - closure * C.TICK_INTERVAL
|
||||
sol.weapons_free = (sol.range < C.WF_RANGE_MAX) or
|
||||
(closure > 0.0 and projected_range < C.WF_RANGE_MAX)
|
||||
local ok, hdg, tti, ip = REDGCI_KERNEL._solveCollision(fighter, target)
|
||||
if ok then
|
||||
sol.heading_deg = hdg
|
||||
sol.time_to_intercept = tti
|
||||
sol.intercept_point = ip
|
||||
sol.solution_found = true
|
||||
sol.mode = C.PURSUIT_COLLISION
|
||||
return sol
|
||||
end
|
||||
local lhdg, ltti = REDGCI_KERNEL._solveLead(fighter, target)
|
||||
sol.heading_deg = lhdg
|
||||
sol.time_to_intercept = ltti
|
||||
sol.solution_found = true
|
||||
sol.mode = C.PURSUIT_LEAD
|
||||
sol.intercept_point = {
|
||||
x = target.x + (target.vx or 0.0) * ltti,
|
||||
z = target.z + (target.vz or 0.0) * ltti,
|
||||
y = math.max(target.y + C.ALT_OFFSET_LOOKDOWN, 300.0),
|
||||
}
|
||||
return sol
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- computeInterceptDCS (DCS-Koordinaten Ein/Aus)
|
||||
-- Flat-Rückgabe kompatibel mit alter C-API
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.computeInterceptDCS(f, t)
|
||||
local f_gci = { x=f.z, z=f.x, y=f.y, vx=f.vz, vz=f.vx, vy=f.vy, speed=f.spd }
|
||||
local t_gci = { x=t.z, z=t.x, y=t.y, vx=t.vz, vz=t.vx, vy=t.vy, speed=t.spd }
|
||||
local sol = REDGCI_KERNEL.computeIntercept(f_gci, t_gci)
|
||||
-- GCI→DCS: ip.z(Nord)→DCS.x, ip.x(Ost)→DCS.z
|
||||
return sol.heading_deg,
|
||||
sol.time_to_intercept,
|
||||
sol.mode,
|
||||
sol.weapons_free,
|
||||
sol.range,
|
||||
sol.aspect_angle,
|
||||
sol.intercept_point.z,
|
||||
sol.intercept_point.x,
|
||||
sol.intercept_point.y,
|
||||
sol.target_alt
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- computeSplit (GCI-Koordinaten intern)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.computeSplit(f1, f2, tgt, tactic, variation)
|
||||
local C = REDGCI_KERNEL.C
|
||||
variation = REDGCI_KERNEL.clamp(variation or 0.5, 0.0, 1.0)
|
||||
tactic = tactic or C.TACTIC_PINCER
|
||||
local mid_x = (f1.x + f2.x) * 0.5
|
||||
local mid_z = (f1.z + f2.z) * 0.5
|
||||
local dx = tgt.x - mid_x
|
||||
local dz = tgt.z - mid_z
|
||||
local rng = REDGCI_KERNEL.vec2len(dx, dz)
|
||||
if rng < 1.0 then rng = 1.0 end
|
||||
local ax = dx / rng
|
||||
local az = dz / rng
|
||||
local px = -az
|
||||
local pz = ax
|
||||
|
||||
local plan = {
|
||||
tactic = tactic,
|
||||
wp_f1 = { x=0, z=0, y=0 },
|
||||
wp_f2 = { x=0, z=0, y=0 },
|
||||
merge_f1 = { x=0, z=0, y=0 },
|
||||
merge_f2 = { x=0, z=0, y=0 },
|
||||
}
|
||||
|
||||
local function clamp_alt(pt)
|
||||
if pt.y < 300.0 then pt.y = 300.0 end
|
||||
end
|
||||
|
||||
local function clamp_alt_noe(pt)
|
||||
if pt.y < 150.0 then pt.y = 150.0 end
|
||||
end
|
||||
|
||||
-- GIRAFFE F2 fliegt NOE — separater clamp mit niedrigerer Mindesthöhe
|
||||
local function clamp_alt_noe(pt)
|
||||
if pt.y < 150.0 then pt.y = 150.0 end
|
||||
end
|
||||
|
||||
if tactic == C.TACTIC_PINCER then
|
||||
local spread = 12000.0 + variation * 5000.0
|
||||
local approach = rng * 0.45
|
||||
local merge_off = spread * 0.30
|
||||
plan.wp_f1 = { x=mid_x+ax*approach+px*spread, z=mid_z+az*approach+pz*spread, y=tgt.y }
|
||||
plan.wp_f2 = { x=mid_x+ax*approach-px*spread, z=mid_z+az*approach-pz*spread, y=tgt.y }
|
||||
plan.merge_f1 = { x=tgt.x-ax*3000+px*merge_off, z=tgt.z-az*3000+pz*merge_off, y=tgt.y }
|
||||
plan.merge_f2 = { x=tgt.x-ax*3000-px*merge_off, z=tgt.z-az*3000-pz*merge_off, y=tgt.y }
|
||||
|
||||
elseif tactic == C.TACTIC_HIGH_LOW then
|
||||
local vert = 3000.0 + variation * 1500.0
|
||||
local approach = rng * 0.50
|
||||
local side_off = 2000.0
|
||||
plan.wp_f1 = { x=mid_x+ax*approach+px*side_off, z=mid_z+az*approach+pz*side_off, y=tgt.y-500.0 }
|
||||
plan.wp_f2 = { x=mid_x+ax*approach-px*side_off, z=mid_z+az*approach-pz*side_off, y=tgt.y+vert }
|
||||
plan.merge_f1 = { x=tgt.x-ax*3000+px*side_off, z=tgt.z-az*3000+pz*side_off, y=plan.wp_f1.y }
|
||||
plan.merge_f2 = { x=tgt.x-ax*3000-px*side_off, z=tgt.z-az*3000-pz*side_off, y=plan.wp_f2.y }
|
||||
|
||||
elseif tactic == C.TACTIC_STAGGER then
|
||||
local lag = 8000.0 + variation * 3000.0
|
||||
local lead_dist = rng * 0.85
|
||||
plan.wp_f1 = { x=mid_x+ax*lead_dist, z=mid_z+az*lead_dist, y=tgt.y }
|
||||
plan.wp_f2 = { x=mid_x+ax*(lead_dist-lag), z=mid_z+az*(lead_dist-lag), y=tgt.y }
|
||||
plan.merge_f1 = { x=plan.wp_f1.x, z=plan.wp_f1.z, y=plan.wp_f1.y }
|
||||
plan.merge_f2 = { x=plan.wp_f2.x, z=plan.wp_f2.z, y=plan.wp_f2.y }
|
||||
|
||||
elseif tactic == C.TACTIC_TRAIL then
|
||||
local lag = 3000.0 + variation * 2000.0
|
||||
local lead_dist = rng * 0.85
|
||||
local side_off = 500.0
|
||||
plan.wp_f1 = { x=mid_x+ax*lead_dist, z=mid_z+az*lead_dist, y=tgt.y }
|
||||
plan.wp_f2 = { x=mid_x+ax*(lead_dist-lag)+px*side_off, z=mid_z+az*(lead_dist-lag)+pz*side_off, y=tgt.y }
|
||||
plan.merge_f1 = { x=plan.wp_f1.x, z=plan.wp_f1.z, y=plan.wp_f1.y }
|
||||
plan.merge_f2 = { x=plan.wp_f2.x, z=plan.wp_f2.z, y=plan.wp_f2.y }
|
||||
|
||||
elseif tactic == C.TACTIC_GIRAFFE then
|
||||
-- ── GIRAFFE: Irak/Iran-Doktrin (Mirage F1 vs F-14A) ──────────────
|
||||
--
|
||||
-- F1 = Decoy: normale Höhe, direkter Anflug, bindet AWG-9 Radar.
|
||||
-- Zieht Phoenixe auf sich — gibt F2 Zeit für Pull-up.
|
||||
--
|
||||
-- F2 = Killer: Nap-of-Earth (~300-600m AGL/MSL) weit seitlich versetzt.
|
||||
-- Nutzt Groundclutter um AWG-9 Look-Down zu degradieren.
|
||||
-- Nähert sich bis 10km vor Ziel, dann Pull-up und Schuss.
|
||||
-- Seitlicher Versatz ~8-12km damit F2 nicht im Radarsektor
|
||||
-- des AWG-9 liegt während F1 den Lock hält.
|
||||
--
|
||||
-- Historisch: Iran-Irak Krieg 1982-88. Irakische Mirage F1EQ nutzten
|
||||
-- dieses Profil gegen F-14A/AIM-54 Phoenix — der AWG-9 hatte trotz
|
||||
-- Look-Down-Fähigkeit bei sehr tiefen Zielen über unebenen Terrain
|
||||
-- (Zagros-Berge, Khuzestan-Ebene) erhöhte Clutter-Probleme.
|
||||
--
|
||||
-- Höhen: neutral (0.0) — Lua addiert AltOffset + terrain-awareness.
|
||||
-- Mindesthöhe 300m MSL wird am Ende geclampt.
|
||||
|
||||
local noe_alt = 300.0 + variation * 300.0 -- 300-600m MSL (Nap-of-Earth)
|
||||
local side_off = 8000.0 + variation * 4000.0 -- 8-12km seitlich (aus AWG-9 Sektor)
|
||||
local approach = rng * 0.60 -- F1 direkter Anflug, 60% des Weges
|
||||
local noe_dist = rng * 0.75 -- F2 nähert sich weiter ran vor Pull-up
|
||||
|
||||
plan.wp_f1 = { x=mid_x+ax*approach+px*2000, z=mid_z+az*approach+pz*2000, y=tgt.y }
|
||||
plan.merge_f1 = { x=tgt.x-ax*5000+px*2000, z=tgt.z-az*5000+pz*2000, y=tgt.y }
|
||||
plan.wp_f2 = { x=mid_x+ax*noe_dist-px*side_off, z=mid_z+az*noe_dist-pz*side_off, y=noe_alt, absolute_alt=true }
|
||||
plan.merge_f2 = { x=tgt.x-ax*10000-px*side_off*0.3, z=tgt.z-az*10000-pz*side_off*0.3, y=tgt.y }
|
||||
|
||||
else
|
||||
plan.wp_f1 = { x=tgt.x, z=tgt.z, y=tgt.y }
|
||||
plan.wp_f2 = { x=tgt.x, z=tgt.z, y=tgt.y }
|
||||
plan.merge_f1 = { x=tgt.x, z=tgt.z, y=tgt.y }
|
||||
plan.merge_f2 = { x=tgt.x, z=tgt.z, y=tgt.y }
|
||||
end
|
||||
|
||||
clamp_alt(plan.wp_f1)
|
||||
if tactic == C.TACTIC_GIRAFFE then
|
||||
clamp_alt_noe(plan.wp_f2)
|
||||
else
|
||||
clamp_alt(plan.wp_f2)
|
||||
end
|
||||
clamp_alt(plan.merge_f1)
|
||||
clamp_alt(plan.merge_f2)
|
||||
return plan
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- computeSplitDCS (DCS-Koordinaten Ein/Aus)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.computeSplitDCS(f1, f2, tgt, tactic, variation)
|
||||
local function dcs2gci(u)
|
||||
return { x=u.z, z=u.x, y=u.y, vx=u.vz or 0, vz=u.vx or 0, speed=u.spd or 0 }
|
||||
end
|
||||
local function gci2dcs(pt)
|
||||
return { x=pt.z, z=pt.x, y=pt.y, absolute_alt=pt.absolute_alt }
|
||||
end
|
||||
local tgt_gci = { x=tgt.z, z=tgt.x, y=tgt.y }
|
||||
local plan = REDGCI_KERNEL.computeSplit(
|
||||
dcs2gci(f1), dcs2gci(f2), tgt_gci, tactic, variation)
|
||||
plan.wp_f1 = gci2dcs(plan.wp_f1)
|
||||
plan.wp_f2 = gci2dcs(plan.wp_f2)
|
||||
plan.merge_f1 = gci2dcs(plan.merge_f1)
|
||||
plan.merge_f2 = gci2dcs(plan.merge_f2)
|
||||
return plan
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- buildTransmission (Port von gci_build_transmission)
|
||||
--
|
||||
-- ctx/prev Felder: state, prev_state, ticks_in_state, range,
|
||||
-- aspect_angle, closure_rate, altitude_delta, fuel_fraction
|
||||
-- sol Felder: heading_deg, time_to_intercept, target_alt,
|
||||
-- range, aspect_angle, weapons_free
|
||||
-- Rückgabe: { token_str, delay_sec, weapons_free, silence }
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.buildTransmission(ctx, prev, sol)
|
||||
local C = REDGCI_KERNEL.C
|
||||
local tx = {
|
||||
token_str = "",
|
||||
delay_sec = REDGCI_KERNEL.clamp(
|
||||
REDGCI_KERNEL.randDelay(C.DELAY_MIN, C.DELAY_MAX), 3.0, 8.0),
|
||||
weapons_free = sol.weapons_free,
|
||||
silence = false,
|
||||
priority = 50,
|
||||
}
|
||||
|
||||
local hdg_i = math.floor((sol.heading_deg or 0) + 0.5)
|
||||
local alt_i = math.floor((sol.target_alt or 0) / 100.0 + 0.5) * 100
|
||||
local rng_km = math.floor((ctx.range or 0) / 1000.0 + 0.5)
|
||||
local aspect_i = math.floor((ctx.aspect_angle or 0) + 0.5)
|
||||
local delay = tx.delay_sec
|
||||
local state = ctx.state or "VECTOR"
|
||||
local prev_state = prev.state or "VECTOR"
|
||||
local ticks = ctx.ticks_in_state or 0
|
||||
|
||||
local function emit(fmt, ...)
|
||||
tx.token_str = string.format(fmt, ...)
|
||||
end
|
||||
|
||||
if state == "VECTOR" then
|
||||
if prev_state ~= "VECTOR" then
|
||||
local tti_m = math.floor((sol.time_to_intercept or 0) / 60.0)
|
||||
local tti_s = math.floor(sol.time_to_intercept or 0) % 60
|
||||
if tti_m > 0 then
|
||||
emit("VECTOR_WITH_TTI|hdg=%d|alt=%d|rng=%d|tti_m=%d|tti_s=%d|delay=%.1f",
|
||||
hdg_i, alt_i, rng_km, tti_m, tti_s, delay)
|
||||
else
|
||||
emit("VECTOR|hdg=%d|alt=%d|rng=%d|delay=%.1f",
|
||||
hdg_i, alt_i, rng_km, delay)
|
||||
end
|
||||
else
|
||||
local hdg_delta = math.abs((sol.heading_deg or 0) - (ctx.aspect_angle or 0))
|
||||
if hdg_delta < 5.0 and ticks > 3 then
|
||||
tx.silence = true
|
||||
else
|
||||
emit("VECTOR|hdg=%d|alt=%d|rng=%d|delay=%.1f",
|
||||
hdg_i, alt_i, rng_km, delay)
|
||||
end
|
||||
end
|
||||
|
||||
elseif state == "COMMIT" then
|
||||
if prev_state ~= "COMMIT" then
|
||||
tx.priority = 100
|
||||
emit("COMMIT_FIRST|hdg=%d|alt=%d|rng=%d|aspect=%d|delay=%.1f",
|
||||
hdg_i, alt_i, rng_km, aspect_i, delay)
|
||||
elseif ticks == 6 then
|
||||
emit("COMMIT_NO_LOCK|hdg=%d|rng=%d|aspect=%d|delay=%.1f",
|
||||
hdg_i, rng_km, aspect_i, delay)
|
||||
elseif ticks > 8 then
|
||||
emit("COMMIT_NUDGE|hdg=%d|aspect=%d|delay=%.1f",
|
||||
hdg_i, aspect_i, delay)
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
elseif state == "RADAR_CONTACT" then
|
||||
if prev_state ~= "RADAR_CONTACT" then
|
||||
if sol.weapons_free then
|
||||
tx.priority = 100
|
||||
emit("RADAR_LOCK_WF|rng=%d|delay=%.1f", rng_km, delay)
|
||||
tx.weapons_free = true
|
||||
else
|
||||
emit("RADAR_LOCK_HOLD|rng=%d|delay=%.1f", rng_km, delay)
|
||||
end
|
||||
elseif not sol.weapons_free
|
||||
and (ctx.range or 0) < C.WF_RANGE_MAX
|
||||
and (ctx.aspect_angle or 0) > C.ASPECT_REAR_ATTACK
|
||||
and prev_state == "RADAR_CONTACT" then
|
||||
emit("RADAR_WF_NOW|rng=%d|delay=%.1f", rng_km, delay)
|
||||
tx.priority = 100
|
||||
tx.weapons_free = true
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
elseif state == "VISUAL" then
|
||||
if prev_state ~= "VISUAL" then
|
||||
emit("VISUAL_CONFIRM|rng=%d|delay=%.1f", rng_km, delay)
|
||||
tx.weapons_free = true
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
elseif state == "NOTCH" then
|
||||
if prev_state ~= "NOTCH" then
|
||||
emit("NOTCH_ENTRY|delay=1.5")
|
||||
elseif ticks % 8 == 0 then
|
||||
emit("NOTCH_UPDATE|rng=%d|aspect=%d|delay=%.1f",
|
||||
rng_km, aspect_i, delay)
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
elseif state == "ABORT" then
|
||||
tx.delay_sec = 1.5
|
||||
if (ctx.fuel_fraction or 1.0) < C.FUEL_BINGO then
|
||||
emit("ABORT_BINGO|hdg=%d|delay=1.5", hdg_i)
|
||||
else
|
||||
emit("ABORT_THREAT|hdg=%d|delay=1.5", hdg_i)
|
||||
end
|
||||
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
return tx
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- mergeTransition (Port von gci_merge_transition)
|
||||
--
|
||||
-- ctx Felder: phase, ticks_in_phase, range, bearing_to_target,
|
||||
-- closure_rate, altitude_delta, pass_count, radar_lost
|
||||
-- Rückgabe: phase string
|
||||
-- "ENTRY"|"OVERSHOOT"|"SEPARATION"|"REATTACK"|"LOST"|"SPLASH"
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.mergeTransition(ctx, prev)
|
||||
if ctx.radar_lost then return "LOST" end
|
||||
if (ctx.closure_rate or 0) < -30.0 and (ctx.range or 0) > 3000.0 then
|
||||
return "SEPARATION"
|
||||
end
|
||||
local brg = ctx.bearing_to_target or 0
|
||||
if brg > 100.0 and brg < 260.0 and (ctx.range or 0) < 5000.0 then
|
||||
return "OVERSHOOT"
|
||||
end
|
||||
if ctx.phase == "SEPARATION" and (ctx.pass_count or 0) < 3 then
|
||||
return "REATTACK"
|
||||
end
|
||||
return ctx.phase
|
||||
end
|
||||
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
-- buildMergeTransmission (Port von gci_build_merge_transmission)
|
||||
-- ─────────────────────────────────────────────────────────────
|
||||
|
||||
function REDGCI_KERNEL.buildMergeTransmission(ctx, prev)
|
||||
local C = REDGCI_KERNEL.C
|
||||
local tx = {
|
||||
token_str = "",
|
||||
delay_sec = REDGCI_KERNEL.clamp(
|
||||
REDGCI_KERNEL.randDelay(C.DELAY_MERGE_MIN, C.DELAY_MERGE_MAX), 2.0, 5.0),
|
||||
weapons_free = false,
|
||||
silence = false,
|
||||
priority = 50,
|
||||
}
|
||||
|
||||
local brg = math.floor((ctx.bearing_to_target or 0) + 0.5)
|
||||
local rng_km = math.floor((ctx.range or 0) / 1000.0 + 0.5)
|
||||
local delay = tx.delay_sec
|
||||
local phase = ctx.phase or "ENTRY"
|
||||
local prev_phase = prev.phase or "ENTRY"
|
||||
local ticks = ctx.ticks_in_phase or 0
|
||||
|
||||
local dir_rl = ((ctx.bearing_to_target or 0) < 180.0) and "right" or "left"
|
||||
local alt_d = ctx.altitude_delta or 0
|
||||
local alt_rel = ""
|
||||
if alt_d > 400.0 then alt_rel = "low"
|
||||
elseif alt_d < -400.0 then alt_rel = "high"
|
||||
end
|
||||
|
||||
local function emit(fmt, ...)
|
||||
tx.token_str = string.format(fmt, ...)
|
||||
end
|
||||
|
||||
if phase == "ENTRY" then
|
||||
tx.priority = 100
|
||||
emit("MERGE_ENTRY|brg=%d|dir_rl=%s|delay=%.1f", brg, dir_rl, delay)
|
||||
|
||||
elseif phase == "OVERSHOOT" then
|
||||
emit("MERGE_OVERSHOOT|brg=%d|dir_rl=%s|alt_rel=%s|delay=%.1f",
|
||||
brg, dir_rl, alt_rel, delay)
|
||||
|
||||
elseif phase == "SEPARATION" then
|
||||
if (ctx.pass_count or 0) < 3 then
|
||||
emit("MERGE_REATTACK|brg=%d|rng=%d|delay=%.1f", brg, rng_km, delay)
|
||||
else
|
||||
emit("ABORT_THREAT|hdg=%d|delay=%.1f", brg, delay)
|
||||
end
|
||||
|
||||
elseif phase == "REATTACK" then
|
||||
if prev_phase ~= "REATTACK" or ticks % 3 == 0 then
|
||||
emit("MERGE_REATTACK|brg=%d|rng=%d|delay=%.1f", brg, rng_km, delay)
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
elseif phase == "LOST" then
|
||||
if prev_phase ~= "LOST" or ticks == 4 then
|
||||
emit("MERGE_LOST|brg=%d|rng=%d|delay=%.1f", brg, rng_km, delay)
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
elseif phase == "SPLASH" then
|
||||
tx.delay_sec = 1.5
|
||||
tx.priority = 100
|
||||
emit("MERGE_SPLASH|delay=1.5")
|
||||
|
||||
else
|
||||
tx.silence = true
|
||||
end
|
||||
|
||||
return tx
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- END of Class
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -80,6 +80,11 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Stratego.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/ClientWatch.lua')
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Formation.lua')
|
||||
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/RedGCIKernel.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/RedGCI.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/RedGCI2v2.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/RedGCIDispatcher.lua' )
|
||||
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/Airboss.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/RecoveryTanker.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Ops/RescueHelo.lua' )
|
||||
|
||||
@@ -189,14 +189,13 @@ AIRWING = {
|
||||
|
||||
--- AIRWING class version.
|
||||
-- @field #string version
|
||||
AIRWING.version="0.9.8"
|
||||
AIRWING.version="0.9.7"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Check that airbase has enough parking spots if a request is BIG.
|
||||
-- DONE: Allow groupping parameter for CAP flights
|
||||
-- DONE: Allow (moving) zones as base for patrol points.
|
||||
-- DONE: Spawn in air ==> Needs WAREHOUSE update.
|
||||
-- DONE: Spawn hot.
|
||||
@@ -234,7 +233,6 @@ function AIRWING:New(warehousename, airwingname)
|
||||
|
||||
-- Defaults:
|
||||
self.nflightsCAP=0
|
||||
self.nCAPgrouping=1
|
||||
self.nflightsAWACS=0
|
||||
self.nflightsRecon=0
|
||||
self.nflightsTANKERboom=0
|
||||
@@ -742,11 +740,9 @@ end
|
||||
--- Set number of CAP flights constantly carried out.
|
||||
-- @param #AIRWING self
|
||||
-- @param #number n (Optional) Number of flights. Default 1.
|
||||
-- @param #number grouping (optional) Number of assets per flight. Default 1.
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetNumberCAP(n,grouping)
|
||||
function AIRWING:SetNumberCAP(n)
|
||||
self.nflightsCAP=n or 1
|
||||
self.nCAPgrouping = grouping or 1
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1274,12 +1270,10 @@ function AIRWING:CheckCAP()
|
||||
if self.capOptionPatrolRaceTrack then
|
||||
|
||||
missionCAP=AUFTRAG:NewPATROL_RACETRACK(patrol.coord,altitude,patrol.speed,patrol.heading,patrol.leg, self.capFormation)
|
||||
missionCAP:SetRequiredAssets(self.nCAPgrouping,self.nCAPgrouping)
|
||||
|
||||
else
|
||||
|
||||
missionCAP=AUFTRAG:NewGCICAP(patrol.coord, altitude, patrol.speed, patrol.heading, patrol.leg)
|
||||
missionCAP:SetRequiredAssets(self.nCAPgrouping,self.nCAPgrouping)
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
-- **Supported Aircraft:**
|
||||
--
|
||||
-- * [F/A-18C Hornet Lot 20](https://forums.eagle.ru/forumdisplay.php?f=557) (Player & AI)
|
||||
-- * [F-14A/B/B(U)/A Early Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
|
||||
-- * [F-14A/B/A Early Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
|
||||
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
|
||||
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI)
|
||||
-- * [T-45C Goshawk](https://forum.dcs.world/topic/203816-vnao-t-45-goshawk/) (VNAO mod) (Player & AI)
|
||||
@@ -1276,7 +1276,6 @@ AIRBOSS = {
|
||||
-- @field #string A4EC A-4E Community mod.
|
||||
-- @field #string HORNET F/A-18C Lot 20 Hornet by Eagle Dynamics.
|
||||
-- @field #string F14A F-14A by Heatblur.
|
||||
-- @field #string F14BU F-14BU by Heatblur.
|
||||
-- @field #string F14A_Early F-14A-135-GR-Early by Heatblur.
|
||||
-- @field #string F14B F-14B by Heatblur.
|
||||
-- @field #string F14A_AI F-14A Tomcat (AI).
|
||||
@@ -1298,7 +1297,6 @@ AIRBOSS.AircraftCarrier={
|
||||
F14A="F-14A-135-GR",
|
||||
F14A_Early="F-14A-135-GR-Early",
|
||||
F14B="F-14B",
|
||||
F14BU="F-14BU",
|
||||
F14A_AI="F-14A",
|
||||
FA18C="F/A-18C",
|
||||
T45C="T-45",
|
||||
@@ -5510,7 +5508,7 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
||||
local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
|
||||
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
|
||||
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
||||
local tomcat = self:_IsTomcat( playerData.actype )
|
||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early
|
||||
local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW
|
||||
|
||||
-- Table with AoA values.
|
||||
@@ -5573,18 +5571,6 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
||||
aoa.OnSpeedMin = 9.5
|
||||
aoa.Fast = 8.0
|
||||
aoa.FAST = 7.5
|
||||
else
|
||||
-- Unknown carrier-capable type: _IsCarrierAircraft() is enum-driven, so a type can
|
||||
-- reach here with no AoA branch. Returning an empty table nil-propagates into
|
||||
-- _GetAircraftParameters() and the AoA waveoff check. Fall back to Hornet values.
|
||||
self:E( self.lid .. string.format( "ERROR: No AoA parameters defined for aircraft type %s! Falling back to F/A-18C values.", tostring( playerData.actype ) ) )
|
||||
aoa.SLOW = 9.8
|
||||
aoa.Slow = 9.3
|
||||
aoa.OnSpeedMax = 8.8
|
||||
aoa.OnSpeed = 8.1
|
||||
aoa.OnSpeedMin = 7.4
|
||||
aoa.Fast = 6.9
|
||||
aoa.FAST = 6.3
|
||||
end
|
||||
|
||||
return aoa
|
||||
@@ -5601,7 +5587,7 @@ function AIRBOSS:_AoAUnit2Deg( playerData, aoaunits )
|
||||
local degrees = aoaunits
|
||||
|
||||
-- Check aircraft type of player.
|
||||
if self:_IsTomcat( playerData.actype ) then
|
||||
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early then
|
||||
|
||||
-------------
|
||||
-- F-14A/B --
|
||||
@@ -5644,7 +5630,7 @@ function AIRBOSS:_AoADeg2Units( playerData, degrees )
|
||||
local aoaunits = degrees
|
||||
|
||||
-- Check aircraft type of player.
|
||||
if self:_IsTomcat( playerData.actype ) then
|
||||
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early then
|
||||
|
||||
-------------
|
||||
-- F-14A/B --
|
||||
@@ -5694,7 +5680,7 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
|
||||
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
|
||||
local tomcat = self:_IsTomcat( playerData.actype )
|
||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
||||
local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
|
||||
local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW
|
||||
@@ -6627,7 +6613,9 @@ function AIRBOSS:_RefuelAI( flight )
|
||||
local refuelac=false
|
||||
local actype=flight.group:GetTypeName()
|
||||
if actype==AIRBOSS.AircraftCarrier.AV8B or
|
||||
self:_IsTomcat( actype, true ) or
|
||||
actype==AIRBOSS.AircraftCarrier.F14A or
|
||||
actype==AIRBOSS.AircraftCarrier.F14B or
|
||||
actype==AIRBOSS.AircraftCarrier.F14A_AI or
|
||||
actype==AIRBOSS.AircraftCarrier.HORNET or
|
||||
actype==AIRBOSS.AircraftCarrier.RHINOE or
|
||||
actype==AIRBOSS.AircraftCarrier.RHINOF or
|
||||
@@ -6737,7 +6725,7 @@ function AIRBOSS:_LandAI( flight )
|
||||
Speed = UTILS.KnotsToKmph( 200 )
|
||||
elseif flight.actype == AIRBOSS.AircraftCarrier.E2D or flight.actype == AIRBOSS.AircraftCarrier.C2A then
|
||||
Speed = UTILS.KnotsToKmph( 150 )
|
||||
elseif self:_IsTomcat( flight.actype, true ) then
|
||||
elseif flight.actype == AIRBOSS.AircraftCarrier.F14A_AI or flight.actype == AIRBOSS.AircraftCarrier.F14A or flight.actype == AIRBOSS.AircraftCarrier.F14B then
|
||||
Speed = UTILS.KnotsToKmph( 175 )
|
||||
elseif flight.actype == AIRBOSS.AircraftCarrier.S3B or flight.actype == AIRBOSS.AircraftCarrier.S3BTANKER then
|
||||
Speed = UTILS.KnotsToKmph( 140 )
|
||||
@@ -8212,7 +8200,7 @@ function AIRBOSS:_CheckPlayerStatus()
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
|
||||
local tomcat = self:_IsTomcat( playerData.actype )
|
||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||
|
||||
-- VNAO Edit - Added wrapped up call to LSO grading Hornet
|
||||
if playerData.step==AIRBOSS.PatternStep.WAKE and hornet then-- VNAO Edit - Added
|
||||
@@ -9467,7 +9455,7 @@ function AIRBOSS:_Initial( playerData )
|
||||
|
||||
-- Hook down for students.
|
||||
if playerData.difficulty == AIRBOSS.Difficulty.EASY and playerData.actype ~= AIRBOSS.AircraftCarrier.AV8B then
|
||||
if self:_IsTomcat( playerData.actype ) then
|
||||
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
|
||||
hint = hint .. " - Hook down, SAS on, Wing Sweep 68°!"
|
||||
else
|
||||
hint = hint .. " - Hook down!"
|
||||
@@ -9632,7 +9620,8 @@ function AIRBOSS:_DirtyUp( playerData )
|
||||
|
||||
-- Radio call "Say/Fly needles". Delayed by 10/15 seconds.
|
||||
if playerData.actype == AIRBOSS.AircraftCarrier.HORNET
|
||||
or self:_IsTomcat( playerData.actype )
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.F14A
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER
|
||||
@@ -10410,7 +10399,7 @@ function AIRBOSS:_Groove( playerData )
|
||||
|
||||
-- Wait until player passed the 0.75 NM distance.
|
||||
local _advice = true
|
||||
if (playerData.TIG0 == nil or playerData.TIG0 == 0) and playerData.difficulty ~= AIRBOSS.Difficulty.EASY then -- rho>RXX
|
||||
if playerData.TIG0 == nil and playerData.difficulty ~= AIRBOSS.Difficulty.EASY then -- rho>RXX
|
||||
_advice = false
|
||||
end
|
||||
|
||||
@@ -10826,7 +10815,7 @@ function AIRBOSS:_Trapped( playerData )
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF
|
||||
or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER then
|
||||
dcorr = 100
|
||||
elseif self:_IsTomcat( playerData.actype ) then
|
||||
elseif playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
|
||||
-- TODO: Check Tomcat.
|
||||
dcorr = 100
|
||||
elseif playerData.actype == AIRBOSS.AircraftCarrier.A4EC then
|
||||
@@ -11639,7 +11628,7 @@ function AIRBOSS:_AttitudeMonitor( playerData )
|
||||
|
||||
local unitClient = Unit.getByName(unit:GetName()) -- VNAO Edit - Added
|
||||
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET -- VNAO Edit - Added
|
||||
local tomcat = self:_IsTomcat( playerData.actype ) -- VNAO Edit - Added
|
||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.F14A_Early -- VNAO Edit - Added
|
||||
|
||||
if hornet then -- VNAO Edit - Added
|
||||
local nozzlePosL = 0 -- VNAO Edit - Added
|
||||
@@ -11872,7 +11861,7 @@ function AIRBOSS:_NozzleArgumentLeft( unit ) -- VNAO Edit - Added
|
||||
else -- VNAO Edit - Added
|
||||
nozzlePosL = 0 -- VNAO Edit - Added
|
||||
end -- VNAO Edit - Added
|
||||
elseif self:_IsTomcat( typeName ) then -- VNAO Edit - Added
|
||||
elseif typeName == "F-14A-135-GR" or typeName == "F-14B" or typeName == "F-14A-135-GR-Early" then -- VNAO Edit - Added
|
||||
nozzlePosL = unitClient:getDrawArgumentValue(434) -- VNAO Edit - Added
|
||||
end -- VNAO Edit - Added
|
||||
|
||||
@@ -11897,7 +11886,7 @@ function AIRBOSS:_NozzleArgumentRight( unit ) -- VNAO Edit - Added
|
||||
else -- VNAO Edit - Added
|
||||
nozzlePosR = 0 -- VNAO Edit - Added
|
||||
end -- VNAO Edit - Added
|
||||
elseif self:_IsTomcat( typeName ) then -- VNAO Edit - Added
|
||||
elseif typeName == "F-14A-135-GR" or typeName == "F-14B" or typeName == "F-14A-135-GR-Early" then -- VNAO Edit - Added
|
||||
nozzlePosR = unitClient:getDrawArgumentValue(433) -- VNAO Edit - Added
|
||||
end -- VNAO Edit - Added
|
||||
return nozzlePosR -- VNAO Edit - Added
|
||||
@@ -13160,7 +13149,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep )
|
||||
|
||||
|
||||
local hornet = playerData.actype == AIRBOSS.AircraftCarrier.HORNET-- VNAO Edit - Added
|
||||
local tomcat = self:_IsTomcat( playerData.actype )-- VNAO Edit - Added
|
||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B-- VNAO Edit - Added
|
||||
|
||||
if hornet then-- VNAO Edit - Added
|
||||
if Lnoz > 0.6 and Rnoz > 0.6 then -- VNAO Edit - Added check them both, it's possilbe there could be a single engine landing and one is in idle perhaps?
|
||||
@@ -13676,7 +13665,7 @@ function AIRBOSS:_StepHint( playerData, step )
|
||||
|
||||
-- Late break.
|
||||
if step == AIRBOSS.PatternStep.LATEBREAK then
|
||||
if self:_IsTomcat( playerData.actype ) then
|
||||
if playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
|
||||
hint = hint .. "\nWing Sweep 20°, Gear DOWN < 280 KIAS."
|
||||
end
|
||||
end
|
||||
@@ -13685,7 +13674,7 @@ function AIRBOSS:_StepHint( playerData, step )
|
||||
if step == AIRBOSS.PatternStep.ABEAM then
|
||||
if playerData.actype == AIRBOSS.AircraftCarrier.AV8B then
|
||||
hint = hint .. "\nNozzles 50°-60°. Antiskid OFF. Lights OFF."
|
||||
elseif self:_IsTomcat( playerData.actype ) then
|
||||
elseif playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B then
|
||||
hint = hint .. "\nSlats/Flaps EXTENDED < 225 KIAS. DLC SELECTED. Auto Throttle IF DESIRED."
|
||||
else
|
||||
hint = hint .. "\nDirty up! Gear DOWN, flaps DOWN. Check hook down."
|
||||
@@ -15120,7 +15109,7 @@ function AIRBOSS:_GetACNickname( actype )
|
||||
nickname = "Hawkeye"
|
||||
elseif actype == AIRBOSS.AircraftCarrier.C2A then
|
||||
nickname = "Greyhound"
|
||||
elseif self:_IsTomcat( actype, true ) then
|
||||
elseif actype == AIRBOSS.AircraftCarrier.F14A_AI or actype == AIRBOSS.AircraftCarrier.F14A or actype == AIRBOSS.AircraftCarrier.F14B or actype == AIRBOSS.AircraftCarrier.F14A_Early then
|
||||
nickname = "Tomcat"
|
||||
elseif actype == AIRBOSS.AircraftCarrier.FA18C or actype == AIRBOSS.AircraftCarrier.HORNET then
|
||||
nickname = "Hornet"
|
||||
@@ -15257,29 +15246,6 @@ function AIRBOSS:_GetGoodBadScore( playerData )
|
||||
return lowscore, badscore
|
||||
end
|
||||
|
||||
--- Check whether an aircraft type name is any F-14 Tomcat variant.
|
||||
-- Central predicate so that adding a new Tomcat variant only requires editing
|
||||
-- this function and the AIRBOSS.AircraftCarrier enum.
|
||||
-- @param #AIRBOSS self
|
||||
-- @param #string actype Aircraft type name, e.g. from `unit:GetTypeName()` or `playerData.actype`.
|
||||
-- @param #boolean IncludeAI If true, also match the AI-only F-14A (AIRBOSS.AircraftCarrier.F14A_AI).
|
||||
-- @return #boolean If true, actype is an F-14 variant.
|
||||
function AIRBOSS:_IsTomcat( actype, IncludeAI )
|
||||
|
||||
if actype == AIRBOSS.AircraftCarrier.F14A
|
||||
or actype == AIRBOSS.AircraftCarrier.F14B
|
||||
or actype == AIRBOSS.AircraftCarrier.F14BU
|
||||
or actype == AIRBOSS.AircraftCarrier.F14A_Early then
|
||||
return true
|
||||
end
|
||||
|
||||
if IncludeAI and actype == AIRBOSS.AircraftCarrier.F14A_AI then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Check if aircraft is capable of landing on this aircraft carrier.
|
||||
-- @param #AIRBOSS self
|
||||
-- @param Wrapper.Unit#UNIT unit Aircraft unit. (Will also work with groups as given parameter.)
|
||||
|
||||
@@ -6466,13 +6466,7 @@ function AUFTRAG:GetDCSMissionTask(MissionGroup)
|
||||
-- ESCORT Mission --
|
||||
--------------------
|
||||
|
||||
local FollowGroup=self.engageTarget:GetObject()
|
||||
local DCStask=nil
|
||||
if next(self.engageTargetTypes)==nil then
|
||||
DCStask=FollowGroup:TaskFollow(FollowGroup, self.escortVec3)
|
||||
else
|
||||
DCStask=CONTROLLABLE.TaskEscort(nil, FollowGroup, self.escortVec3, nil, self.engageMaxDistance, self.engageTargetTypes)
|
||||
end
|
||||
local DCStask=CONTROLLABLE.TaskEscort(nil, self.engageTarget:GetObject(), self.escortVec3, nil, self.engageMaxDistance, self.engageTargetTypes)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
|
||||
@@ -183,7 +183,6 @@ do
|
||||
-- my_ctld.placeCratesAhead = false -- place crates straight ahead of the helicopter, in a random way. If true, crates are more neatly sorted.
|
||||
-- my_ctld.nobuildinloadzones = true -- forbid players to build stuff in LOAD zones if set to `true`
|
||||
-- my_ctld.movecratesbeforebuild = true -- crates must be moved once before they can be build. Set to false for direct builds.
|
||||
-- my_ctld.useaircraftheadingforbuilds = false -- Matches the heading of the spawned groups from a crate build to the aircraft heading when starting the build. Default is false for template heading.
|
||||
-- my_ctld.surfacetypes = {land.SurfaceType.LAND,land.SurfaceType.ROAD,land.SurfaceType.RUNWAY,land.SurfaceType.SHALLOW_WATER} -- surfaces for loading back objects.
|
||||
-- my_ctld.nobuildmenu = false -- if set to true effectively enforces to have engineers build/repair stuff for you.
|
||||
-- my_ctld.RadioSound = "beacon.ogg" -- -- this sound will be hearable if you tune in the beacon frequency. Add the sound file to your miz.
|
||||
@@ -2038,7 +2037,7 @@ function CTLD:_C130DcAutoRegisterEntry(SetId, Cargo)
|
||||
|
||||
local pos = Cargo:GetPositionable()
|
||||
local pname = pos and pos.GetName and pos:GetName() or nil
|
||||
local pcoord = pos and pos.GetCoord and pos:GetCoord() or nil
|
||||
local pcoord = pos and pos.GetCoordinate and pos:GetCoordinate() or nil
|
||||
local entryId = string.format("%s#%d", SetId, #setData.entries + 1)
|
||||
local entry = {
|
||||
id = entryId,
|
||||
@@ -2749,12 +2748,14 @@ function CTLD:_EventHandler(EventData)
|
||||
loaded = self.Loaded_Cargo[unitname] -- #CTLD.LoadedCargo
|
||||
loaded.Cratesloaded = loaded.Cratesloaded - 1
|
||||
if loaded.Cratesloaded < 0 then loaded.Cratesloaded = 0 end
|
||||
-- TODO zap cargo from list
|
||||
local Loaded = {}
|
||||
for _,_item in pairs (loaded.Cargo or {}) do
|
||||
self:T(self.lid.."UNLOAD checking: ".._item:GetName())
|
||||
self:T(self.lid.."UNLOAD state: ".. tostring(_item:WasDropped()))
|
||||
local unloadedItem = _item and _item:GetType() == CTLD_CARGO.Enum.GCLOADABLE and event.IniDynamicCargoName and event.IniDynamicCargoName == _item:GetName()
|
||||
if not unloadedItem then
|
||||
if _item and _item:GetType() == CTLD_CARGO.Enum.GCLOADABLE and event.IniDynamicCargoName and event.IniDynamicCargoName ~= _item:GetName() and not _item:WasDropped() then
|
||||
table.insert(Loaded,_item)
|
||||
else
|
||||
table.insert(Loaded,_item)
|
||||
end
|
||||
end
|
||||
@@ -3124,14 +3125,14 @@ end
|
||||
function CTLD:_FindRepairNearby(Group, Unit, Repairtype)
|
||||
self:T(self.lid .. " _FindRepairNearby")
|
||||
--self:T({Group:GetName(),Unit:GetName(),Repairtype})
|
||||
local unitcoord = Unit:GetCoord()
|
||||
local unitcoord = Unit:GetCoordinate()
|
||||
|
||||
-- find nearest group of deployed groups
|
||||
local nearestGroup = nil
|
||||
local nearestGroupIndex = -1
|
||||
local nearestDistance = 10000
|
||||
for k,v in pairs(self.DroppedTroops) do
|
||||
local distance = self:_GetDistance(v:GetCoord(),unitcoord)
|
||||
local distance = self:_GetDistance(v:GetCoordinate(),unitcoord)
|
||||
local unit = v:GetUnit(1) -- Wrapper.Unit#UNIT
|
||||
local desc = unit:GetDesc() or nil
|
||||
if distance < nearestDistance and distance ~= -1 and not desc.attributes.Infantry then
|
||||
@@ -3276,7 +3277,7 @@ end
|
||||
local capabilities = self:_GetUnitCapabilities(Unit)
|
||||
local cantroops = capabilities.troops -- #boolean
|
||||
local trooplimit = capabilities.trooplimit -- #number
|
||||
local unitcoord = unit:GetCoord()
|
||||
local unitcoord = unit:GetCoordinate()
|
||||
|
||||
-- find nearest group of deployed troops
|
||||
local nearestGroup = nil
|
||||
@@ -3287,7 +3288,7 @@ end
|
||||
local distancekeys = {}
|
||||
local extractdistance = self.CrateDistance * self.ExtractFactor
|
||||
for k,v in pairs(self.DroppedTroops) do
|
||||
local distance = self:_GetDistance(v:GetCoord(),unitcoord)
|
||||
local distance = self:_GetDistance(v:GetCoordinate(),unitcoord)
|
||||
local TNow = timer.getTime()
|
||||
local vtime = v.ExtractTime or TNow-310
|
||||
if distance <= extractdistance and distance ~= -1 and (TNow - vtime > 300) then
|
||||
@@ -3375,7 +3376,7 @@ end
|
||||
self:_UpdateUnitCargoMass(Unit)
|
||||
local groupname = nearestGroup:GetName()
|
||||
self:__TroopsExtracted(running,Group, Unit, nearestGroup, groupname)
|
||||
local coord = Unit:GetCoord() or Group:GetCoord() -- Core.Point#COORDINATE
|
||||
local coord = Unit:GetCoordinate() or Group:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local Point
|
||||
if coord then
|
||||
local heading = unit:GetHeading() or 0
|
||||
@@ -3746,16 +3747,16 @@ function CTLD:_C130GetUnits(Group, Unit, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
local coord = Unit:GetCoord() or Group:GetCoord()
|
||||
local coord = Unit:GetCoordinate() or Group:GetCoordinate()
|
||||
local capabilities = self:_GetUnitCapabilities(Unit)
|
||||
local innerDist = (capabilities.length and capabilities.length/2) or 15
|
||||
local maxUnitsNearby = self.maxUnitsNearby or 3
|
||||
local searchRadius = self.UnitDistance or 90
|
||||
local checkZone = ZONE_RADIUS:New("CTLD_C130UnitsZone",coord:GetVec2(),searchRadius,false)
|
||||
local nearGroups = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterZones({checkZone}):FilterOnce()
|
||||
local nearGroups = SET_GROUP:New():FilterCoalitions("blue"):FilterZones({checkZone}):FilterOnce()
|
||||
local nearbyCount = 0
|
||||
for _,gr in pairs(nearGroups.Set) do
|
||||
local gc = gr:GetCoord()
|
||||
local gc = gr:GetCoordinate()
|
||||
if gc then
|
||||
local dist = coord:Get2DDistance(gc)
|
||||
if dist > innerDist then
|
||||
@@ -3805,7 +3806,6 @@ function CTLD:_C130GetUnits(Group, Unit, Name)
|
||||
if canmove then
|
||||
SPAWN:NewWithAlias(_template,alias)
|
||||
:InitRandomizeUnits(true,10,2)
|
||||
:InitCoalition(self.coalition)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits, 70)
|
||||
:InitDelayOff()
|
||||
:OnSpawnGroup(function(grp,TimeStamp)
|
||||
@@ -3819,7 +3819,6 @@ function CTLD:_C130GetUnits(Group, Unit, Name)
|
||||
SPAWN:NewWithAlias(_template,alias)
|
||||
:InitRandomizeUnits(true,10,2)
|
||||
:InitDelayOff()
|
||||
:InitCoalition(self.coalition)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits, 70)
|
||||
:OnSpawnGroup(function(grp,TimeStamp)
|
||||
grp.spawntime = TimeStamp or timer.getTime()
|
||||
@@ -3926,7 +3925,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
|
||||
-- Check cargo location if available
|
||||
local location = Cargo:GetLocation()
|
||||
if location then
|
||||
local unitcoord = Unit:GetCoord() or Group:GetCoord()
|
||||
local unitcoord = Unit:GetCoordinate() or Group:GetCoordinate()
|
||||
if unitcoord then
|
||||
if not location:IsCoordinateInZone(unitcoord) then
|
||||
-- no we're not at the right spot
|
||||
@@ -3973,7 +3972,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
|
||||
end
|
||||
|
||||
-- get position and heading of heli
|
||||
local position = Unit:GetCoord()
|
||||
local position = Unit:GetCoordinate()
|
||||
local heading = Unit:GetHeading() + 1
|
||||
local height = Unit:GetHeight()
|
||||
local droppedcargo = {}
|
||||
@@ -4137,8 +4136,8 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
|
||||
if type(ship) == "string" then
|
||||
self:T("Spawning on ship "..ship)
|
||||
local Ship = UNIT:FindByName(ship)
|
||||
local shipcoord = Ship:GetCoord()
|
||||
local unitcoord = Unit:GetCoord()
|
||||
local shipcoord = Ship:GetCoordinate()
|
||||
local unitcoord = Unit:GetCoordinate()
|
||||
local dist = shipcoord:Get2DDistance(unitcoord)
|
||||
dist = dist - (20 + math.random(1, 10))
|
||||
local halfwidth = (width or 20) / 2
|
||||
@@ -4390,17 +4389,17 @@ end
|
||||
function CTLD:_C130RemoveUnitsNearby(_group,_unit)
|
||||
self:T(self.lid .. " _C130RemoveUnitsNearby")
|
||||
if not _group or not _unit then return self end
|
||||
local location = _group:GetCoord()
|
||||
local location = _group:GetCoordinate()
|
||||
if not location then return self end
|
||||
local capabilities = self:_GetUnitCapabilities(_unit)
|
||||
local innerDist = (capabilities.length and capabilities.length/2) or 15
|
||||
local finddist = self.PackDistance or (self.CrateDistance or 35)
|
||||
local zone = ZONE_RADIUS:New("CTLD_C130RemoveZone",location:GetVec2(),finddist,false)
|
||||
local nearestGroups = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterZones({zone}):FilterOnce()
|
||||
local nearestGroups = SET_GROUP:New():FilterCoalitions("blue"):FilterZones({zone}):FilterOnce()
|
||||
local removedAny = false
|
||||
local removedTable = {}
|
||||
for _, gr in pairs(nearestGroups.Set) do
|
||||
local gc = gr:GetCoord()
|
||||
local gc = gr:GetCoordinate()
|
||||
if gc then
|
||||
local dist = location:Get2DDistance(gc)
|
||||
if dist > innerDist then
|
||||
@@ -4534,7 +4533,7 @@ end
|
||||
function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight, ignoretype, ignoreHercInner)
|
||||
self:T(self.lid .. " _FindCratesNearby")
|
||||
local finddist = _dist
|
||||
local location = _group:GetCoord()
|
||||
local location = _group:GetCoordinate()
|
||||
local existingcrates = self.Spawned_Cargo -- #table
|
||||
-- cycle
|
||||
local index = 0
|
||||
@@ -5160,6 +5159,7 @@ function CTLD:_UnloadTroops(Group, Unit)
|
||||
-- unload troops
|
||||
local name = cargo:GetName() or "none"
|
||||
local temptable = cargo:GetTemplates() or {}
|
||||
local position = Group:GetCoordinate()
|
||||
local zoneradius = self.troopdropzoneradius or 100 -- drop zone radius
|
||||
local factor = 1
|
||||
if IsHerc then
|
||||
@@ -5196,7 +5196,6 @@ function CTLD:_UnloadTroops(Group, Unit)
|
||||
local Positions = self:_GetUnitPositions(randomcoord,rad,heading,_template)
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||
:InitDelayOff()
|
||||
:InitCoalition(self.coalition)
|
||||
:InitSetUnitAbsolutePositions(Positions)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
@@ -5507,8 +5506,8 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop,NotifyGroup)
|
||||
local required = Crate:GetCratesNeeded()
|
||||
local template = Crate:GetTemplates()
|
||||
local ctype = Crate:GetType()
|
||||
local ccoord = Crate:GetPositionable():GetCoord() -- Core.Point#COORDINATE
|
||||
local distToUnit=Unit and ccoord:Get2DDistance(Unit:GetCoord())or 0
|
||||
local ccoord = Crate:GetPositionable():GetCoordinate() -- Core.Point#COORDINATE
|
||||
local distToUnit=Unit and ccoord:Get2DDistance(Unit:GetCoordinate())or 0
|
||||
local isHercDrop=Crate:WasDropped(true)
|
||||
if not isHercDrop and distToUnit>baseDist then
|
||||
elseif self:IsC130J(Unit) and distToUnit<15 then
|
||||
@@ -5527,7 +5526,6 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop,NotifyGroup)
|
||||
object.Found = 1
|
||||
object.Template = template
|
||||
object.CanBuild = false
|
||||
object.Heading = Unit:GetHeading()
|
||||
object.Type = ctype -- #CTLD_CARGO.Enum
|
||||
object.Coord = ccoord:GetVec2()
|
||||
buildables[name] = object
|
||||
@@ -5613,7 +5611,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop,NotifyGroup)
|
||||
local sep = self.buildPairSeparation or 25
|
||||
local hdg = (Unit:GetHeading()+180)%360
|
||||
local lat = (hdg+90)%360
|
||||
local base = Unit:GetCoord():Translate(20,hdg)
|
||||
local base = Unit:GetCoordinate():Translate(20,hdg)
|
||||
|
||||
if full == 1 then
|
||||
local cratesNow, numberNow = self:_FindCratesNearby(Group,Unit, finddist,true,true, not Engineering)
|
||||
@@ -5647,7 +5645,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop,NotifyGroup)
|
||||
self:_RefreshPackMenus(Group,Unit)
|
||||
local off = start + (n-1)*sep
|
||||
local coord = base:Translate(off,lat):GetVec2()
|
||||
local b = { Name=build.Name, Required=build.Required, Template=build.Template, CanBuild=true, Type=build.Type, Coord=coord, Heading=build.Heading }
|
||||
local b = { Name=build.Name, Required=build.Required, Template=build.Template, CanBuild=true, Type=build.Type, Coord=coord }
|
||||
if self.buildtime and self.buildtime > 0 then
|
||||
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,b,false,Group:GetCoordinate(),MultiDrop)
|
||||
buildtimer:Start(self.buildtime)
|
||||
@@ -5685,18 +5683,18 @@ end
|
||||
-- @return #number Number
|
||||
function CTLD:_FindPackableGroupsNearby(Group, Unit)
|
||||
self:T(self.lid .. " _FindPackableGroupsNearby")
|
||||
local location = Group:GetCoord()
|
||||
local location = Group:GetCoordinate()
|
||||
if not location then return {}, 0 end
|
||||
local capabilities = self:_GetUnitCapabilities(Unit)
|
||||
local innerDist = (capabilities.length and capabilities.length/2) or 15
|
||||
local finddist = self.PackDistance or (self.CrateDistance or 35)
|
||||
local zone = ZONE_RADIUS:New("CTLD_PackableZone", location:GetVec2(), finddist, false)
|
||||
local nearestGroups = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterZones({zone}):FilterOnce()
|
||||
local nearestGroups = SET_GROUP:New():FilterCoalitions("blue"):FilterZones({zone}):FilterOnce()
|
||||
local packable = {}
|
||||
|
||||
for _, gr in pairs(nearestGroups.Set) do
|
||||
if gr and gr:GetName() ~= Group:GetName() then
|
||||
local gc = gr:GetCoord()
|
||||
local gc = gr:GetCoordinate()
|
||||
if gc then
|
||||
local dist = location:Get2DDistance(gc)
|
||||
if dist > innerDist and dist <= finddist then
|
||||
@@ -5829,12 +5827,12 @@ function CTLD:_LoadPackedCratesByIds(Group, Unit, crateIds, cargoName)
|
||||
|
||||
local matchingCrates = {}
|
||||
local finddist = self.CrateDistance or 35
|
||||
local location = Group:GetCoord()
|
||||
local location = Group:GetCoordinate()
|
||||
for _, crateObj in pairs(self.Spawned_Cargo or {}) do
|
||||
if crateObj and idLookup[crateObj:GetID()] then
|
||||
local pos = crateObj:GetPositionable()
|
||||
if pos and pos:IsAlive() then
|
||||
local dist = location:Get2DDistance(pos:GetCoord())
|
||||
local dist = location:Get2DDistance(pos:GetCoordinate())
|
||||
if dist <= finddist then
|
||||
matchingCrates[#matchingCrates + 1] = crateObj
|
||||
end
|
||||
@@ -5944,12 +5942,12 @@ function CTLD:_RemovePackedCratesByIds(Group, Unit, crateIds)
|
||||
|
||||
local crates = {}
|
||||
local finddist = self.CrateDistance or 35
|
||||
local location = Group:GetCoord()
|
||||
local location = Group:GetCoordinate()
|
||||
for _, entry in pairs(self.Spawned_Cargo or {}) do
|
||||
if entry and idLookup[entry:GetID()] then
|
||||
local pos = entry:GetPositionable()
|
||||
if pos and pos:IsAlive() then
|
||||
local dist = location:Get2DDistance(pos:GetCoord())
|
||||
local dist = location:Get2DDistance(pos:GetCoordinate())
|
||||
if dist <= finddist then
|
||||
crates[#crates + 1] = entry
|
||||
end
|
||||
@@ -6199,31 +6197,28 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,Mult
|
||||
for _,_template in pairs(temptable) do
|
||||
self.TroopCounter = self.TroopCounter + 1
|
||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||
local spawn = SPAWN:NewWithAlias(_template,alias)
|
||||
if canmove then
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||
--:InitRandomizeUnits(true,20,2)
|
||||
:InitDelayOff()
|
||||
:InitCoalition(self.coalition)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
if canmove then
|
||||
--spawn:InitRandomizeUnits(true,20,2)
|
||||
:SpawnFromVec2(randomcoord)
|
||||
else -- don't random position of e.g. SAM units build as FOB
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||
:InitDelayOff()
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
:SpawnFromVec2(randomcoord)
|
||||
end
|
||||
if Build.Heading and self.useaircraftheadingforbuilds then
|
||||
spawn:InitGroupHeading(Build.Heading)
|
||||
end
|
||||
local spawnedGroup = spawn:SpawnFromVec2(randomcoord)
|
||||
self.DroppedTroops[self.TroopCounter] = spawnedGroup
|
||||
|
||||
if Repair then
|
||||
self:__CratesRepaired(1,Group,Unit,spawnedGroup)
|
||||
self:__CratesRepaired(1,Group,Unit,self.DroppedTroops[self.TroopCounter])
|
||||
else
|
||||
self:__CratesBuild(1,Group,Unit,spawnedGroup)
|
||||
self:__CratesBuild(1,Group,Unit,self.DroppedTroops[self.TroopCounter])
|
||||
end
|
||||
end -- template loop
|
||||
|
||||
if Group and Group:IsAlive() and Group:GetID() then
|
||||
self:_RefreshLoadCratesMenu(Group, Unit)
|
||||
self:_RefreshPackMenus(Group, Unit)
|
||||
end
|
||||
else
|
||||
self:T(self.lid.."Group KIA while building!")
|
||||
end
|
||||
@@ -6246,11 +6241,14 @@ end
|
||||
-- @param Wrapper.Group#GROUP Group The Group to move.
|
||||
function CTLD:_MoveGroupToZone(Group)
|
||||
self:T(self.lid .. " _MoveGroupToZone")
|
||||
local groupname = Group:GetName() or "none"
|
||||
local groupcoord = Group:GetCoordinate()
|
||||
-- Get closest zone of type
|
||||
local outcome, name, zone, distance = self:IsUnitInZone(Group,CTLD.CargoZoneType.MOVE)
|
||||
self:T({canmove=outcome, name=name, zone=zone, dist=distance,max=self.movetroopsdistance})
|
||||
if (distance <= self.movetroopsdistance) and outcome == true and zone~= nil then
|
||||
-- yes, we can ;)
|
||||
local groupname = Group:GetName()
|
||||
local zonecoord = zone:GetRandomCoordinate(20,125) -- Core.Point#COORDINATE
|
||||
local formation = self:_GetVehicleFormation()
|
||||
--local coordinate = zonecoord:GetVec2()
|
||||
@@ -7933,7 +7931,6 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID, qty)
|
||||
local Positions = self:_GetUnitPositions(randomcoord, rad, heading, _template)
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
|
||||
:InitDelayOff()
|
||||
:InitCoalition(self.coalition)
|
||||
:InitSetUnitAbsolutePositions(Positions)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
@@ -9011,7 +9008,7 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
|
||||
local zoneret = nil
|
||||
local zonewret = nil
|
||||
local zonenameret = nil
|
||||
local unitcoord = Unit:GetCoord()
|
||||
local unitcoord = Unit:GetCoordinate()
|
||||
if not unitcoord then
|
||||
if Zonetype == CTLD.CargoZoneType.SHIP then
|
||||
return false, nil, nil, 1000000, nil
|
||||
@@ -9032,7 +9029,7 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
|
||||
self:T("Checking Type Ship: "..zonename)
|
||||
local ZoneUNIT = UNIT:FindByName(zonename)
|
||||
if not ZoneUNIT then return false end
|
||||
zonecoord = ZoneUNIT:GetCoord()
|
||||
zonecoord = ZoneUNIT:GetCoordinate()
|
||||
zoneradius = czone.shiplength
|
||||
zonewidth = czone.shipwidth
|
||||
zone = ZONE_UNIT:New( ZoneUNIT:GetName(), ZoneUNIT, zoneradius/2)
|
||||
@@ -9081,7 +9078,7 @@ function CTLD:SmokePositionNow(Unit, Flare, SmokeColor)
|
||||
end
|
||||
local FlareColor = self.FlareColor or FLARECOLOR.Red
|
||||
-- table of #CTLD.CargoZone table
|
||||
local unitcoord = Unit:GetCoord() -- Core.Point#COORDINATE
|
||||
local unitcoord = Unit:GetCoordinate() -- Core.Point#COORDINATE
|
||||
local Group = Unit:GetGroup()
|
||||
if Flare then
|
||||
unitcoord:Flare(FlareColor, 90)
|
||||
@@ -9100,7 +9097,7 @@ end
|
||||
function CTLD:SmokeZoneNearBy(Unit, Flare)
|
||||
self:T(self.lid .. " SmokeZoneNearBy")
|
||||
-- table of #CTLD.CargoZone table
|
||||
local unitcoord = Unit:GetCoord()
|
||||
local unitcoord = Unit:GetCoordinate()
|
||||
local Group = Unit:GetGroup()
|
||||
local smokedistance = self.smokedistance
|
||||
local smoked = false
|
||||
@@ -9237,7 +9234,7 @@ end
|
||||
-- get speed and height
|
||||
local uspeed = Unit:GetVelocityMPS()
|
||||
local uheight = Unit:GetHeight()
|
||||
local ucoord = Unit:GetCoord()
|
||||
local ucoord = Unit:GetCoordinate()
|
||||
if not ucoord then
|
||||
return false
|
||||
end
|
||||
@@ -9266,7 +9263,7 @@ end
|
||||
-- get speed and height
|
||||
local uspeed = Unit:GetVelocityMPS()
|
||||
local uheight = Unit:GetHeight()
|
||||
local ucoord = Unit:GetCoord()
|
||||
local ucoord = Unit:GetCoordinate()
|
||||
if not ucoord then
|
||||
return false
|
||||
end
|
||||
@@ -9358,7 +9355,7 @@ end
|
||||
minheight = 5.1 -- herc is 5m AGL on the ground
|
||||
end
|
||||
local uheight = Unit:GetHeight()
|
||||
local ucoord = Unit:GetCoord()
|
||||
local ucoord = Unit:GetCoordinate()
|
||||
if not ucoord then
|
||||
return false
|
||||
end
|
||||
@@ -10144,7 +10141,6 @@ end
|
||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||
:InitRandomizeUnits(randompositions,20,2)
|
||||
:InitCoalition(self.coalition)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:InitDelayOff()
|
||||
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
||||
@@ -10299,7 +10295,6 @@ end
|
||||
if canmove then
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||
:InitRandomizeUnits(true,20,2)
|
||||
:InitCoalition(self.coalition)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:InitDelayOff()
|
||||
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
||||
@@ -10307,7 +10302,6 @@ end
|
||||
else -- don't random position of e.g. SAM units build as FOB
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||
:InitDelayOff()
|
||||
:InitCoalition(self.coalition)
|
||||
:InitValidateAndRepositionGroundUnits(self.validateAndRepositionUnits)
|
||||
:OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp)
|
||||
:SpawnFromVec2(randomcoord)
|
||||
@@ -10589,7 +10583,7 @@ end
|
||||
self:T({From, Event, To})
|
||||
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
|
||||
local playername = Unit:GetPlayerName()
|
||||
local dropcoord = Troops:GetCoord() or COORDINATE:New(0,0,0)
|
||||
local dropcoord = Troops:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||
local dropvec2 = dropcoord:GetVec2()
|
||||
self.PlayerTaskQueue:ForEach(
|
||||
function (Task)
|
||||
@@ -10646,7 +10640,7 @@ end
|
||||
for _,_cargo in pairs(Cargotable) do
|
||||
local Vehicle = _cargo.Positionable
|
||||
if Vehicle then
|
||||
local dropcoord = Vehicle:GetCoord() or COORDINATE:New(0,0,0)
|
||||
local dropcoord = Vehicle:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||
local dropvec2 = dropcoord:GetVec2()
|
||||
self.PlayerTaskQueue:ForEach(
|
||||
function (Task)
|
||||
@@ -10711,7 +10705,7 @@ end
|
||||
self:T({From, Event, To})
|
||||
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
|
||||
local playername = Unit:GetPlayerName()
|
||||
local dropcoord = Vehicle:GetCoord() or COORDINATE:New(0,0,0)
|
||||
local dropcoord = Vehicle:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||
local dropvec2 = dropcoord:GetVec2()
|
||||
self.PlayerTaskQueue:ForEach(
|
||||
function (Task)
|
||||
|
||||
@@ -288,7 +288,7 @@ EASYGCICAP = {
|
||||
|
||||
--- EASYGCICAP class version.
|
||||
-- @field #string version
|
||||
EASYGCICAP.version="0.1.39"
|
||||
EASYGCICAP.version="0.1.38"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--
|
||||
@@ -796,9 +796,8 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
||||
CAP_Wing:SetRespawnAfterDestroyed()
|
||||
|
||||
--- #DONE avoid wings with no CAP points starting CAP anyhow; AirWing uses this to start CAP and creates points when there are none.
|
||||
local nCapPoints = counttable(self.ManagedCP)
|
||||
if nCapPoints >0 then
|
||||
CAP_Wing:SetNumberCAP(nCapPoints,self.capgrouping)
|
||||
if counttable(self.ManagedCP) >0 then
|
||||
CAP_Wing:SetNumberCAP(self.capgrouping)
|
||||
end
|
||||
CAP_Wing:SetCapCloseRaceTrack(true)
|
||||
|
||||
|
||||
@@ -2661,7 +2661,7 @@ function LEGION._CohortCan(Cohort, MissionType, Categories, Attributes, Properti
|
||||
local RangeMax = RangeMax or 0
|
||||
local InRange=(RangeMax and math.max(RangeMax, Rmax) or Rmax) >= TargetDistance and TargetDistance > RangeMin
|
||||
|
||||
--env.info(string.format("Range TargetDist=%.1f Rmax=%.1f RangeMax=%.1f InRange=%s", TargetDistance, Rmax, RangeMax, tostring(InRange)))
|
||||
--env.info(string.format("Range TargetDist=%.1f Rmax=%.1f RangeMax=%.1f InRange=%s RangeMin=%s", TargetDistance, Rmax, RangeMax, tostring(InRange),tostring(RangeMin)))
|
||||
|
||||
return InRange
|
||||
end
|
||||
|
||||
@@ -131,24 +131,14 @@ ENUMS.WeaponFlag={
|
||||
Cannons = 805306368, -- GUN_POD + BuiltInCannon
|
||||
--- Torpedo
|
||||
Torpedo = 4294967296,
|
||||
--- Decoy
|
||||
Decoys = 8589934592,
|
||||
--- Shell
|
||||
SmokeShell = 17179869184,
|
||||
IlluminationShell = 34359738368,
|
||||
MarkerShell = 51539607552,
|
||||
MarkerWeapon = 51539620864,
|
||||
SubmunitionDispenserShell = 68719476736,
|
||||
ConventionalShell = 206963736576,
|
||||
---
|
||||
-- Even More Genral
|
||||
Auto = 265214230526, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons + Torpedos)
|
||||
Auto = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons)
|
||||
AutoDCS = 1073741822, -- Something if often see
|
||||
AnyAG = 2956984318, -- Any Air-To-Ground Weapon
|
||||
AnyAA = 264241152, -- Any Air-To-Air Weapon
|
||||
AnyUnguided = 2952822768, -- Any Unguided Weapon
|
||||
AnyGuided = 268402702, -- Any Guided Weapon
|
||||
AnyShell = 258503344128, -- Any Shell
|
||||
}
|
||||
|
||||
--- Weapon types by category. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on hoggit wiki.
|
||||
@@ -230,7 +220,7 @@ ENUMS.WeaponType.Torpedo={
|
||||
}
|
||||
ENUMS.WeaponType.Any={
|
||||
-- General combinations
|
||||
Weapon = 265214230526, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons + Torpedos)
|
||||
Weapon = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons)
|
||||
AG = 2956984318, -- Any Air-To-Ground Weapon
|
||||
AA = 264241152, -- Any Air-To-Air Weapon
|
||||
Unguided = 2952822768, -- Any Unguided Weapon
|
||||
@@ -523,7 +513,7 @@ ENUMS.ReportingName =
|
||||
Tornado = "Tornado",
|
||||
-- Transport / Bomber / Others
|
||||
Atlas = "A400",
|
||||
Lancer = "B-1B",
|
||||
Lancer = "B1-B",
|
||||
Stratofortress = "B-52H",
|
||||
Herc = "C-130",
|
||||
Hercules = "C-130J-30",
|
||||
@@ -568,7 +558,7 @@ ENUMS.ReportingName =
|
||||
Apache = "AH-64",
|
||||
Chinook = "CH-47",
|
||||
Sea_Stallion = "CH-53",
|
||||
Kiowa = "OH58D",
|
||||
Kiowa = "OH-58",
|
||||
Seahawk = "SH-60",
|
||||
Blackhawk = "UH-60",
|
||||
Sea_King = "S-61",
|
||||
@@ -1808,21 +1798,13 @@ ENUMS.Storage.weapons.missiles.Igla_S = 'weapons.missiles.Igla_S'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.{AKAN_NO_TRC}'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.{AKAN}'
|
||||
ENUMS.Storage.weapons.shells.M882_9x19 = 'weapons.shells.9x19_m882'
|
||||
ENUMS.Storage.weapons.droptanks.fuel_tank_370gal = "weapons.droptanks.fuel_tank_370gal"
|
||||
ENUMS.Storage.weapons.droptanks.fuel_tank_300gal = "weapons.droptanks.fuel_tank_300gal"
|
||||
|
||||
-- NEW
|
||||
ENUMS.Storage.weapons.adapters.HB_F_4E_ORD_LAU_77 = 'weapons.adapters.HB_F-4E_ORD_LAU_77'
|
||||
ENUMS.Storage.weapons.adapters.hb_a_6e_lau7_adu299 = 'weapons.adapters.hb_a-6e_lau7_adu299'
|
||||
ENUMS.Storage.weapons.adapters.CHAP_AIM92LN = 'weapons.adapters.CHAP_AIM92LN'
|
||||
ENUMS.Storage.weapons.adapters.CHAP_HOT3LN = 'weapons.adapters.CHAP_HOT3LN'
|
||||
ENUMS.Storage.weapons.adapters.CHAP_FZ225 = 'weapons.adapters.CHAP_FZ225'
|
||||
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_BLUE = 'weapons.bombs.AH6_SMOKE_BLUE'
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_GREEN = 'weapons.bombs.AH6_SMOKE_GREEN'
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_RED = 'weapons.bombs.AH6_SMOKE_RED'
|
||||
ENUMS.Storage.weapons.bombs.AH6_SMOKE_YELLOW = 'weapons.bombs.AH6_SMOKE_YELLOW'
|
||||
ENUMS.Storage.weapons.bombs.AO_25SL = 'weapons.bombs.AO_25SL'
|
||||
|
||||
ENUMS.Storage.weapons.missiles.HB_AGM_78 = 'weapons.missiles.HB_AGM_78'
|
||||
ENUMS.Storage.weapons.missiles.V_1 = 'weapons.missiles.V-1'
|
||||
@@ -1869,10 +1851,6 @@ ENUMS.Storage.weapons.shells.M42A1_HE = 'weapons.shells.M42A1_HE'
|
||||
ENUMS.Storage.weapons.shells.HE_20x138B = 'weapons.shells.20x138B_HE'
|
||||
ENUMS.Storage.weapons.shells.HE_37x263 = 'weapons.shells.37x263_HE'
|
||||
ENUMS.Storage.weapons.shells.HE_2A20_115mm = 'weapons.shells.2A20_115mm_HE'
|
||||
ENUMS.Storage.weapons.shells.AP_20x99R = 'weapons.shells.20x99R_AP'
|
||||
ENUMS.Storage.weapons.shells.IranFAC_DShK_API_T = 'weapons.shells.IranFAC_DShK_API_T'
|
||||
ENUMS.Storage.weapons.shells.IranFAC_DShK_API = 'weapons.shells.IranFAC_DShK_API'
|
||||
ENUMS.Storage.weapons.shells.HE_T_20x99R = 'weapons.shells.20x99R_HE_T'
|
||||
|
||||
ENUMS.Storage.weapons.gunmounts.B17_TailTurret_M2_L = 'weapons.gunmounts.B17_TailTurret_M2_L'
|
||||
ENUMS.Storage.weapons.gunmounts.AH6_M134L = 'weapons.gunmounts.{AH6_M134L}'
|
||||
@@ -1903,11 +1881,6 @@ ENUMS.Storage.weapons.gunmounts.AH_6_FN_HMP400 = 'weapons.gunmounts.{AH-6_FN_HMP
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_M134L = 'weapons.gunmounts.AH-6_M134L'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_M134R = 'weapons.gunmounts.AH-6_M134R'
|
||||
ENUMS.Storage.weapons.gunmounts.AH_6_HMP400 = 'weapons.gunmounts.AH-6_HMP400'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.{AKAN_NO_TRC}'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.{AKAN}'
|
||||
ENUMS.Storage.weapons.gunmounts.CHAP_HMP400LC = 'weapons.gunmounts.{CHAP_HMP400LC}'
|
||||
ENUMS.Storage.weapons.gunmounts.HMP400LC = 'weapons.gunmounts.HMP400LC'
|
||||
ENUMS.Storage.weapons.gunmounts.SHVAK_GUN = 'weapons.gunmounts.SHVAK_GUN'
|
||||
|
||||
ENUMS.Storage.weapons.droptanks.PTB_800 = 'weapons.droptanks.PTB-800'
|
||||
ENUMS.Storage.weapons.droptanks.PTB_275 = 'weapons.droptanks.PTB-275'
|
||||
@@ -1958,7 +1931,6 @@ ENUMS.Storage.weapons.droptanks.S_3_PTB = 'weapons.droptanks.S-3-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.fuel_tank_370gal = 'weapons.droptanks.fuel_tank_370gal'
|
||||
ENUMS.Storage.weapons.droptanks.MIG_23_PTB = 'weapons.droptanks.MIG-23-PTB'
|
||||
ENUMS.Storage.weapons.droptanks.f_18c_ptb = 'weapons.droptanks.f-18c-ptb'
|
||||
ENUMS.Storage.weapons.droptanks.CHAP_TigerUHT_fueltank = 'weapons.droptanks.CHAP_TigerUHT_fueltank'
|
||||
|
||||
ENUMS.Storage.weapons.containers.FN_HMP400_100 = 'weapons.containers.{FN_HMP400_100}'
|
||||
ENUMS.Storage.weapons.containers.AN_M3 = 'weapons.containers.{AN-M3}'
|
||||
@@ -2090,13 +2062,6 @@ ENUMS.Storage.weapons.containers.GIAT_M621_AP = 'weapons.containers.{GIAT_M621_A
|
||||
ENUMS.Storage.weapons.containers.M134_R = 'weapons.containers.M134_R'
|
||||
ENUMS.Storage.weapons.containers.OH58D_M3P_L300 = 'weapons.containers.OH58D_M3P_L300'
|
||||
ENUMS.Storage.weapons.containers.AH6_M134R = 'weapons.containers.{AH6_M134R}'
|
||||
ENUMS.Storage.weapons.containers.CHAP_HMP400LC = 'weapons.containers.{CHAP_HMP400LC}'
|
||||
|
||||
ENUMS.Storage.weapons.missiles.C701_AShM = 'weapons.missiles.C701 AShM'
|
||||
ENUMS.Storage.weapons.missiles.IGLA_9M39 = 'weapons.missiles.9M39_IGLA'
|
||||
ENUMS.Storage.weapons.missiles.CHAP_AIM92 = 'weapons.missiles.CHAP_AIM92'
|
||||
ENUMS.Storage.weapons.missiles.AM39 = 'weapons.missiles.AM39'
|
||||
ENUMS.Storage.weapons.missiles.Shahed136_LM = 'weapons.missiles.Shahed136_LM'
|
||||
|
||||
ENUMS.Storage.weapons.torpedoes.G7A_T1 = 'weapons.torpedoes.G7A_T1'
|
||||
|
||||
@@ -2126,56 +2091,6 @@ ENUMS.Storage.weapons.containers.UH60_GAU19_RIGHT = 'weapons.containers.{UH60_GA
|
||||
ENUMS.Storage.weapons.containers.UH60_M230_RIGHT = 'weapons.containers.{UH60_M230_RIGHT}'
|
||||
ENUMS.Storage.weapons.containers.UH60L_M2_GUNNER = 'weapons.containers.{UH60L_M2_GUNNER}'
|
||||
|
||||
|
||||
ENUMS.Storage.weapons.adapters.GD_F100_SUU_13 = 'weapons.adapters.GD_F100_SUU-13'
|
||||
ENUMS.Storage.weapons.containers.GPU_5_POD = 'weapons.containers.{GPU_5_POD}'
|
||||
ENUMS.Storage.weapons.bombs.BOLT_117 = 'weapons.bombs.BOLT-117'
|
||||
ENUMS.Storage.weapons.shells.F100_M39_20_TP_T = 'weapons.shells.F100_M39_20_TP_T'
|
||||
ENUMS.Storage.weapons.gunmounts.M_39_F_100 = 'weapons.gunmounts.M-39 F-100'
|
||||
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_275_L = 'weapons.droptanks.GD_F100_TANK_275_L'
|
||||
ENUMS.Storage.weapons.bombs.BLU_4B_R_GROUP_R = 'weapons.bombs.BLU-4B_R_GROUP_R'
|
||||
ENUMS.Storage.weapons.containers.F100_CAMERA_P2 = 'weapons.containers.F100_CAMERA_P2'
|
||||
ENUMS.Storage.weapons.containers.HB_ORD_SUU_7 = 'weapons.containers.HB_ORD_SUU_7'
|
||||
ENUMS.Storage.weapons.adapters.SidewinderPylon = 'weapons.adapters.SidewinderPylon'
|
||||
ENUMS.Storage.weapons.adapters.apu_470 = 'weapons.adapters.apu_470'
|
||||
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_335_R = 'weapons.droptanks.GD_F100_TANK_335_R'
|
||||
ENUMS.Storage.weapons.bombs.BLU_3B_R_GROUP_R = 'weapons.bombs.BLU-3B_R_GROUP_R'
|
||||
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_335_L = 'weapons.droptanks.GD_F100_TANK_335_L'
|
||||
ENUMS.Storage.weapons.adapters.mbdz_u2t = 'weapons.adapters.mbdz_u2t'
|
||||
ENUMS.Storage.weapons.containers.ZellRocket = 'weapons.containers.ZellRocket'
|
||||
ENUMS.Storage.weapons.containers.apu_73 = 'weapons.containers.apu-73'
|
||||
ENUMS.Storage.weapons.gunmounts.GAU_13 = 'weapons.gunmounts.GAU-13'
|
||||
ENUMS.Storage.weapons.shells.F100_M39_20_TP = 'weapons.shells.F100_M39_20_TP'
|
||||
ENUMS.Storage.weapons.shells.F100_M39_20_API = 'weapons.shells.F100_M39_20_API'
|
||||
ENUMS.Storage.weapons.adapters.bdz_umk2b = 'weapons.adapters.bdz_umk2b'
|
||||
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_450 = 'weapons.droptanks.GD_F100_TANK_450'
|
||||
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_275_R = 'weapons.droptanks.GD_F100_TANK_275_R'
|
||||
ENUMS.Storage.weapons.bombs.BLU_18_B_GROUP = 'weapons.bombs.BLU-18/B_GROUP'
|
||||
ENUMS.Storage.weapons.containers.ZELL_Booster = 'weapons.containers.ZELL Booster'
|
||||
ENUMS.Storage.weapons.adapters.apu_60 = 'weapons.adapters.apu_60'
|
||||
ENUMS.Storage.weapons.gunmounts.GPU_5_POD = 'weapons.gunmounts.{GPU_5_POD}'
|
||||
ENUMS.Storage.weapons.containers.F100_CAMERA_KA71A = 'weapons.containers.F100_CAMERA_KA71A'
|
||||
ENUMS.Storage.weapons.bombs.BLU_3_R_GROUP_R = 'weapons.bombs.BLU-3_R_GROUP_R'
|
||||
ENUMS.Storage.weapons.shells.F100_M39_20_HEI = 'weapons.shells.F100_M39_20_HEI'
|
||||
ENUMS.Storage.weapons.droptanks.GD_F100_TANK_200 = 'weapons.droptanks.GD_F100_TANK_200'
|
||||
ENUMS.Storage.weapons.adapters.apu_73 = 'weapons.adapters.apu-73'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.AKAN_NO_TRC'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.AKAN'
|
||||
ENUMS.Storage.weapons.shells.F100_M39_20_HEI_T = 'weapons.shells.F100_M39_20_HEI_T'
|
||||
ENUMS.Storage.weapons.shells.F100_M39_20_API_T = 'weapons.shells.F100_M39_20_API_T'
|
||||
ENUMS.Storage.weapons.containers.GD_F100_STRIKE_CAMERA = 'weapons.containers.GD_F100_STRIKE_CAMERA'
|
||||
ENUMS.Storage.weapons.bombs.BLU_49_B = 'weapons.bombs.BLU-49/B'
|
||||
|
||||
ENUMS.Storage.weapons.bombs.GBU_24E = 'weapons.bombs.GBU_24E'
|
||||
ENUMS.Storage.weapons.containers.GD_F100_SUU_13 = 'weapons.containers.GD_F100_SUU-13'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN = 'weapons.gunmounts.{AKAN}'
|
||||
ENUMS.Storage.weapons.gunmounts.AKAN_NO_TRC = 'weapons.gunmounts.{AKAN_NO_TRC}'
|
||||
ENUMS.Storage.weapons.gunmounts.SUU_23_POD_Wing = 'weapons.gunmounts.{SUU_23_POD_Wing}'
|
||||
ENUMS.Storage.weapons.containers.SUU_23_POD_Wing = 'weapons.containers.{SUU_23_POD_Wing}'
|
||||
ENUMS.Storage.weapons.containers.SUU_23_POD_Centerline = 'weapons.containers.{SUU_23_POD_Centerline}'
|
||||
ENUMS.Storage.weapons.gunmounts.SUU_23_POD_Centerline = 'weapons.gunmounts.{SUU_23_POD_Centerline}'
|
||||
ENUMS.Storage.weapons.containers.HB_F_4E_BRU_42 = 'weapons.containers.HB_F-4E_BRU-42'
|
||||
|
||||
---
|
||||
-- @type ENUMS.FARPType
|
||||
-- @field #string FARP
|
||||
|
||||
@@ -753,8 +753,8 @@ UTILS.KnotsToKmph = function(knots)
|
||||
return knots * 1.852
|
||||
end
|
||||
|
||||
UTILS.KmphToKnots = function(knots)
|
||||
return knots / 1.852
|
||||
UTILS.KmphToKnots = function(kmph)
|
||||
return kmph / 1.852
|
||||
end
|
||||
|
||||
UTILS.KmphToMps = function( kmph )
|
||||
|
||||
@@ -287,7 +287,7 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role, Zone)
|
||||
--BASE:I("Coordinate x = "..Coordinate.x .. " y = "..Coordinate.y.." z = "..Coordinate.z)
|
||||
|
||||
local findme = self:_FindByName(Name)
|
||||
if findme and findme:GetDCSObject() then return findme end
|
||||
if findme then return findme end
|
||||
|
||||
local radius = Radius or 100
|
||||
local name = Name or "unknown"
|
||||
@@ -322,6 +322,8 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role, Zone)
|
||||
scenery = SceneryScan(Coordinate, radius, name)
|
||||
end
|
||||
|
||||
if not scenery then scenery = SCENERY:Register(Name,nil,Zone) end
|
||||
|
||||
return scenery
|
||||
end
|
||||
|
||||
|
||||
@@ -76,6 +76,10 @@ Functional/Tiresias.lua
|
||||
Functional/Stratego.lua
|
||||
Functional/ClientWatch.lua
|
||||
Functional/Formation.lua
|
||||
Functional/RedGCIKernel.lua
|
||||
Functional/RedGCI.lua
|
||||
Functional/RedGCI2v2.lua
|
||||
Functional/RedGCIDispatcher.lua
|
||||
|
||||
Ops/Airboss.lua
|
||||
Ops/RecoveryTanker.lua
|
||||
|
||||
Reference in New Issue
Block a user