Compare commits

..

12 Commits

Author SHA1 Message Date
Applevangelist 23112c9954 Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-14 13:45:08 +02:00
Applevangelist 23c59d906f Merge remote-tracking branch 'origin/develop' into develop 2026-06-14 12:07:31 +02:00
Applevangelist cc62655ffe Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-14 12:07:25 +02:00
Thomas 401e9d9e8e Merge pull request #2597 from FlightControl-Master/master-ng
Merge from master
2026-06-14 09:57:46 +02:00
Applevangelist 9b1a3e4894 Merge remote-tracking branch 'origin/master-ng' into develop
# Conflicts:
#	Moose Development/Moose/Core/Spawn.lua
2026-06-11 17:34:53 +02:00
Thomas 6c32aa6044 Merge pull request #2595 from geofffranks/fix/spawn-air-takeoff-event-args
fix(Spawn): air-spawn takeoff event never fired (wrong arg packing)
2026-06-11 07:59:43 +02:00
Geoff Franks edf70e971c fix(Spawn): air-spawn takeoff event never fired (wrong arg packing)
SPAWN:SpawnAtAirbase scheduled the synthetic takeoff event for air-spawned
groups with:

    self:ScheduleOnce(5, BASE.CreateEventTakeoff,
                      {GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject()})

BASE:ScheduleOnce(Start, SchedulerFunction, ...) forwards its trailing
arguments to the scheduled function as varargs (it wraps `...` in a table
internally). Wrapping the arguments in a table here made that table argument
number one, so CreateEventTakeoff ran with the {group, time, dcs} table as
`self`. A plain table has no :F(), the very first line errored, and the
S_EVENT_TAKEOFF event was never raised. Air-spawned AI_A2A_DISPATCHER GCI
defenders therefore never activated (observed: zero QRA scrambled with
takeoff = Air).

The sibling call site in SpawnAtParkingSpot is correct because it uses
SCHEDULER:New(nil, fn, {args}, 5), which DOES take a single argument table.
Drop the braces so the args pass as varargs, matching CreateEventTakeoff's
(self=group, EventTime, Initiator) signature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 21:02:40 -04:00
Thomas 7c5af54473 Merge pull request #2594 from FlightControl-Master/master-ng
Merge from master
2026-06-07 20:04:55 +02:00
Applevangelist 2aa9b91ce5 Merge remote-tracking branch 'origin/master-ng' into develop 2026-06-05 14:25:35 +02:00
Applevangelist fdc19a6898 Merge remote-tracking branch 'origin/develop' into develop 2026-05-24 13:01:26 +02:00
Applevangelist d3ebf023fb Merge remote-tracking branch 'origin/master-ng' into develop 2026-05-24 13:01:22 +02:00
Thomas d40c559d2d Merge pull request #2592 from FlightControl-Master/master-ng
Merge
2026-05-21 20:04:54 +02:00
7 changed files with 16 additions and 66 deletions
+1 -5
View File
@@ -1453,11 +1453,7 @@ function EVENT:onEvent( Event )
-- Weapon.
if Event.weapon and type(Event.weapon) == "table" and Event.weapon.isExist and Event.weapon:isExist() then
Event.Weapon = Event.weapon
if Event.weapon_name == "ZELL Booster" then
Event.WeaponName = "ZELL Booster"
else
Event.WeaponName = Event.weapon:isExist() and Event.weapon.getTypeName and Event.weapon:getTypeName() or "Unknown Weapon"
end
Event.WeaponName = Event.weapon:isExist() and Event.weapon.getTypeName and Event.weapon:getTypeName() or "Unknown Weapon"
if Event.weapon_name == "ZELL Booster" then Event.WeaponName = "ZELL Booster" end
Event.WeaponUNIT = CLIENT:Find( Event.Weapon, '', true ) -- Sometimes, the weapon is a player unit!
Event.WeaponPlayerName = Event.WeaponUNIT and Event.Weapon.getPlayerName and Event.Weapon:getPlayerName()
@@ -375,13 +375,3 @@ function SCHEDULEDISPATCHER:NoTrace( Scheduler )
Scheduler.ShowTrace = false
end
--- Helper for memory cleanup for self stopping schedulers
-- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
-- @param #string CallID (Optional) Scheduler Call ID.
function SCHEDULEDISPATCHER:_Reclaim( Scheduler, CallID )
self:Stop( Scheduler, CallID ) -- remove DCS timer, nil ScheduleID
if self.Schedule[Scheduler] then self.Schedule[Scheduler][CallID] = nil end
self.ObjectSchedulers[CallID] = nil
self.PersistentSchedulers[CallID] = nil
end
+6 -9
View File
@@ -4201,16 +4201,13 @@ function AIRBOSS:_CheckRecoveryTimes()
-- Time into the wind 1 day or if longer recovery time + the 5 min early.
local t = math.max( nextwindow.STOP - nextwindow.START + self.dTturn, 60 * 60 * 24 )
-- Recovery wind on deck in knots.
-- NOTE: Do NOT clamp the desired wind-over-deck (WOD) to the carrier's max hull
-- speed here. WOD = carrier speed + headwind, so a WOD target above the hull's
-- top speed is achievable whenever there is wind. CarrierTurnIntoWind ->
-- GetHeadingIntoWind already converts the WOD target into the required hull
-- speed and caps THAT at the carrier's max speed (Vmax) internally. Clamping the
-- WOD target itself capped achievable WOD at ~30 kts (the supercarrier's max
-- hull speed) even in strong wind, which made high-WOD recovery windows fall
-- short of their requested value.
-- Recovery wind on deck in knots.
local v = UTILS.KnotsToMps( nextwindow.SPEED )
-- Check that we do not go above max possible speed.
local vmax = self.carrier:GetSpeedMax() / 3.6 -- convert to m/s
v = math.min( v, vmax )
-- Route carrier into the wind. Sets self.turnintowind=true
self:CarrierTurnIntoWind( t, v, uturn )
+4 -32
View File
@@ -135,7 +135,6 @@
-- local mywing = EASYGCICAP:New("Blue CAP Operations",AIRBASE.Caucasus.Kutaisi,"blue","Blue EWR")
--
-- -- Add a CAP patrol point belonging to our airbase, we'll be at 30k ft doing 400 kn, initial direction 90 degrees (East), leg 20NM
-- -- NOTE - Skip this function and do not create CAP Points if you want GCI behaviour only.
-- mywing:AddPatrolPointCAP(AIRBASE.Caucasus.Kutaisi,ZONE:FindByName("Blue Zone 1"):GetCoordinate(),30000,400,90,20)
--
-- -- Add a Squadron with template "Blue Sq1 M2000c", 20 airframes, skill good, Modex starting with 102 and skin "Vendee Jeanne"
@@ -191,10 +190,9 @@
-- * @{#EASYGCICAP.SetDefaultResurrection}: Set how many seconds the AirWing stays inoperable after the AirWing STATIC HQ ist destroyed, default 900 secs.
-- * @{#EASYGCICAP.SetDefaultCAPSpeed}: Set how many knots the CAP flights should do (will be altitude corrected), default 300 kn.
-- * @{#EASYGCICAP.SetDefaultCAPAlt}: Set at which altitude (ASL) the CAP planes will fly, default 25,000 ft.
-- * @{#EASYGCICAP.SetDefaultINTERCEPTAlt}: Set at which altitude (ASL) the Intercept planes will fly, default 25,000 ft.
-- * @{#EASYGCICAP.SetDefaultCAPDirection}: Set the initial direction from the CAP point the planes will fly in degrees, default is 90°.
-- * @{#EASYGCICAP.SetDefaultCAPLeg}: Set the length of the CAP leg, default is 15 NM.
-- * @{#EASYGCICAP.SetDefaultCAPGrouping}: Set how many planes will be spawned per mission (CAP/GCI), defaults to 2.
-- * @{#EASYGCICAP.SetDefaultCAPGrouping}: Set how many planes will be spawned per mission (CVAP/GCI), defaults to 2.
-- * @{#EASYGCICAP.SetDefaultMissionRange}: Set how many NM the planes can go from the home base, defaults to 100.
-- * @{#EASYGCICAP.SetDefaultNumberAlert5Standby}: Set how many planes will be spawned on cold standby (Alert5), default 2.
-- * @{#EASYGCICAP.SetDefaultEngageRange}: Set max engage range for CAP flights if they detect intruders, defaults to 50.
@@ -288,7 +286,7 @@ EASYGCICAP = {
--- EASYGCICAP class version.
-- @field #string version
EASYGCICAP.version="0.1.38"
EASYGCICAP.version="0.1.36"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--
@@ -589,17 +587,6 @@ function EASYGCICAP:SetDefaultCAPAlt(Altitude)
return self
end
--- Set default INTERCEPT Altitude in feet
-- @param #EASYGCICAP self
-- @param #number Altitude (Optional) Altitude defaults to 25000
-- @return #EASYGCICAP self
function EASYGCICAP:SetDefaultINTERCEPTAlt(Altitude)
self:T(self.lid.."SetDefaultINTERCEPTAlt")
self.interceptalt = Altitude or 25000
return self
end
--
--- Set default CAP lieg initial direction in degrees
-- @param #EASYGCICAP self
-- @param #number Direction (Optional) Direction defaults to 90 (East)
@@ -767,15 +754,6 @@ end
function EASYGCICAP:_AddAirwing(Airbasename, Alias)
self:T(self.lid.."_AddAirwing "..Airbasename)
-- Gather Some Stats
local function counttable(tbl)
local count = 0
for _,_data in pairs(tbl) do
count = count + 1
end
return count
end
local CapFormation = self.CapFormation
local DespawnAfterLanding = self.DespawnAfterLanding
local DespawnAfterHolding = self.DespawnAfterHolding
@@ -794,11 +772,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
CAP_Wing:SetMarker(false)
CAP_Wing:SetAirbase(AIRBASE:FindByName(Airbasename))
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.
if counttable(self.ManagedCP) >0 then
CAP_Wing:SetNumberCAP(self.capgrouping)
end
CAP_Wing:SetNumberCAP(self.capgrouping)
CAP_Wing:SetCapCloseRaceTrack(true)
if self.showpatrolpointmarks then
@@ -1065,7 +1039,7 @@ function EASYGCICAP:_SetCAPPatrolPoints()
MESSAGE:New(self.lid.."You are trying to create a CAP point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
return
end
local Wing = self.wings[data.AirbaseName][1] -- Ops.AirWing#AIRWING
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
local Coordinate = data.Coordinate
local Altitude = data.Altitude
local Speed = data.Speed
@@ -1531,7 +1505,6 @@ function EASYGCICAP:_AssignIntercept(Cluster)
local overhead = self.overhead
local capspeed = self.capspeed + 100
local capalt = self.capalt
local interalt = self.interceptalt or self.capalt
local maxsize = self.maxinterceptsize
local repeatsonfailure = self.repeatsonfailure
@@ -1619,7 +1592,6 @@ function EASYGCICAP:_AssignIntercept(Cluster)
:SetRepeatOnFailure(repeats)
:SetMissionSpeed(UTILS.KnotsToAltKIAS(capspeed,capalt))
:SetMissionAltitude(capalt)
:SetEngageAltitude(interalt)
if nogozoneset:Count() > 0 then
InterceptAuftrag:AddConditionSuccess(
+3 -3
View File
@@ -2108,7 +2108,7 @@ function MSRS:_HoundTextToSpeech(Message,Frequencies,Modulations,Volume,Label,Co
local ffs = {}
for _,_f in pairs(Frequencies) do
table.insert(ffs,string.format("%.3f",_f))
table.insert(ffs,string.format("%.1f",_f))
end
local freqs = table.concat(ffs, ",")
@@ -2214,7 +2214,7 @@ function MSRS:_HoundTestTone(Frequencies, Modulations, Coalition)
local ffs = {}
for _,_f in pairs(Frequencies or self.frequencies) do
table.insert(ffs,string.format("%.3f",_f))
table.insert(ffs,string.format("%.1f",_f))
end
local freqs = table.concat(ffs, ",")
@@ -2291,7 +2291,7 @@ function MSRS:RadioJammerOn(Frequencies, Modulations, Coalition, Noisetype, Volu
local ffs = {}
for _,_f in pairs(Frequencies or self.frequencies) do
table.insert(ffs,string.format("%.3f",_f))
table.insert(ffs,string.format("%.1f",_f))
end
local freqs = table.concat(ffs, ",")
+2 -2
View File
@@ -523,7 +523,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 +568,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",
@@ -2378,11 +2378,6 @@ function UTILS.IsLoadingDoorOpen( unit_name )
BASE:T(unit_name .. " front door(s) are open or doors removed")
return true
end
if type_name == "Ka-50_3" and unit:getDrawArgumentValue(38) == 1 then
BASE:T(unit_name .. " cockpit door is open")
return true
end
if type_name=="C-130J-30" and (unit:getDrawArgumentValue(86)==1)then
BASE:T(unit_name.." rear doors are open")