From 9364579a18e51086084f285a3c8e5a989ba966f6 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 19 Apr 2025 17:53:00 +0200 Subject: [PATCH 01/50] #EASYGCICAP - fixed some wrongly used self.values #OPSZONE - make check time schedule configureable --- Moose Development/Moose/Ops/EasyGCICAP.lua | 7 +++++-- Moose Development/Moose/Ops/OpsZone.lua | 9 ++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 4fcd7c2cb..31b732a74 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -259,7 +259,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.18" +EASYGCICAP.version="0.1.20" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -606,6 +606,9 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) local Intel = self.Intel local TankerInvisible = self.TankerInvisible + local engagerange = self.engagerange + local GoZoneSet = self.GoZoneSet + local NoGoZoneSet = self.NoGoZoneSet function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission) local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP @@ -619,7 +622,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch() if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then flightgroup:SetDetection(true) - flightgroup:SetEngageDetectedOn(self.engagerange,{"Air"},self.GoZoneSet,self.NoGoZoneSet) + flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet) flightgroup:SetOutOfAAMRTB() if CapFormation then flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation) diff --git a/Moose Development/Moose/Ops/OpsZone.lua b/Moose Development/Moose/Ops/OpsZone.lua index bbcf4f97b..9a47b16ae 100644 --- a/Moose Development/Moose/Ops/OpsZone.lua +++ b/Moose Development/Moose/Ops/OpsZone.lua @@ -53,7 +53,8 @@ -- @field #number threatlevelCapture Threat level necessary to capture a zone. -- @field Core.Set#SET_UNIT ScanUnitSet Set of scanned units. -- @field Core.Set#SET_GROUP ScanGroupSet Set of scanned groups. --- @extends Core.Fsm#FSM +-- @field #number UpdateSeconds Run status every this many seconds. +-- @extends Core.Fsm#FSM --- *Gentlemen, when the enemy is committed to a mistake we must not interrupt him too soon.* --- Horation Nelson -- @@ -77,6 +78,7 @@ OPSZONE = { Tnut = 0, chiefs = {}, Missions = {}, + UpdateSeconds = 120, } --- OPSZONE.MISSION @@ -97,7 +99,7 @@ OPSZONE.ZoneType={ --- OPSZONE class version. -- @field #string version -OPSZONE.version="0.6.1" +OPSZONE.version="0.6.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -733,7 +735,8 @@ function OPSZONE:onafterStart(From, Event, To) self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self) -- Status update. - self.timerStatus:Start(1, 120) + local EveryUpdateIn = self.UpdateSeconds or 120 + self.timerStatus:Start(1, EveryUpdateIn) -- Handle base captured event. if self.airbase then From 9705b49dbeeeaed9273aa4e6110fa14f46d85812 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 20 Apr 2025 15:52:30 +0200 Subject: [PATCH 02/50] #PLAYERTASKMANAGER - Surfaced some functions for conflict zones --- Moose Development/Moose/Ops/PlayerTask.lua | 72 ++++++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 673c5095c..74d53667d 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -21,7 +21,7 @@ -- === -- @module Ops.PlayerTask -- @image OPS_PlayerTask.jpg --- @date Last Update Jan 2025 +-- @date Last Update April 2025 do @@ -1902,7 +1902,7 @@ PLAYERTASKCONTROLLER.Messages = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASKCONTROLLER.version="0.1.69" +PLAYERTASKCONTROLLER.version="0.1.70" --- Create and run a new TASKCONTROLLER instance. -- @param #PLAYERTASKCONTROLLER self @@ -2415,7 +2415,7 @@ function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode,Holdi end ) else - self:E(self.lid.."No FLIGHTGROUP object passed or FLIGHTGROUP is not alive!") + self:E(self.lid.."No OPSGROUP/SET_OPSGROUP object passed or object is not alive!") end else self.autolase = nil @@ -3703,6 +3703,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client) else CoordText = Coordinate:ToStringA2A(Client,nil,self.ShowMagnetic) end + --self:I("CoordText = "..CoordText) -- Threat Level local ThreatLevel = task.Target:GetThreatLevelMax() --local ThreatLevelText = "high" @@ -3837,7 +3838,8 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client) Text = string.gsub(Text,"9","niner") CoordText = "MGRS;"..Text if self.PathToGoogleKey then - CoordText = string.format("%s",CoordText) + --CoordText = string.format("%s",CoordText) + --doesn't seem to work any longer end --self:I(self.lid.." | ".. CoordText) end @@ -3855,10 +3857,12 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client) CoordText = string.gsub(ttstext," BR, "," Bee, Arr, ") end elseif task:HasFreetext() then + -- add tts freetext local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale) ttstext = ttstext .. string.format("; %s: ",brieftxt)..task:GetFreetextTTS() end + --self:I("**** TTS Text ****\n"..ttstext.."\n*****") self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,2) end else @@ -4357,7 +4361,7 @@ function PLAYERTASKCONTROLLER:SwitchDetectStatics(OnOff) return self end ---- [User] Add accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add an accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4371,7 +4375,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZone(AcceptZone) return self end ---- [User] Add accept SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add an accept SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Set#SET_ZONE AcceptZoneSet Add a SET_ZONE to the accept zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4385,7 +4389,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZoneSet(AcceptZoneSet) return self end ---- [User] Add reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add a reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4399,7 +4403,7 @@ function PLAYERTASKCONTROLLER:AddRejectZone(RejectZone) return self end ---- [User] Add reject SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add a reject SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self -- @param Core.Set#SET_ZONE RejectZoneSet Add a zone to the reject zone set. -- @return #PLAYERTASKCONTROLLER self @@ -4413,9 +4417,37 @@ function PLAYERTASKCONTROLLER:AddRejectZoneSet(RejectZoneSet) return self end ---- [User] Remove accept zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Add a conflict zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self --- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set. +-- @param Core.Zone#ZONE ConflictZone Add a zone to the conflict zone set. +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:AddConflictZone(ConflictZone) + self:T(self.lid.."AddConflictZone") + if self.Intel then + self.Intel:AddConflictZone(ConflictZone) + else + self:E(self.lid.."*****NO detection has been set up (yet)!") + end + return self +end + +--- [User] Add a conflict SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +-- @param #PLAYERTASKCONTROLLER self +-- @param Core.Set#SET_ZONE ConflictZoneSet Add a zone to the conflict zone set. +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:AddConflictZoneSet(ConflictZoneSet) + self:T(self.lid.."AddConflictZoneSet") + if self.Intel then + self.Intel.conflictzoneset:AddSet(ConflictZoneSet) + else + self:E(self.lid.."*****NO detection has been set up (yet)!") + end + return self +end + +--- [User] Remove an accept zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +-- @param #PLAYERTASKCONTROLLER self +-- @param Core.Zone#ZONE AcceptZone Remove this zone from the accept zone set. -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone) self:T(self.lid.."RemoveAcceptZone") @@ -4427,11 +4459,11 @@ function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone) return self end ---- [User] Remove reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +--- [User] Remove a reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. -- @param #PLAYERTASKCONTROLLER self --- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set. +-- @param Core.Zone#ZONE RejectZone Remove this zone from the reject zone set. -- @return #PLAYERTASKCONTROLLER self -function PLAYERTASKCONTROLLER:RemoveRejectZoneSet(RejectZone) +function PLAYERTASKCONTROLLER:RemoveRejectZone(RejectZone) self:T(self.lid.."RemoveRejectZone") if self.Intel then self.Intel:RemoveRejectZone(RejectZone) @@ -4441,6 +4473,20 @@ function PLAYERTASKCONTROLLER:RemoveRejectZoneSet(RejectZone) return self end +--- [User] Remove a conflict zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this. +-- @param #PLAYERTASKCONTROLLER self +-- @param Core.Zone#ZONE ConflictZone Remove this zone from the conflict zone set. +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:RemoveConflictZone(ConflictZone) + self:T(self.lid.."RemoveConflictZone") + if self.Intel then + self.Intel:RemoveConflictZone(ConflictZone) + else + self:E(self.lid.."*****NO detection has been set up (yet)!") + end + return self +end + --- [User] Set the top menu name to a custom string. -- @param #PLAYERTASKCONTROLLER self -- @param #string Name The name to use as the top menu designation. From 0f6439cf9fe6d8cc38a2919adce2dedf031100c4 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 20 Apr 2025 17:49:25 +0200 Subject: [PATCH 03/50] #MANTIS - added C-RAM Point Defense --- Moose Development/Moose/Functional/Mantis.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 0ebe76f4a..bd529dcd3 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -22,7 +22,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg -- --- Last Update: Mar 2025 +-- Last Update: Apr 2025 ------------------------------------------------------------------------- --- **MANTIS** class, extends Core.Base#BASE @@ -393,6 +393,7 @@ MANTIS.SamData = { ["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" }, ["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" }, ["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" }, + ["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" }, -- units from HDS Mod, multi launcher options is tricky ["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"}, ["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" }, @@ -689,7 +690,7 @@ do -- TODO Version -- @field #string version - self.version="0.9.27" + self.version="0.9.28" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -1493,7 +1494,7 @@ do elseif chm then SAMData = self.SamDataCH end - --self:T("Looking to auto-match for "..grpname) + --self:I("Looking to auto-match for "..grpname) for _,_unit in pairs(units) do local unit = _unit -- Wrapper.Unit#UNIT local type = string.lower(unit:GetTypeName()) From 6f72697e267e81ec859108f619045989bdb4dbdc Mon Sep 17 00:00:00 2001 From: shaji Date: Mon, 21 Apr 2025 19:11:22 +0200 Subject: [PATCH 04/50] [ADDED] New Kola airbases -- * AIRBASE.Kola.Alta -- * AIRBASE.Kola.Sodankyla -- * AIRBASE.Kola.Enontekio -- * AIRBASE.Kola.Evenes -- * AIRBASE.Kola.Hosio --- Moose Development/Moose/Wrapper/Airbase.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 21d69a296..0e3e8d9e3 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -793,6 +793,11 @@ AIRBASE.Sinai = { -- * AIRBASE.Kola.Alakourtti -- * AIRBASE.Kola.Kittila -- * AIRBASE.Kola.Bardufoss +-- * AIRBASE.Kola.Alta +-- * AIRBASE.Kola.Sodankyla +-- * AIRBASE.Kola.Enontekio +-- * AIRBASE.Kola.Evenes +-- * AIRBASE.Kola.Hosio -- -- @field Kola AIRBASE.Kola = { @@ -818,6 +823,11 @@ AIRBASE.Kola = { ["Alakourtti"] = "Alakourtti", ["Kittila"] = "Kittila", ["Bardufoss"] = "Bardufoss", + ["Alta"] = "Alta", + ["Sodankyla"] = "Sodankyla", + ["Enontekio"] = "Enontekio", + ["Evenes"] = "Evenes", + ["Hosio"] = "Hosio", } --- Airbases of the Afghanistan map From 195aac45048426d4b01104507f1039426f1f8021 Mon Sep 17 00:00:00 2001 From: shaji Date: Tue, 22 Apr 2025 20:57:06 +0200 Subject: [PATCH 05/50] [ADDED] IsAlive condition for Unit and Group out message --- Moose Development/Moose/Core/Message.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 4165bdc57..ff74527f2 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -206,7 +206,7 @@ end function MESSAGE:ToGroup( Group, Settings ) self:F( Group.GroupName ) - if Group then + if Group and Group:IsAlive() then if self.MessageType then local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS @@ -231,7 +231,7 @@ end function MESSAGE:ToUnit( Unit, Settings ) self:F( Unit.IdentifiableName ) - if Unit then + if Unit and Unit:IsAlive() then if self.MessageType then local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS From 3c742727490b1eea304a0e8a7f6d23a3bc37a4fc Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 23 Apr 2025 09:00:05 +0200 Subject: [PATCH 06/50] Update Range.lua #RANGE log an error if os/os.date() are not available --- Moose Development/Moose/Functional/Range.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 62b85e828..8badfd798 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -2102,7 +2102,12 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV result.attackHdg = attackHdg result.attackVel = attackVel result.attackAlt = attackAlt - result.date=os and os.date() or "n/a" + if os and os.date then + result.date=os.date() + else + self:E(self.lid.."os or os.date() not available") + result.date = "n/a" + end -- Add to table. table.insert( _results, result ) From dd7b87e9cd6f38aced7935d38ce74804c182199c Mon Sep 17 00:00:00 2001 From: shaji Date: Wed, 23 Apr 2025 13:39:55 +0200 Subject: [PATCH 07/50] [ADDED] AIRBOSS:SetMaxSectionDistance --- Moose Development/Moose/Ops/Airboss.lua | 161 +++++++++++++----------- 1 file changed, 90 insertions(+), 71 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 5ef25bdc7..5e6f70443 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1731,10 +1731,10 @@ AIRBOSS.Difficulty = { -- @field #table trapsheet Groove data table recorded every 0.5 seconds. -- @field #boolean trapon If true, save trap sheets. -- @field #string debriefschedulerID Debrief scheduler ID. --- +-- -- @field Sound.SRS#MSRS SRS -- @field Sound.SRS#MSRSQUEUE SRSQ --- +-- -- @extends #AIRBOSS.FlightGroup --- Main group level radio menu: F10 Other/Airboss. @@ -1912,6 +1912,9 @@ function AIRBOSS:New( carriername, alias ) -- Set max section members. Default 2. self:SetMaxSectionSize() + -- Set max section distance. Default 100 meters. + self:SetMaxSectionDistance() + -- Set max flights per stack. Default is 2. self:SetMaxFlightsPerStack() @@ -2539,7 +2542,7 @@ function AIRBOSS:AddRecoveryWindow( starttime, stoptime, case, holdingoffset, tu return self end if Tstop <= Tnow then - string.format( "WARNING: Recovery stop time %s already over. Tnow=%s! Recovery window rejected.", UTILS.SecondsToClock( Tstop ), UTILS.SecondsToClock( Tnow ) ) + string.format( "WARNING: Recovery stop time %s already over. Tnow=%s! Recovery window rejected.", UTILS.SecondsToClock( Tstop ), UTILS.SecondsToClock( Tnow ) ) return self end @@ -3066,7 +3069,7 @@ end -- @param #number Port Port of the SRS server, defaults to 5002. -- @param #string Culture (Optional, Airboss Culture) Culture, defaults to "en-US". -- @param #string Gender (Optional, Airboss Gender) Gender, e.g. "male" or "female". Defaults to "male". --- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings. +-- @param #string Voice (Optional, Airboss Voice) Set to use a specific voice. Will **override gender and culture** settings. -- @param #string GoogleCreds (Optional) Path to Google credentials, e.g. "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourgooglekey.json". -- @param #number Volume (Optional) E.g. 0.75. Defaults to 1.0 (loudest). -- @param #table AltBackend (Optional) See MSRS for details. @@ -3097,10 +3100,10 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum -- SRSQUEUE self.SRSQ = MSRSQUEUE:New("AIRBOSS") self.SRSQ:SetTransmitOnlyWithPlayers(true) - if not self.PilotRadio then + if not self.PilotRadio then self:SetSRSPilotVoice() end - return self + return self end --- Set LSO radio frequency and modulation. Default frequency is 264 MHz AM. @@ -3343,6 +3346,22 @@ function AIRBOSS:SetMaxSectionSize( nmax ) return self end +--- Set maximum distance up to which section members are allowed (default: 100 meters). +-- @param #AIRBOSS self +-- @param #number dmax Max distance in meters (default 100 m). Minimum is 10 m, maximum is 5000 m. +-- @return #AIRBOSS self +function AIRBOSS:SetMaxSectionDistance( dmax ) + if dmax then + if dmax < 10 then + dmax = 10 + elseif dmax > 5000 then + dmax = 5000 + end + end + self.maxsectiondistance = dmax or 100 + return self +end + --- Set max number of flights per stack. All members of a section count as one "flight". -- @param #AIRBOSS self -- @param #number nmax Number of max allowed flights per stack. Default is two. Minimum is one, maximum is 4. @@ -11596,7 +11615,7 @@ function AIRBOSS:GetHeadingIntoWind_old( vdeck, magnetic, coord ) local function adjustDegreesForWindSpeed(windSpeed) local degreesAdjustment = 0 -- the windspeeds are in m/s - + -- +0 degrees at 15m/s = 37kts -- +0 degrees at 14m/s = 35kts -- +0 degrees at 13m/s = 33kts @@ -11611,7 +11630,7 @@ function AIRBOSS:GetHeadingIntoWind_old( vdeck, magnetic, coord ) -- +20 degrees at 4m/s = 26kts -- +20 degrees at 3m/s = 26kts -- +30 degrees at 2m/s = 26kts 1s - + if windSpeed > 0 and windSpeed < 3 then degreesAdjustment = 30 elseif windSpeed >= 3 and windSpeed < 5 then @@ -11623,7 +11642,7 @@ function AIRBOSS:GetHeadingIntoWind_old( vdeck, magnetic, coord ) elseif windSpeed >= 13 then degreesAdjustment = 0 end - + return degreesAdjustment end @@ -11682,60 +11701,60 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord ) local h=self:GetHeading(magnetic) return h, math.min(vdeck, Vmax) end - + -- Convert wind speed to knots. vwind=UTILS.MpsToKnots(vwind) - + -- Wind to in knots. local windto=(windfrom+180)%360 - + -- Offset angle in rad. We also define the rotation to be clock-wise, which requires a minus sign. local alpha=math.rad(-Offset) - + -- Constant. local C = math.sqrt(math.cos(alpha)^2 / math.sin(alpha)^2 + 1) - + -- Upper limit of desired speed due to max boat speed. local vdeckMax=vwind + math.cos(alpha) * Vmax - + -- Lower limit of desired speed due to min boat speed. local vdeckMin=vwind + math.cos(alpha) * Vmin - - + + -- Speed of ship so it matches the desired speed. local v=0 - - -- Angle wrt. to wind TO-direction + + -- Angle wrt. to wind TO-direction local theta=0 if vdeck>vdeckMax then -- Boat cannot go fast enough - + -- Set max speed. v=Vmax - + -- Calculate theta. theta = math.asin(v/(vwind*C)) - math.asin(-1/C) - + elseif vdeckvwind then -- Too little wind - + -- Set theta to 90° theta=math.pi/2 - + -- Set speed. v = math.sqrt(vdeck^2 - vwind^2) - + else -- Normal case theta = math.asin(vdeck * math.sin(alpha) / vwind) @@ -11744,9 +11763,9 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord ) -- Magnetic heading. local magvar= magnetic and self.magvar or 0 - + -- Ship heading so cross wind is min for the given wind. - local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 + local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 return intowind, v end @@ -12204,7 +12223,7 @@ function AIRBOSS:_LSOgrade( playerData ) -- Normal laning part at the beginning local Gb = GXX .. " " .. GIM - -- Number of deviations that occurred at the the beginning of the landing (XX or IM). These are graded like in non-VTOL landings, i.e. on deviations is + -- Number of deviations that occurred at the the beginning of the landing (XX or IM). These are graded like in non-VTOL landings, i.e. on deviations is local N=nXX+nIM local nL=count(Gb, '_')/2 local nS=count(Gb, '%(') @@ -12222,7 +12241,7 @@ function AIRBOSS:_LSOgrade( playerData ) if nL>0 or nLv>1 then -- Larger deviations at XX or IM or at least one larger deviation IC or AR==> "No grade" 2.0 points. - -- In other words, we allow one larger deviation at IC+AR + -- In other words, we allow one larger deviation at IC+AR grade="--" points=2.0 elseif nN>0 or nNv>1 or nLv==1 then @@ -13718,7 +13737,7 @@ function AIRBOSS:CarrierTurnIntoWind( time, vdeck, uturn ) local deltaH = self:_GetDeltaHeading( hdg, hiw ) -- Debug output - self:I( self.lid .. string.format( "Carrier steaming into the wind (%.1f kts). Heading=%03d-->%03d (Delta=%.1f), Speed=%.1f knots, Distance=%.1f NM, Time=%d sec", + self:I( self.lid .. string.format( "Carrier steaming into the wind (%.1f kts). Heading=%03d-->%03d (Delta=%.1f), Speed=%.1f knots, Distance=%.1f NM, Time=%d sec", UTILS.MpsToKnots( vwind ), hdg, hiw, deltaH, speedknots, distNM, speedknots, time ) ) -- Current coordinate. @@ -14930,12 +14949,12 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p if radio == nil or call == nil then return end - + if not self.SRS then - + -- Create a new radio transmission item. local transmission = {} -- #AIRBOSS.Radioitem - + transmission.radio = radio transmission.call = call transmission.Tplay = timer.getAbsTime() + (delay or 0) @@ -14943,49 +14962,49 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p transmission.isplaying = false transmission.Tstarted = nil transmission.loud = loud and call.loud - + -- Player onboard number if sender has one. if self:_IsOnboard( call.modexsender ) then self:_Number2Radio( radio, call.modexsender, delay, 0.3, pilotcall ) end - + -- Play onboard number if receiver has one. if self:_IsOnboard( call.modexreceiver ) then self:_Number2Radio( radio, call.modexreceiver, delay, 0.3, pilotcall ) end - + -- Add transmission to the right queue. local caller = "" if radio.alias == "LSO" then - + table.insert( self.RQLSO, transmission ) - + caller = "LSOCall" - + -- Schedule radio queue checks. if not self.RQLid then self:T( self.lid .. string.format( "Starting LSO radio queue." ) ) self.RQLid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQLSO, "LSO" }, 0.02, 0.05 ) end - + elseif radio.alias == "MARSHAL" then - + table.insert( self.RQMarshal, transmission ) - + caller = "MarshalCall" - + if not self.RQMid then self:T( self.lid .. string.format( "Starting Marhal radio queue." ) ) self.RQMid = self.radiotimer:Schedule( nil, AIRBOSS._CheckRadioQueue, { self, self.RQMarshal, "MARSHAL" }, 0.02, 0.05 ) end - + end - + -- Append radio click sound at the end of the transmission. if click then self:RadioTransmission( radio, self[caller].CLICK, false, delay ) end - + else -- SRS transmission @@ -14996,7 +15015,7 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p local voice = nil local gender = nil local culture = nil - + if radio.alias == "AIRBOSS" then frequency = self.AirbossRadio.frequency modulation = self.AirbossRadio.modulation @@ -15004,13 +15023,13 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p gender = self.AirbossRadio.gender culture = self.AirbossRadio.culture end - + if radio.alias == "MARSHAL" then voice = self.MarshalRadio.voice gender = self.MarshalRadio.gender culture = self.MarshalRadio.culture end - + if radio.alias == "LSO" then frequency = self.LSORadio.frequency modulation = self.LSORadio.modulation @@ -15018,7 +15037,7 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p gender = self.LSORadio.gender culture = self.LSORadio.culture end - + if pilotcall then voice = self.PilotRadio.voice gender = self.PilotRadio.gender @@ -15032,16 +15051,16 @@ function AIRBOSS:RadioTransmission( radio, call, loud, delay, interval, click, p modulation = self.AirbossRadio.modulation radio.alias = "AIRBOSS" end - + local volume = nil - + if loud then volume = 1.0 end - + --local text = tostring(call.modexreceiver).."; "..radio.alias.."; "..call.subtitle local text = call.subtitle - self:T(self.lid..text) + self:T(self.lid..text) local srstext = self:_GetNiceSRSText(text) self.SRSQ:NewTransmission(srstext, call.duration, self.SRS, nil, 0.1, nil, call.subtitle, call.subduration, frequency, modulation, gender, culture, voice, volume, radio.alias) end @@ -15061,11 +15080,11 @@ function AIRBOSS:SetSRSPilotVoice( Voice, Gender, Culture ) self.PilotRadio.voice = Voice or MSRS.Voices.Microsoft.David self.PilotRadio.gender = Gender or "male" self.PilotRadio.culture = Culture or "en-US" - + if (not Voice) and self.SRS and self.SRS:GetProvider() == MSRS.Provider.GOOGLE then self.PilotRadio.voice = MSRS.Voices.Google.Standard.en_US_Standard_J end - + return self end @@ -15379,44 +15398,44 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio -- SCHEDULER:New(nil, self.MessageToPlayer, {self, playerData, message, sender, receiver, duration, clear}, delay) self:ScheduleOnce( delay, self.MessageToPlayer, self, playerData, message, sender, receiver, duration, clear ) else - + if not self.SRS then -- Wait until previous sound finished. local wait = 0 - + -- Onboard number to get the attention. if receiver == playerData.onboard then - + -- Which voice over number to use. if sender and (sender == "LSO" or sender == "MARSHAL" or sender == "AIRBOSS") then - + -- User sound of board number. wait = wait + self:_Number2Sound( playerData, sender, receiver ) - + end end - + -- Negative. if string.find( text:lower(), "negative" ) then local filename = self:_RadioFilename( self.MarshalCall.NEGATIVE, false, "MARSHAL" ) USERSOUND:New( filename ):ToGroup( playerData.group, wait ) wait = wait + self.MarshalCall.NEGATIVE.duration end - + -- Affirm. if string.find( text:lower(), "affirm" ) then local filename = self:_RadioFilename( self.MarshalCall.AFFIRMATIVE, false, "MARSHAL" ) USERSOUND:New( filename ):ToGroup( playerData.group, wait ) wait = wait + self.MarshalCall.AFFIRMATIVE.duration end - + -- Roger. if string.find( text:lower(), "roger" ) then local filename = self:_RadioFilename( self.MarshalCall.ROGER, false, "MARSHAL" ) USERSOUND:New( filename ):ToGroup( playerData.group, wait ) wait = wait + self.MarshalCall.ROGER.duration end - + -- Play click sound to end message. if wait > 0 then local filename = self:_RadioFilename( self.MarshalCall.CLICK ) @@ -15429,7 +15448,7 @@ function AIRBOSS:MessageToPlayer( playerData, message, sender, receiver, duratio local voice = self.MarshalRadio.voice local gender = self.MarshalRadio.gender local culture = self.MarshalRadio.culture - + if not sender then sender = "AIRBOSS" end if string.find(sender,"AIRBOSS" ) then @@ -17047,7 +17066,7 @@ function AIRBOSS:_RemoveSectionMember( playerData, sectionmember ) return false end ---- Set all flights within 100 meters to be part of my section. +--- Set all flights within maxsectiondistance meters to be part of my section (default: 100 meters). -- @param #AIRBOSS self -- @param #string _unitName Name of the player unit. function AIRBOSS:_SetSection( _unitName ) @@ -17065,7 +17084,7 @@ function AIRBOSS:_SetSection( _unitName ) local mycoord = _unit:GetCoordinate() -- Max distance up to which section members are allowed. - local dmax = 100 + local dmax = self.maxsectiondistance -- Check if player is in Marshal or pattern queue already. local text From cdad3bd058b08ae9ae636a9c9b748aab575c8ee7 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 24 Apr 2025 14:48:12 +0200 Subject: [PATCH 08/50] #PLAYERTASK - make an existing marker move with the group if the group is moving around --- Moose Development/Moose/Ops/PlayerTask.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 74d53667d..8c6361a48 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -98,7 +98,7 @@ PLAYERTASK = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.25" +PLAYERTASK.version="0.1.26" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -979,6 +979,12 @@ function PLAYERTASK:onafterStatus(From, Event, To) if status == "Stopped" then return self end + -- update marker in case target is moving + if self.TargetMarker then + local coordinate = self.Target:GetCoordinate() + self.TargetMarker:UpdateCoordinate(coordinate,0.5) + end + -- Check Target status local targetdead = false From 1547d66327f0d7659df52c525ec001128977edd3 Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Sat, 26 Apr 2025 03:28:16 +0200 Subject: [PATCH 09/50] Update CTLD.lua Getting rid of this error, bad argument #1 to 'find' (string expected, got nil) --- Moose Development/Moose/Ops/CTLD.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index cd0bc8403..a10860011 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -3564,7 +3564,7 @@ end function CTLD:IsFixedWing(Unit) local typename = Unit:GetTypeName() or "none" for _,_name in pairs(self.FixedWingTypes or {}) do - if typename == _name or string.find(typename,_name,1,true) then + if _name and (typename==_name or string.find(typename,_name,1,true))then return true end end From ac4b620f16b33fcda0072e4107d29ec525d12174 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 26 Apr 2025 23:39:22 +0200 Subject: [PATCH 10/50] COORDINATE - Improved Smoke and Fire and Smoke functions by adding delay and duration parameters --- Moose Development/Moose/Core/Base.lua | 2 +- Moose Development/Moose/Core/Point.lua | 201 +++++++++++++------- Moose Development/Moose/Utilities/Utils.lua | 34 ++-- 3 files changed, 158 insertions(+), 79 deletions(-) diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index b1a12e740..81cf8892d 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -974,7 +974,7 @@ do -- Scheduling -- @param #BASE self -- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. -- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments. - -- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. + -- @param ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. -- @return #string The Schedule ID of the planned schedule. function BASE:ScheduleOnce( Start, SchedulerFunction, ... ) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 4a5d26e22..f1aa66289 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -25,7 +25,7 @@ do -- COORDINATE - --- + --- Coordinate class -- @type COORDINATE -- @field #string ClassName Name of the class -- @field #number x Component of the 3D vector. @@ -2118,14 +2118,35 @@ do -- COORDINATE end - --- Smokes the point in a color. + --- Create colored smoke the point. The smoke we last up to 5 min (DCS limitation) but you can optionally specify a shorter duration or stop it manually. -- @param #COORDINATE self - -- @param Utilities.Utils#SMOKECOLOR SmokeColor - -- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) - function COORDINATE:Smoke( SmokeColor, name ) - self:F2( { SmokeColor } ) - self.firename = name or "Smoke-"..math.random(1,100000) - trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + -- @param #number SmokeColor Color of smoke, e.g. `SMOKECOLOR.Green` for green smoke. + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) + -- @return #COORDINATE self + function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name) + self:F2( { SmokeColor, Name, Duration, Delay } ) + + SmokeColor=SmokeColor or SMOKECOLOR.Green + + if Delay and Delay>0 then + self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name) + else + + -- Create a name which is used to stop the smoke manually + self.firename = Name or "Smoke-"..math.random(1,100000) + + -- Create smoke + trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + + -- Stop smoke + if Duration and Duration>0 then + self:ScheduleOnce(Duration, COORDINATE.StopSmoke, self, self.firename ) + end + end + + return self end --- Stops smoking the point in a color. @@ -2137,49 +2158,83 @@ do -- COORDINATE --- Smoke the COORDINATE Green. -- @param #COORDINATE self - function COORDINATE:SmokeGreen() - self:F2() - self:Smoke( SMOKECOLOR.Green ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeGreen(Duration, Delay) + self:Smoke( SMOKECOLOR.Green, Duration, Delay ) + return self end --- Smoke the COORDINATE Red. -- @param #COORDINATE self - function COORDINATE:SmokeRed() - self:F2() - self:Smoke( SMOKECOLOR.Red ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeRed(Duration, Delay) + self:Smoke( SMOKECOLOR.Red, Duration, Delay ) + return self end --- Smoke the COORDINATE White. -- @param #COORDINATE self - function COORDINATE:SmokeWhite() - self:F2() - self:Smoke( SMOKECOLOR.White ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeWhite(Duration, Delay) + self:Smoke( SMOKECOLOR.White, Duration, Delay ) + return self end --- Smoke the COORDINATE Orange. -- @param #COORDINATE self - function COORDINATE:SmokeOrange() - self:F2() - self:Smoke( SMOKECOLOR.Orange ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeOrange(Duration, Delay) + self:Smoke( SMOKECOLOR.Orange, Duration, Delay ) + return self end --- Smoke the COORDINATE Blue. -- @param #COORDINATE self - function COORDINATE:SmokeBlue() - self:F2() - self:Smoke( SMOKECOLOR.Blue ) + -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. + -- @param #number Delay (Optional) Delay before the smoke is started in seconds. + -- @return #COORDINATE self + function COORDINATE:SmokeBlue(Duration, Delay) + self:Smoke( SMOKECOLOR.Blue, Duration, Delay ) + return self end --- Big smoke and fire at the coordinate. -- @param #COORDINATE self - -- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke). - -- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. - -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFire( preset, density, name ) - self:F2( { preset=preset, density=density } ) - density=density or 0.5 - self.firename = name or "Fire-"..math.random(1,10000) - trigger.action.effectSmokeBig( self:GetVec3(), preset, density, self.firename ) + -- @param #number Preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke). + -- @param #number Density (Optional) Smoke density. Number in [0,...,1]. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. + -- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFire( Preset, Density, Duration, Delay, Name ) + self:F2( { preset=Preset, density=Density } ) + + Preset=Preset or BIGSMOKEPRESET.SmallSmokeAndFire + Density=Density or 0.5 + + if Delay and Delay>0 then + self:ScheduleOnce(Delay, COORDINATE.BigSmokeAndFire, self, Preset, Density, Duration, 0, Name) + else + + self.firename = Name or "Fire-"..math.random(1,10000) + + trigger.action.effectSmokeBig( self:GetVec3(), Preset, Density, self.firename ) + + -- Stop smoke + if Duration and Duration>0 then + self:ScheduleOnce(Duration, COORDINATE.StopBigSmokeAndFire, self, self.firename ) + end + end + + return self end --- Stop big smoke and fire at the coordinate. @@ -2192,82 +2247,98 @@ do -- COORDINATE --- Small smoke and fire at the coordinate. -- @param #COORDINATE self - -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. - -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireSmall( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density, name) + -- @param #number Density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. + -- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireSmall( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Medium smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireMedium( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireMedium( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Large smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireLarge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireLarge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Huge smoke and fire at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeAndFireHuge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeAndFireHuge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, Density, Duration, Delay, Name) + return self end --- Small smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeSmall( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeSmall( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, Density, Duration, Delay, Name) + return self end --- Medium smoke at the coordinate. -- @param #COORDINATE self -- @param number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeMedium( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density, name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeMedium( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, Density, Duration, Delay, Name) + return self end --- Large smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeLarge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density,name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeLarge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, Density, Duration, Delay, Name) + return self end --- Huge smoke at the coordinate. -- @param #COORDINATE self -- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5. + -- @param #number Duration (Optional) Duration of the smoke and fire in seconds. + -- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds. -- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number. - function COORDINATE:BigSmokeHuge( density, name ) - self:F2( { density=density } ) - density=density or 0.5 - self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density,name) + -- @return #COORDINATE self + function COORDINATE:BigSmokeHuge( Density, Duration, Delay, Name ) + self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, Density, Duration, Delay, Name) + return self end --- Flares the point in a color. diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 361e786d5..73ce154c9 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -12,27 +12,35 @@ -- @module Utilities.Utils -- @image MOOSE.JPG ---- +--- Smoke color enum `trigger.smokeColor`. -- @type SMOKECOLOR --- @field Green --- @field Red --- @field White --- @field Orange --- @field Blue +-- @field #number Green Green smoke (0) +-- @field #number Red Red smoke (1) +-- @field #number White White smoke (2) +-- @field #number Orange Orange smoke (3) +-- @field #number Blue Blue smoke (4) SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR ---- +--- Flare colur enum `trigger.flareColor`. -- @type FLARECOLOR --- @field Green --- @field Red --- @field White --- @field Yellow +-- @field #number Green (0) +-- @field #number Red Red flare (1) +-- @field #number White White flare (2) +-- @field #number Yellow Yellow flare (3) FLARECOLOR = trigger.flareColor -- #FLARECOLOR --- Big smoke preset enum. -- @type BIGSMOKEPRESET +-- @field #number SmallSmokeAndFire Small moke and fire (1) +-- @field #number MediumSmokeAndFire Medium smoke and fire (2) +-- @field #number LargeSmokeAndFire Large smoke and fire (3) +-- @field #number HugeSmokeAndFire Huge smoke and fire (4) +-- @field #number SmallSmoke Small smoke (5) +-- @field #number MediumSmoke Medium smoke (6) +-- @field #number LargeSmoke Large smoke (7) +-- @field #number HugeSmoke Huge smoke (8) BIGSMOKEPRESET = { SmallSmokeAndFire=1, MediumSmokeAndFire=2, @@ -351,7 +359,7 @@ end -- @return #string Table as a string. UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - lookup_table = {} + local lookup_table = {} local function _Serialize( tbl ) @@ -490,7 +498,7 @@ end --- Counts the number of elements in a table. -- @param #table T Table to count --- @return #int Number of elements in the table +-- @return #number Number of elements in the table function UTILS.TableLength(T) local count = 0 for _ in pairs(T or {}) do count = count + 1 end From 5c3b7312c06631a6e0e990b7dc29b71a52db9985 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 26 Apr 2025 23:55:13 +0200 Subject: [PATCH 11/50] Update Range.lua - Reduced smoke duration at impact coordinate to 30 seconds --- Moose Development/Moose/Functional/Range.lua | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 8badfd798..6c0143823 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -603,7 +603,7 @@ RANGE.MenuF10Root = nil --- Range script version. -- @field #string version -RANGE.version = "2.8.0" +RANGE.version = "2.8.1" -- TODO list: -- TODO: Verbosity level for messages. @@ -2032,10 +2032,10 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV -- Smoke impact point of bomb. if playerData and playerData.smokebombimpact and insidezone then - if playerData and playerData.delaysmoke then - timer.scheduleFunction( self._DelayedSmoke, { coord = impactcoord, color = playerData.smokecolor }, timer.getTime() + self.TdelaySmoke ) + if playerData.delaysmoke then + impactcoord:Smoke(playerData.smokecolor, 30, self.TdelaySmoke) else - impactcoord:Smoke( playerData.smokecolor ) + impactcoord:Smoke(playerData.smokecolor, 30) end end @@ -2640,13 +2640,6 @@ end -- Display Messages ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Start smoking a coordinate with a delay. --- @param #table _args Argements passed. -function RANGE._DelayedSmoke( _args ) - _args.coord:Smoke(_args.color) - --trigger.action.smoke( _args.coord:GetVec3(), _args.color ) -end - --- Display top 10 stafing results of a specific player. -- @param #RANGE self -- @param #string _unitName Name of the player unit. From 3ad60a95cecc59e5699261228ee4d1e6bf2cc1f2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 27 Apr 2025 11:25:46 +0200 Subject: [PATCH 12/50] #MANTIS - Adde Gepard data, made Roland Short --- Moose Development/Moose/Functional/Mantis.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index bd529dcd3..9a412d768 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -374,7 +374,7 @@ MANTIS.radiusscale[MANTIS.SamType.POINT] = 3 MANTIS.SamData = { ["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km ["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B - ["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot" }, + ["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot str" }, ["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" }, ["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" }, ["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" }, @@ -382,7 +382,8 @@ MANTIS.SamData = { ["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" }, ["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"}, ["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" }, - ["Roland"] = { Range=5, Blindspot=0, Height=5, Type="Point", Radar="Roland" }, + ["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", Radar="Roland" }, + ["Gepard"] = { Range=5, Blindspot=0, Height=4, Type="Point", Radar="Gepard" }, ["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" }, ["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" }, ["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" }, From db23a0bf2be682a0edbe79594f7203188c1b0080 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 27 Apr 2025 11:26:22 +0200 Subject: [PATCH 13/50] #FlightGroup - added nil check for name --- Moose Development/Moose/Ops/FlightGroup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 1d77397e0..81a19cd80 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -259,7 +259,7 @@ function FLIGHTGROUP:New(group) local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #FLIGHTGROUP -- Set some string id for output to DCS.log file. - self.lid=string.format("FLIGHTGROUP %s | ", self.groupname) + self.lid=string.format("FLIGHTGROUP %s | ", self.groupname or "N/A") -- Defaults self:SetDefaultROE() From b145588ed5db17767f4cb4efbae60b912a789816 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Mon, 28 Apr 2025 09:20:04 +0200 Subject: [PATCH 14/50] Update CTLD.lua Fix an issue when a ship is used as loading zone and the ship is destroyed --- Moose Development/Moose/Ops/CTLD.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index a10860011..c0c30ec72 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -5662,6 +5662,7 @@ function CTLD:IsUnitInZone(Unit,Zonetype) if Zonetype == CTLD.CargoZoneType.SHIP then self:T("Checking Type Ship: "..zonename) local ZoneUNIT = UNIT:FindByName(zonename) + if not ZoneUNIT then return false end zonecoord = ZoneUNIT:GetCoordinate() zoneradius = czone.shiplength zonewidth = czone.shipwidth From f97ef251049d8048e34ad2300237d296582b1f1a Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 1 May 2025 22:11:43 +0200 Subject: [PATCH 15/50] Update Unit.lua --- Moose Development/Moose/Wrapper/Unit.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 10d59ed81..b4a80c643 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -1107,7 +1107,6 @@ function UNIT:GetUnits() if DCSUnit then Units[1] = UNIT:Find(DCSUnit) - - self:T3(Units) return Units end From 0c90e90c180b0c7808081b4aae1905b5cb2bc6fc Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 2 May 2025 10:52:52 +0200 Subject: [PATCH 16/50] #CSAR - fixed design issue that prevented usage of ZONE objects as MASHes --- Moose Development/Moose/Ops/CSAR.lua | 40 +++++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index e7805f25a..76f6df917 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -31,7 +31,7 @@ -- @image OPS_CSAR.jpg --- --- Last Update Jan 2025 +-- Last Update May 2025 ------------------------------------------------------------------------- --- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM @@ -313,7 +313,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31 --- CSAR class version. -- @field #string version -CSAR.version="1.0.30" +CSAR.version="1.0.31" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -2120,7 +2120,11 @@ end function CSAR:_GetClosestMASH(_heli) self:T(self.lid .. " _GetClosestMASH") local _mashset = self.mash -- Core.Set#SET_GROUP - local _mashes = _mashset:GetSetObjects() -- #table + local MashSets = {} + --local _mashes = _mashset.Set-- #table + table.insert(MashSets,_mashset.Set) + table.insert(MashSets,self.zonemashes.Set) + table.insert(MashSets,self.staticmashes.Set) local _shortestDistance = -1 local _distance = 0 local _helicoord = _heli:GetCoordinate() @@ -2151,14 +2155,19 @@ function CSAR:_GetClosestMASH(_heli) _shortestDistance = distance end - for _, _mashUnit in pairs(_mashes) do - if _mashUnit and _mashUnit:IsAlive() then - local _mashcoord = _mashUnit:GetCoordinate() - _distance = self:_GetDistance(_helicoord, _mashcoord) - if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then - _shortestDistance = _distance - end - end + for _,_mashes in pairs(MashSets) do + for _, _mashUnit in pairs(_mashes or {}) do + local _mashcoord + if _mashUnit and (not _mashUnit:IsInstanceOf("ZONE_BASE")) and _mashUnit:IsAlive() then + _mashcoord = _mashUnit:GetCoordinate() + elseif _mashUnit and _mashUnit:IsInstanceOf("ZONE_BASE") then + _mashcoord = _mashUnit:GetCoordinate() + end + _distance = self:_GetDistance(_helicoord, _mashcoord) + if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then + _shortestDistance = _distance + end + end end if _shortestDistance ~= -1 then @@ -2166,6 +2175,7 @@ function CSAR:_GetClosestMASH(_heli) else return -1 end + end --- (Internal) Display onboarded rescued pilots. @@ -2454,9 +2464,10 @@ function CSAR:onafterStart(From, Event, To) self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() - local staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterOnce() - local zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterOnce() + self.staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterOnce() + self.zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterOnce() + --[[ if staticmashes:Count() > 0 then for _,_mash in pairs(staticmashes.Set) do self.mash:AddObject(_mash) @@ -2464,10 +2475,13 @@ function CSAR:onafterStart(From, Event, To) end if zonemashes:Count() > 0 then + self:T("Adding zones to self.mash SET") for _,_mash in pairs(zonemashes.Set) do self.mash:AddObject(_mash) end + self:T("Objects in SET: "..self.mash:Count()) end + --]] if not self.coordinate then local csarhq = self.mash:GetRandom() From f1af3a50b82b7975e1a3995ecc41b975f1326223 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 2 May 2025 21:36:03 +0200 Subject: [PATCH 17/50] Update Unit.lua - GetAmmo HE shells can also be named "HESH" --- Moose Development/Moose/Wrapper/Unit.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index b4a80c643..1a5e51011 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -897,7 +897,7 @@ function UNIT:GetAmmunition() nAPshells = nAPshells + Nammo end - if ammotable[w].desc.typeName and string.find(ammotable[w].desc.typeName, "_HE", 1, true) then + if ammotable[w].desc.typeName and (string.find(ammotable[w].desc.typeName, "_HE", 1, true) or string.find(ammotable[w].desc.typeName, "HESH", 1, true)) then nHEshells = nHEshells + Nammo end From a6b622ed312fc3e7f7a7bde89bf68724ca8ba421 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 3 May 2025 17:01:02 +0200 Subject: [PATCH 18/50] #CTLD - Additional features by Lekaa to drop and build one/many in one go and pack/load or get/load in one go --- Moose Development/Moose/Ops/CTLD.lua | 1112 ++++++++++++++++---------- 1 file changed, 671 insertions(+), 441 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index c0c30ec72..405ca9a07 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -20,11 +20,12 @@ -- -- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!) -- ### Repack addition for crates: **Raiden** +-- ### Additional cool features: **Lekaa** -- -- @module Ops.CTLD -- @image OPS_CTLD.jpg --- Last Update April 2025 +-- Last Update May 2025 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -865,6 +866,7 @@ do -- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook -- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook -- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew. +-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack only. it will be a 1 step solution. -- -- ## 2.1 CH-47 Chinook support -- @@ -1412,7 +1414,7 @@ CTLD.FixedWingTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.2.33" +CTLD.version="1.3.34" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1591,6 +1593,7 @@ function CTLD:New(Coalition, Prefixes, Alias) self.subcats = {} self.subcatsTroop = {} self.showstockinmenuitems = false + self.onestepmenu = false -- disallow building in loadzones self.nobuildinloadzones = true @@ -2913,10 +2916,10 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack) if drop then text = string.format("Crates for %s have been dropped!",cratename) self:__CratesDropped(1, Group, Unit, droppedcargo) + else + self:_SendMessage(text, 10, false, Group) end - self:_SendMessage(text, 10, false, Group) self:_RefreshLoadCratesMenu(Group, Unit) - return self end @@ -3576,11 +3579,14 @@ end -- @param Wrapper.Unit#UNIT Unit -- @return #boolean Outcome function CTLD:IsHook(Unit) - if Unit and string.find(Unit:GetTypeName(),"CH.47") then - return true - else - return false - end + if not Unit then return false end + local typeName = Unit:GetTypeName() + if not typeName then return false end + if string.find(typeName, "CH.47") then + return true + else + return false + end end --- (Internal) Function to set troops positions of a template to a nice circle @@ -3763,89 +3769,103 @@ end -- @param Wrapper.Group#GROUP Group -- @param Wrapper.Unit#UNIT Unit function CTLD:_UnloadCrates(Group, Unit) - self:T(self.lid .. " _UnloadCrates") - - if not self.dropcratesanywhere then -- #1570 - -- check if we are in DROP zone - local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP) - if not inzone then - self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group) - if not self.debug then - return self - end - end - end - -- Door check - if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then - self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group) - if not self.debug then return self end - end - -- check for hover unload - local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters - local IsHerc = self:IsFixedWing(Unit) - local IsHook = self:IsHook(Unit) - if IsHerc and (not IsHook) then - -- no hover but airdrop here - hoverunload = self:IsCorrectFlightParameters(Unit) - end - -- check if we\'re landed - local grounded = not self:IsUnitInAir(Unit) - -- Get what we have loaded - local unitname = Unit:GetName() - if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then - local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo - -- looking for crate - local cargotable = loadedcargo.Cargo - for _,_cargo in pairs (cargotable) do - local cargo = _cargo -- #CTLD_CARGO - local type = cargo:GetType() -- #CTLD_CARGO.Enum - if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then - -- unload crates - self:_GetCrates(Group, Unit, cargo, 1, true) - cargo:SetWasDropped(true) - cargo:SetHasMoved(true) - end - end - -- cleanup load list - local loaded = {} -- #CTLD.LoadedCargo - loaded.Troopsloaded = 0 - loaded.Cratesloaded = 0 - loaded.Cargo = {} + self:T(self.lid .. " _UnloadCrates") - for _,_cargo in pairs (cargotable) do - local cargo = _cargo -- #CTLD_CARGO - local type = cargo:GetType() -- #CTLD_CARGO.Enum - local size = cargo:GetCratesNeeded() - if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then - table.insert(loaded.Cargo,_cargo) - loaded.Troopsloaded = loaded.Troopsloaded + size - end - if type == CTLD_CARGO.Enum.GCLOADABLE and not cargo:WasDropped() then - table.insert(loaded.Cargo,_cargo) - loaded.Cratesloaded = loaded.Cratesloaded + size + if not self.dropcratesanywhere then -- #1570 + local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP) + if not inzone then + self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group) + if not self.debug then + return self + end end end - self.Loaded_Cargo[unitname] = nil - self.Loaded_Cargo[unitname] = loaded - - self:_UpdateUnitCargoMass(Unit) - self:_RefreshDropCratesMenu(Group,Unit) - else - if IsHerc then - self:_SendMessage("Nothing loaded or not within airdrop parameters!", 10, false, Group) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group) + if not self.debug then return self end + end + local hoverunload = self:IsCorrectHover(Unit) + local IsHerc = self:IsFixedWing(Unit) + local IsHook = self:IsHook(Unit) + if IsHerc and (not IsHook) then + hoverunload = self:IsCorrectFlightParameters(Unit) + end + local grounded = not self:IsUnitInAir(Unit) + local unitname = Unit:GetName() + if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then + local loadedcargo = self.Loaded_Cargo[unitname] or {} + local cargotable = loadedcargo.Cargo + local droppedCount = {} + local neededMap = {} + for _,_cargo in pairs (cargotable) do + local cargo = _cargo + local type = cargo:GetType() + if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then + self:_GetCrates(Group, Unit, cargo, 1, true) + cargo:SetWasDropped(true) + cargo:SetHasMoved(true) + local cname = cargo:GetName() or "Unknown" + droppedCount[cname] = (droppedCount[cname] or 0) + 1 + if not neededMap[cname] then + neededMap[cname] = cargo:GetCratesNeeded() or 1 + end + end + end + for cname,count in pairs(droppedCount) do + local needed = neededMap[cname] or 1 + if needed > 1 then + local full = math.floor(count/needed) + local left = count % needed + if full > 0 and left == 0 then + self:_SendMessage(string.format("Dropped %d %s.",full,cname),10,false,Group) + elseif full > 0 and left > 0 then + self:_SendMessage(string.format("Dropped %d %s(s), with %d leftover crate(s).",full,cname,left),10,false,Group) + else + self:_SendMessage(string.format("Dropped %d/%d crate(s) of %s.",count,needed,cname),15,false,Group) + end + else + self:_SendMessage(string.format("Dropped %d %s(s).",count,cname),10,false,Group) + end + end + local loaded = {} + loaded.Troopsloaded = 0 + loaded.Cratesloaded = 0 + loaded.Cargo = {} + for _,_cargo in pairs (cargotable) do + local cargo = _cargo + local type = cargo:GetType() + local size = cargo:GetCratesNeeded() + if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then + table.insert(loaded.Cargo,_cargo) + loaded.Troopsloaded = loaded.Troopsloaded + size + end + if type == CTLD_CARGO.Enum.GCLOADABLE and not cargo:WasDropped() then + table.insert(loaded.Cargo,_cargo) + loaded.Cratesloaded = loaded.Cratesloaded + size + end + end + self.Loaded_Cargo[unitname] = nil + self.Loaded_Cargo[unitname] = loaded + + self:_UpdateUnitCargoMass(Unit) + self:_RefreshDropCratesMenu(Group,Unit) else - self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group) - end + if IsHerc then + self:_SendMessage("Nothing loaded or not within airdrop parameters!", 10, false, Group) + else + self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group) + end + end + return self end - return self -end --- (Internal) Function to build nearby crates. -- @param #CTLD self -- @param Wrapper.Group#GROUP Group -- @param Wrapper.Unit#UNIT Unit -- @param #boolean Engineering If true build is by an engineering team. -function CTLD:_BuildCrates(Group, Unit,Engineering) +-- @param #boolean MultiDrop If true and not engineering or FOB, vary position a bit. +function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop) self:T(self.lid .. " _BuildCrates") -- avoid users trying to build from flying Hercs if self:IsFixedWing(Unit) and self.enableFixedWing and not Engineering then @@ -3939,12 +3959,13 @@ function CTLD:_BuildCrates(Group, Unit,Engineering) if build.CanBuild then self:_CleanUpCrates(crates,build,number) if self.buildtime and self.buildtime > 0 then - local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate()) + local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate(),MultiDrop) buildtimer:Start(self.buildtime) self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group) self:__CratesBuildStarted(1,Group,Unit) + self:_RefreshDropTroopsMenu(Group,Unit) else - self:_BuildObjectFromCrates(Group,Unit,build) + self:_BuildObjectFromCrates(Group,Unit,build,false,nil,MultiDrop) end end end @@ -3983,13 +4004,14 @@ function CTLD:_PackCratesNearby(Group, Unit) _Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu - return self + return true end end end end end - return self + self:_SendMessage("Nothing to pack at this distance pilot!",10,false,Group) + return false end --- (Internal) Function to repair nearby vehicles / FOBs @@ -4082,7 +4104,8 @@ end -- @param #CTLD.Buildable Build -- @param #boolean Repair If true this is a repair and not a new build -- @param Core.Point#COORDINATE RepairLocation Location for repair (e.g. where the destroyed unit was) -function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation) +-- @param #boolean MultiDrop if true and not a repair, vary location a bit if not a FOB +function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,MultiDrop) self:T(self.lid .. " _BuildObjectFromCrates") -- Spawn-a-crate-content if Group and Group:IsAlive() or (RepairLocation and not Repair) then @@ -4099,7 +4122,7 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation) if type(temptable) == "string" then temptable = {temptable} end - local zone = nil + local zone = nil -- Core.Zone#ZONE_RADIUS if RepairLocation and not Repair then -- timed build zone = ZONE_RADIUS:New(string.format("Build zone-%d",math.random(1,10000)),RepairLocation:GetVec2(),100) @@ -4108,6 +4131,10 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation) end --local randomcoord = zone:GetRandomCoordinate(35):GetVec2() local randomcoord = Build.Coord or zone:GetRandomCoordinate(35):GetVec2() + if MultiDrop and (not Repair) and canmove then + -- coordinate may be the same, avoid + local randomcoord = zone:GetRandomCoordinate(35):GetVec2() + end if Repair then randomcoord = RepairLocation:GetVec2() end @@ -4199,310 +4226,458 @@ function CTLD:_CleanUpCrates(Crates,Build,Number) return self end +--- (Internal) Helper - Drop **all** loaded crates nearby and build them. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_DropAndBuild(Group,Unit) + if self.nobuildinloadzones then + if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then + self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group) + return self + end + end + self:_UnloadCrates(Group,Unit) + timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false,true) end,{},timer.getTime()+1) + end + + --- (Internal) Helper - Drop a **single** crate set and build it. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +-- @param number setIndex Index of the crate-set to drop + function CTLD:_DropSingleAndBuild(Group,Unit,setIndex) + if self.nobuildinloadzones then + if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then + self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group) + return self + end + end + self:_UnloadSingleCrateSet(Group,Unit,setIndex) + timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false) end,{},timer.getTime()+1) + end + +--- (Internal) Helper - Pack crates near the unit and load them. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_PackAndLoad(Group,Unit) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group) + return self + end + if not self:_PackCratesNearby(Group,Unit) then + return self + end + timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1) + return self + end + +--- (Internal) Helper - Pack crates near the unit and then remove them. +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_PackAndRemove(Group,Unit) + if not self:_PackCratesNearby(Group,Unit) then + return self + end + timer.scheduleFunction(function() self:_RemoveCratesNearby(Group,Unit) end,{},timer.getTime()+1) + return self +end + +--- (Internal) Helper - get and load in one step +-- @param Wrapper.Group#GROUP Group The calling group +-- @param Wrapper.Unit#UNIT Unit The calling unit +function CTLD:_GetAndLoad(Group,Unit,cargoObj) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group) + return self + end + self:_GetCrates(Group,Unit,cargoObj) + + timer.scheduleFunction(function() self:_LoadSingleCrateSet(Group,Unit,cargoObj.Name) end,{},timer.getTime()+1) +end + +-- @param Wrapper.Group#GROUP Group The player’s group that triggered the action +-- @param Wrapper.Unit#UNIT Unit The unit performing the pack-and-load +function CTLD:_GetAllAndLoad(Group,Unit) + if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group) + return self + end + + timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1) +end + --- (Internal) Housekeeping - Function to refresh F10 menus. -- @param #CTLD self -- @return #CTLD self function CTLD:_RefreshF10Menus() - self:T(self.lid .. " _RefreshF10Menus") - - -- 1) Gather all the pilot groups from our Set - local PlayerSet = self.PilotGroups - local PlayerTable = PlayerSet:GetSetObjects() - - -- 2) Rebuild the self.CtldUnits table - local _UnitList = {} - for _, groupObj in pairs(PlayerTable) do - local firstUnit = groupObj:GetFirstUnitAlive() - if firstUnit then - if firstUnit:IsPlayer() then - if firstUnit:IsHelicopter() or (self.enableFixedWing and self:IsFixedWing(firstUnit)) then - local _unit = firstUnit:GetName() - _UnitList[_unit] = _unit + self:T(self.lid .. " _RefreshF10Menus") + self.onestepmenu = self.onestepmenu or false -- hybrid toggle (default = false) + + -- 1) Gather all the pilot groups from our Set + local PlayerSet = self.PilotGroups + local PlayerTable = PlayerSet:GetSetObjects() + + -- 2) Rebuild the self.CtldUnits table + local _UnitList = {} + for _, groupObj in pairs(PlayerTable) do + local firstUnit = groupObj:GetFirstUnitAlive() + if firstUnit then + if firstUnit:IsPlayer() then + if firstUnit:IsHelicopter() or (self.enableFixedWing and self:IsFixedWing(firstUnit)) then + local _unit = firstUnit:GetName() + _UnitList[_unit] = _unit + end end end end - end - - -- 3) CA Units - if self.allowCATransport and self.CATransportSet then - for _,_clientobj in pairs(self.CATransportSet.Set) do - local client = _clientobj -- Wrapper.Client#CLIENT - if client:IsGround() then - local cname = client:GetName() - self:T(self.lid.."Adding: "..cname) - _UnitList[cname] = cname + + -- 3) CA Units + if self.allowCATransport and self.CATransportSet then + for _,_clientobj in pairs(self.CATransportSet.Set) do + local client = _clientobj -- Wrapper.Client#CLIENT + if client:IsGround() then + local cname = client:GetName() + self:T(self.lid.."Adding: "..cname) + _UnitList[cname] = cname + end end end + + self.CtldUnits = _UnitList + + -- subcats? + if self.usesubcats then + for _id,_cargo in pairs(self.Cargo_Crates) do + local entry = _cargo -- #CTLD_CARGO + if not self.subcats[entry.Subcategory] then + self.subcats[entry.Subcategory] = entry.Subcategory + end + end + for _id,_cargo in pairs(self.Cargo_Statics) do + local entry = _cargo -- #CTLD_CARGO + if not self.subcats[entry.Subcategory] then + self.subcats[entry.Subcategory] = entry.Subcategory + end + end + for _id,_cargo in pairs(self.Cargo_Troops) do + local entry = _cargo -- #CTLD_CARGO + if not self.subcatsTroop[entry.Subcategory] then + self.subcatsTroop[entry.Subcategory] = entry.Subcategory + end + end + end + + local menucount = 0 + local menus = {} + for _, _unitName in pairs(self.CtldUnits) do + if (not self.MenusDone[_unitName]) or (self.showstockinmenuitems == true) then + self:T(self.lid.."Menu not done yet for ".._unitName) + local _unit = UNIT:FindByName(_unitName) + if not _unit and self.allowCATransport then + _unit = CLIENT:FindByName(_unitName) + end + if _unit and _unit:IsAlive() then + local _group = _unit:GetGroup() + if _group then + self:T(self.lid.."Unit and Group exist") + local capabilities = self:_GetUnitCapabilities(_unit) + local cantroops = capabilities.troops + local cancrates = capabilities.crates + local unittype = _unit:GetTypeName() + local isHook = self:IsHook(_unit) + local nohookswitch = true + --local nohookswitch = not (isHook and self.enableChinookGCLoading) + -- Clear old topmenu if it existed + if _group.CTLDTopmenu then + _group.CTLDTopmenu:Remove() + _group.CTLDTopmenu = nil + end + local toptroops = nil + local topcrates = nil + local topmenu = MENU_GROUP:New(_group, "CTLD", nil) + _group.CTLDTopmenu = topmenu + + if cantroops then + local toptroops = MENU_GROUP:New(_group, "Manage Troops", topmenu) + local troopsmenu = MENU_GROUP:New(_group, "Load troops", toptroops) + _group.MyTopTroopsMenu = toptroops + + if self.usesubcats then + local subcatmenus = {} + for catName, _ in pairs(self.subcatsTroop) do + subcatmenus[catName] = MENU_GROUP:New(_group, catName, troopsmenu) + end + for _, cargoObj in pairs(self.Cargo_Troops) do + if not cargoObj.DontShowInMenu then + local stock = cargoObj:GetStock() + local menutext = cargoObj.Name + if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, menutext, subcatmenus[cargoObj.Subcategory], self._LoadTroops, self, _group, _unit, cargoObj) + end + end + else + for _, cargoObj in pairs(self.Cargo_Troops) do + if not cargoObj.DontShowInMenu then + local stock = cargoObj:GetStock() + local menutext = cargoObj.Name + if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj) + end + end + end + local dropTroopsMenu=MENU_GROUP:New(_group,"Drop Troops",toptroops):Refresh() + MENU_GROUP_COMMAND:New(_group,"Drop ALL troops",dropTroopsMenu,self._UnloadTroops,self,_group,_unit):Refresh() + MENU_GROUP_COMMAND:New(_group,"Extract troops",toptroops,self._ExtractTroops,self,_group,_unit):Refresh() + local uName=_unit:GetName() + local loadedData=self.Loaded_Cargo[uName] + if loadedData and loadedData.Cargo then + for i,cargoObj in ipairs(loadedData.Cargo) do + if cargoObj and (cargoObj:GetType()==CTLD_CARGO.Enum.TROOPS or cargoObj:GetType()==CTLD_CARGO.Enum.ENGINEERS) and not cargoObj:WasDropped() then + local name=cargoObj:GetName() or "Unknown" + local needed=cargoObj:GetCratesNeeded() or 1 + local cID=cargoObj:GetID() + local line=string.format("Drop: %s",name,needed,cID) + MENU_GROUP_COMMAND:New(_group,line,dropTroopsMenu,self._UnloadSingleTroopByID,self,_group,_unit,cID):Refresh() + end + end + end + end + if cancrates then + local topcrates = MENU_GROUP:New(_group, "Manage Crates", topmenu) + _group.MyTopCratesMenu = topcrates + + -- Build the “Get Crates” sub-menu items + local cratesmenu = MENU_GROUP:New(_group,"Get Crates",topcrates) + + if self.onestepmenu then + if self.usesubcats then + local subcatmenus = {} + for catName,_ in pairs(self.subcats) do + subcatmenus[catName] = MENU_GROUP:New(_group,catName,cratesmenu) + end + for _,cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + for _,cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + else + for _,cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + for _,cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) + MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end + end + end + else + if self.usesubcats then + local subcatmenus = {} + for catName, _ in pairs(self.subcats) do + subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case + end + for _, cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) + end + end + for _, cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) + end + end + else + for _, cargoObj in pairs(self.Cargo_Crates) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) + end + end + for _, cargoObj in pairs(self.Cargo_Statics) do + if not cargoObj.DontShowInMenu then + local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) + if cargoObj.Location then txt = txt.."[R]" end + local stock = cargoObj:GetStock() + if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end + MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) + end + end + end + end + + local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates) + _group.MyLoadCratesMenu=loadCratesMenu + MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit) + + local dropCratesMenu = MENU_GROUP:New(_group,"Drop Crates",topcrates) + topcrates.DropCratesMenu = dropCratesMenu + + if not self.nobuildmenu then + MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "Repair", topcrates, self._RepairCrates, self, _group, _unit):Refresh() + end + + local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates) + MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit) + + if self.onestepmenu then + local mPack=MENU_GROUP:New(_group,"Pack crates",topcrates) + MENU_GROUP_COMMAND:New(_group,"Pack and Load",mPack,self._PackAndLoad,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group,"Pack and Remove",mPack,self._PackAndRemove,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group,"Pack only",mPack,self._PackCratesNearby,self,_group,_unit) + MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) + else + MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) + end + + local uName = _unit:GetName() + local loadedData = self.Loaded_Cargo[uName] + if loadedData and loadedData.Cargo then + local cargoByName = {} + for _, cgo in pairs(loadedData.Cargo) do + if cgo and (not cgo:WasDropped()) then + local cname = cgo:GetName() + local cneeded = cgo:GetCratesNeeded() + cargoByName[cname] = cargoByName[cname] or { count=0, needed=cneeded } + cargoByName[cname].count = cargoByName[cname].count + 1 + end + end + for name, info in pairs(cargoByName) do + local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed) + MENU_GROUP_COMMAND:New(_group, line, dropCratesMenu, self._UnloadSingleCrateSet, self, _group, _unit, name) + end + end + end + + ----------------------------------------------------- + -- Misc sub‐menus + ----------------------------------------------------- + MENU_GROUP_COMMAND:New(_group, "List boarded cargo", topmenu, self._ListCargo, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "Inventory", topmenu, self._ListInventory, self, _group, _unit) + MENU_GROUP_COMMAND:New(_group, "List active zone beacons", topmenu, self._ListRadioBeacons, self, _group, _unit) + + local smoketopmenu = MENU_GROUP:New(_group, "Smokes, Flares, Beacons", topmenu) + MENU_GROUP_COMMAND:New(_group, "Smoke zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, false) + local smokeself = MENU_GROUP:New(_group, "Drop smoke now", smoketopmenu) + MENU_GROUP_COMMAND:New(_group, "Red smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Red) + MENU_GROUP_COMMAND:New(_group, "Blue smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Blue) + MENU_GROUP_COMMAND:New(_group, "Green smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Green) + MENU_GROUP_COMMAND:New(_group, "Orange smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Orange) + MENU_GROUP_COMMAND:New(_group, "White smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.White) + + MENU_GROUP_COMMAND:New(_group, "Flare zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, true) + MENU_GROUP_COMMAND:New(_group, "Fire flare now", smoketopmenu, self.SmokePositionNow, self, _unit, true) + MENU_GROUP_COMMAND:New(_group, "Drop beacon now", smoketopmenu, self.DropBeaconNow, self, _unit):Refresh() + + if self:IsFixedWing(_unit) then + MENU_GROUP_COMMAND:New(_group, "Show flight parameters", topmenu, self._ShowFlightParams, self, _group, _unit):Refresh() + else + MENU_GROUP_COMMAND:New(_group, "Show hover parameters", topmenu, self._ShowHoverParams, self, _group, _unit):Refresh() + end + + -- Mark we built the menu + self.MenusDone[_unitName] = true + self:_RefreshLoadCratesMenu(_group,_unit) + self:_RefreshDropCratesMenu(_group,_unit) + + end -- if _group + end -- if _unit + else + self:T(self.lid .. " Menus already done for this group!") + end + end -- for all pilot units + + return self end - self.CtldUnits = _UnitList - - -- subcats? - if self.usesubcats then - for _id,_cargo in pairs(self.Cargo_Crates) do - local entry = _cargo -- #CTLD_CARGO - if not self.subcats[entry.Subcategory] then - self.subcats[entry.Subcategory] = entry.Subcategory - end - end - for _id,_cargo in pairs(self.Cargo_Statics) do - local entry = _cargo -- #CTLD_CARGO - if not self.subcats[entry.Subcategory] then - self.subcats[entry.Subcategory] = entry.Subcategory - end - end - for _id,_cargo in pairs(self.Cargo_Troops) do - local entry = _cargo -- #CTLD_CARGO - if not self.subcatsTroop[entry.Subcategory] then - self.subcatsTroop[entry.Subcategory] = entry.Subcategory - end - end - end - - local menucount = 0 - local menus = {} - for _, _unitName in pairs(self.CtldUnits) do - if (not self.MenusDone[_unitName]) or (self.showstockinmenuitems == true) then - self:T(self.lid.."Menu not done yet for ".._unitName) - local _unit = UNIT:FindByName(_unitName) - if not _unit and self.allowCATransport then - _unit = CLIENT:FindByName(_unitName) - end - if _unit and _unit:IsAlive() then - local _group = _unit:GetGroup() - if _group then - self:T(self.lid.."Unit and Group exist") - local capabilities = self:_GetUnitCapabilities(_unit) - local cantroops = capabilities.troops - local cancrates = capabilities.crates - local unittype = _unit:GetTypeName() - local isHook = self:IsHook(_unit) - local nohookswitch = true - --local nohookswitch = not (isHook and self.enableChinookGCLoading) - -- Clear old topmenu if it existed - if _group.CTLDTopmenu then - _group.CTLDTopmenu:Remove() - _group.CTLDTopmenu = nil - end - local toptroops = nil - local topcrates = nil - local topmenu = MENU_GROUP:New(_group, "CTLD", nil) - _group.CTLDTopmenu = topmenu - - if cantroops then - local toptroops = MENU_GROUP:New(_group, "Manage Troops", topmenu) - local troopsmenu = MENU_GROUP:New(_group, "Load troops", toptroops) - _group.MyTopTroopsMenu = toptroops - - if self.usesubcats then - local subcatmenus = {} - for catName, _ in pairs(self.subcatsTroop) do - subcatmenus[catName] = MENU_GROUP:New(_group, catName, troopsmenu) - end - for _, cargoObj in pairs(self.Cargo_Troops) do - if not cargoObj.DontShowInMenu then - local stock = cargoObj:GetStock() - local menutext = cargoObj.Name - if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, menutext, subcatmenus[cargoObj.Subcategory], self._LoadTroops, self, _group, _unit, cargoObj) - end - end - else - for _, cargoObj in pairs(self.Cargo_Troops) do - if not cargoObj.DontShowInMenu then - local stock = cargoObj:GetStock() - local menutext = cargoObj.Name - if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj) - - end - end - end - local dropTroopsMenu=MENU_GROUP:New(_group,"Drop Troops",toptroops):Refresh() - MENU_GROUP_COMMAND:New(_group,"Drop ALL troops",dropTroopsMenu,self._UnloadTroops,self,_group,_unit):Refresh() - MENU_GROUP_COMMAND:New(_group,"Extract troops",toptroops,self._ExtractTroops,self,_group,_unit):Refresh() - local uName=_unit:GetName() - local loadedData=self.Loaded_Cargo[uName] - if loadedData and loadedData.Cargo then - for i,cargoObj in ipairs(loadedData.Cargo) do - if cargoObj and (cargoObj:GetType()==CTLD_CARGO.Enum.TROOPS or cargoObj:GetType()==CTLD_CARGO.Enum.ENGINEERS) and not cargoObj:WasDropped() then - local name=cargoObj:GetName() or "Unknown" - local needed=cargoObj:GetCratesNeeded() or 1 - local cID=cargoObj:GetID() - local line=string.format("Drop: %s",name,needed,cID) - MENU_GROUP_COMMAND:New(_group,line,dropTroopsMenu,self._UnloadSingleTroopByID,self,_group,_unit,cID):Refresh() - end - end - end - end - if cancrates then - local topcrates = MENU_GROUP:New(_group, "Manage Crates", topmenu) - _group.MyTopCratesMenu = topcrates - - -- Build the “Get Crates” sub-menu items - local cratesmenu = MENU_GROUP:New(_group, "Get Crates", topcrates) - if self.usesubcats then - local subcatmenus = {} - for catName, _ in pairs(self.subcats) do - subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) - end - for _, cargoObj in pairs(self.Cargo_Crates) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) - end - end - for _, cargoObj in pairs(self.Cargo_Statics) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, subcatmenus[cargoObj.Subcategory], self._GetCrates, self, _group, _unit, cargoObj) - end - end - else - for _, cargoObj in pairs(self.Cargo_Crates) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) - end - end - for _, cargoObj in pairs(self.Cargo_Statics) do - if not cargoObj.DontShowInMenu then - local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0) - if cargoObj.Location then txt = txt.."[R]" end - local stock = cargoObj:GetStock() - if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end - MENU_GROUP_COMMAND:New(_group, txt, cratesmenu, self._GetCrates, self, _group, _unit, cargoObj) - end - end - end - - local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates) - _group.MyLoadCratesMenu=loadCratesMenu - MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit) - MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit) - - local dropCratesMenu=MENU_GROUP:New(_group,"Drop Crates",topcrates) - topcrates.DropCratesMenu=dropCratesMenu - - if not self.nobuildmenu then - MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "Repair", topcrates, self._RepairCrates, self, _group, _unit):Refresh() - end - - local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates) - MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit) - - MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) - - local uName = _unit:GetName() - local loadedData = self.Loaded_Cargo[uName] - if loadedData and loadedData.Cargo then - local cargoByName = {} - for _, cgo in pairs(loadedData.Cargo) do - if cgo and (not cgo:WasDropped()) then - local cname = cgo:GetName() - local cneeded = cgo:GetCratesNeeded() - cargoByName[cname] = cargoByName[cname] or { count=0, needed=cneeded } - cargoByName[cname].count = cargoByName[cname].count + 1 - end - end - for name, info in pairs(cargoByName) do - local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed) - MENU_GROUP_COMMAND:New(_group, line, dropCratesMenu, self._UnloadSingleCrateSet, self, _group, _unit, name) - end - end - end - - - - ----------------------------------------------------- - -- Misc sub‐menus - ----------------------------------------------------- - MENU_GROUP_COMMAND:New(_group, "List boarded cargo", topmenu, self._ListCargo, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "Inventory", topmenu, self._ListInventory, self, _group, _unit) - MENU_GROUP_COMMAND:New(_group, "List active zone beacons", topmenu, self._ListRadioBeacons, self, _group, _unit) - - local smoketopmenu = MENU_GROUP:New(_group, "Smokes, Flares, Beacons", topmenu) - MENU_GROUP_COMMAND:New(_group, "Smoke zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, false) - local smokeself = MENU_GROUP:New(_group, "Drop smoke now", smoketopmenu) - MENU_GROUP_COMMAND:New(_group, "Red smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Red) - MENU_GROUP_COMMAND:New(_group, "Blue smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Blue) - MENU_GROUP_COMMAND:New(_group, "Green smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Green) - MENU_GROUP_COMMAND:New(_group, "Orange smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.Orange) - MENU_GROUP_COMMAND:New(_group, "White smoke", smokeself, self.SmokePositionNow, self, _unit, false, SMOKECOLOR.White) - - MENU_GROUP_COMMAND:New(_group, "Flare zones nearby", smoketopmenu, self.SmokeZoneNearBy, self, _unit, true) - MENU_GROUP_COMMAND:New(_group, "Fire flare now", smoketopmenu, self.SmokePositionNow, self, _unit, true) - MENU_GROUP_COMMAND:New(_group, "Drop beacon now", smoketopmenu, self.DropBeaconNow, self, _unit):Refresh() - - if self:IsFixedWing(_unit) then - MENU_GROUP_COMMAND:New(_group, "Show flight parameters", topmenu, self._ShowFlightParams, self, _group, _unit):Refresh() - else - MENU_GROUP_COMMAND:New(_group, "Show hover parameters", topmenu, self._ShowHoverParams, self, _group, _unit):Refresh() - end - - -- Mark we built the menu - self.MenusDone[_unitName] = true - self:_RefreshLoadCratesMenu(_group, _unit) - self:_RefreshDropCratesMenu(_group,_unit) - - end -- if _group - end -- if _unit - else - self:T(self.lid .. " Menus already done for this group!") - end - end -- for all pilot units - - return self -end - --- (Internal) Function to refresh the menu for load crates. Triggered from land/getcrate/pack and more -- @param #CTLD self -- @param Wrapper.Group#GROUP Group The calling group. -- @param Wrapper.Unit#UNIT Unit The calling unit. -- @return #CTLD self -function CTLD:_RefreshLoadCratesMenu(Group, Unit) - if not Group.MyLoadCratesMenu then return end - Group.MyLoadCratesMenu:RemoveSubMenus() - - local d = self.CrateDistance or 35 - local nearby, n = self:_FindCratesNearby(Group, Unit, d, true, true) - if n == 0 then - MENU_GROUP_COMMAND:New(Group, "No crates found! Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end) - return - end - MENU_GROUP_COMMAND:New(Group, "Load ALL", Group.MyLoadCratesMenu, self._LoadCratesNearby, self, Group, Unit) - local cargoByName = {} - for _, crate in pairs(nearby) do - local cName = crate:GetName() - cargoByName[cName] = cargoByName[cName] or {} - table.insert(cargoByName[cName], crate) - end - - for cName, cList in pairs(cargoByName) do - local needed = cList[1]:GetCratesNeeded() or 1 - local found = #cList - - local line - if found >= needed then - line = string.format("Load %s", cName) - else - MENU_GROUP_COMMAND:New(Group, "Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end) - line = string.format("Load %s (%d/%d)", cName, found, needed) +function CTLD:_RefreshLoadCratesMenu(Group,Unit) + if not Group.MyLoadCratesMenu then return end + Group.MyLoadCratesMenu:RemoveSubMenus() + + local d=self.CrateDistance or 35 + local nearby,n=self:_FindCratesNearby(Group,Unit,d,true,true) + if n==0 then + MENU_GROUP_COMMAND:New(Group,"No crates found! Rescan?",Group.MyLoadCratesMenu,function() self:_RefreshLoadCratesMenu(Group,Unit) end) + return + end + MENU_GROUP_COMMAND:New(Group,"Load ALL",Group.MyLoadCratesMenu,self._LoadCratesNearby,self,Group,Unit) + + local cargoByName={} + for _,crate in pairs(nearby) do + local name=crate:GetName() + cargoByName[name]=cargoByName[name] or{} + table.insert(cargoByName[name],crate) + end + + local lineIndex=1 + for cName,list in pairs(cargoByName) do + local needed=list[1]:GetCratesNeeded() or 1 + table.sort(list,function(a,b)return a:GetID()=needed then + label=string.format("%d. Load %s",lineIndex,cName) + i=i+needed + else + label=string.format("%d. Load %s (%d/%d)",lineIndex,cName,left,needed) + i=#list+1 + end + MENU_GROUP_COMMAND:New(Group,label,Group.MyLoadCratesMenu,self._LoadSingleCrateSet,self,Group,Unit,cName) + lineIndex=lineIndex+1 + end end - MENU_GROUP_COMMAND:New(Group, line, Group.MyLoadCratesMenu, self._LoadSingleCrateSet, self, Group, Unit, cName) end -end + --- -- Loads exactly `CratesNeeded` crates for one cargoName in range. @@ -4745,78 +4920,133 @@ end -- @param Wrapper.Unit#UNIT Unit The calling unit. -- @return #CTLD self function CTLD:_RefreshDropCratesMenu(Group, Unit) - if not Group.CTLDTopmenu then return end - local topCrates = Group.MyTopCratesMenu - if not topCrates then return end - if topCrates.DropCratesMenu then - topCrates.DropCratesMenu:RemoveSubMenus() - else - topCrates.DropCratesMenu = MENU_GROUP:New(Group, "Drop Crates", topCrates) - end - local dropCratesMenu = topCrates.DropCratesMenu - local loadedData = self.Loaded_Cargo[Unit:GetName()] - if not loadedData or not loadedData.Cargo then - MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) - return - end - - local cargoByName={} - local dropableCrates=0 - for _,cObj in ipairs(loadedData.Cargo) do - if cObj and not cObj:WasDropped() then - local cType=cObj:GetType() - if cType~=CTLD_CARGO.Enum.TROOPS and cType~=CTLD_CARGO.Enum.ENGINEERS and cType~=CTLD_CARGO.Enum.GCLOADABLE then - local name=cObj:GetName()or"Unknown" - cargoByName[name]=cargoByName[name]or{} - table.insert(cargoByName[name],cObj) - dropableCrates=dropableCrates+1 + if not Group.CTLDTopmenu then return end + local topCrates = Group.MyTopCratesMenu + if not topCrates then return end + if topCrates.DropCratesMenu then + topCrates.DropCratesMenu:RemoveSubMenus() + else + topCrates.DropCratesMenu = MENU_GROUP:New(Group, "Drop Crates", topCrates) + end + + local dropCratesMenu = topCrates.DropCratesMenu + local loadedData = self.Loaded_Cargo[Unit:GetName()] + if not loadedData or not loadedData.Cargo then + MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) + return + end + + local cargoByName={} + local dropableCrates=0 + for _,cObj in ipairs(loadedData.Cargo) do + if cObj and not cObj:WasDropped() then + local cType=cObj:GetType() + if cType~=CTLD_CARGO.Enum.TROOPS and cType~=CTLD_CARGO.Enum.ENGINEERS and cType~=CTLD_CARGO.Enum.GCLOADABLE then + local name=cObj:GetName()or"Unknown" + cargoByName[name]=cargoByName[name]or{} + table.insert(cargoByName[name],cObj) + dropableCrates=dropableCrates+1 + end + end + end + + if dropableCrates==0 then + MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) + return + end + + ---------------------------------------------------------------------- + -- DEFAULT (“classic”) versus ONE-STEP behaviour + ---------------------------------------------------------------------- + if not self.onestepmenu then + -------------------------------------------------------------------- + -- classic menu + -------------------------------------------------------------------- + MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit) + + self.CrateGroupList=self.CrateGroupList or{} + self.CrateGroupList[Unit:GetName()]={} + + local lineIndex=1 + for cName,list in pairs(cargoByName) do + local needed=list[1]:GetCratesNeeded() or 1 + table.sort(list,function(a,b)return a:GetID()=needed then + local chunk={} + for n=i,i+needed-1 do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s",lineIndex,cName) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=i+needed + else + local chunk={} + for n=i,#list do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s %d/%d",lineIndex,cName,left,needed) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=#list+1 + end + lineIndex=lineIndex+1 + end + end + + else + -------------------------------------------------------------------- + -- one-step (enhanced) menu + -------------------------------------------------------------------- + local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit) + MENU_GROUP_COMMAND:New(Group,"Drop only",mAll,self._UnloadCrates,self,Group,Unit) + + self.CrateGroupList=self.CrateGroupList or{} + self.CrateGroupList[Unit:GetName()]={} + + local lineIndex=1 + for cName,list in pairs(cargoByName) do + local needed=list[1]:GetCratesNeeded() or 1 + table.sort(list,function(a,b)return a:GetID()=needed then + local chunk={} + for n=i,i+needed-1 do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s",lineIndex,cName) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + local mSet=MENU_GROUP:New(Group,label,dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex) + MENU_GROUP_COMMAND:New(Group,"Drop only",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=i+needed + else + local chunk={} + for n=i,#list do + table.insert(chunk,list[n]) + end + local label=string.format("%d. %s %d/%d",lineIndex,cName,left,needed) + table.insert(self.CrateGroupList[Unit:GetName()],chunk) + local setIndex=#self.CrateGroupList[Unit:GetName()] + MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) + i=#list+1 + end + lineIndex=lineIndex+1 + end end end end - if dropableCrates==0 then - MENU_GROUP_COMMAND:New(Group,"No crates to drop!",dropCratesMenu,function() end) - return - end - - MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit) - self.CrateGroupList=self.CrateGroupList or{} - self.CrateGroupList[Unit:GetName()]={} - - local lineIndex=1 - for cName,list in pairs(cargoByName) do - local needed=list[1]:GetCratesNeeded() or 1 - table.sort(list,function(a,b)return a:GetID()=needed then - local chunk={} - for n=i,i+needed-1 do - table.insert(chunk,list[n]) - end - local label=string.format("%d. %s",lineIndex,cName) - table.insert(self.CrateGroupList[Unit:GetName()],chunk) - local setIndex=#self.CrateGroupList[Unit:GetName()] - MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) - i=i+needed - else - local chunk={} - for n=i,#list do - table.insert(chunk,list[n]) - end - local label=string.format("%d. %s %d/%d",lineIndex,cName,left,needed) - table.insert(self.CrateGroupList[Unit:GetName()],chunk) - local setIndex=#self.CrateGroupList[Unit:GetName()] - MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) - i=#list+1 - end - lineIndex=lineIndex+1 - end - end -end - --- (Internal) Function to unload a single Troop group by ID. -- @param #CTLD self -- @param Wrapper.Group#GROUP Group The calling group. @@ -8167,4 +8397,4 @@ end ------------------------------------------------------------------- -- End Ops.CTLD.lua -------------------------------------------------------------------- +------------------------------------------------------------------- \ No newline at end of file From 89c3f7310b051746e175aa24e404d95f90e0979b Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Sat, 3 May 2025 19:22:59 +0200 Subject: [PATCH 19/50] Update CTLD.lua Changed the naming from Get only to Get and the order is Get, Get and load Instead of Get and load, and Get only. Changed the order on Pack and load, Pack and remove, pack only to Pack, Pack and load, Pack and remove. Same goes for Drop and build, Drop only to Drop, Drop and build. It purely subjective what one would like, so I leave it up to you. If you like it this way or the first version, you decide, then disregard this change. --- Moose Development/Moose/Ops/CTLD.lua | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 405ca9a07..487230947 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -866,7 +866,7 @@ do -- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook -- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook -- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew. --- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack only. it will be a 1 step solution. +-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution. -- -- ## 2.1 CH-47 Chinook support -- @@ -4461,8 +4461,8 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) end end for _,cargoObj in pairs(self.Cargo_Statics) do @@ -4472,8 +4472,8 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory]) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) end end else @@ -4484,8 +4484,8 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) end end for _,cargoObj in pairs(self.Cargo_Statics) do @@ -4495,8 +4495,9 @@ function CTLD:_RefreshF10Menus() local stock = cargoObj:GetStock() if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end local mSet = MENU_GROUP:New(_group,txt,cratesmenu) + MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj) MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj) - MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj) + end end end @@ -4564,9 +4565,9 @@ function CTLD:_RefreshF10Menus() if self.onestepmenu then local mPack=MENU_GROUP:New(_group,"Pack crates",topcrates) + MENU_GROUP_COMMAND:New(_group,"Pack",mPack,self._PackCratesNearby,self,_group,_unit) MENU_GROUP_COMMAND:New(_group,"Pack and Load",mPack,self._PackAndLoad,self,_group,_unit) MENU_GROUP_COMMAND:New(_group,"Pack and Remove",mPack,self._PackAndRemove,self,_group,_unit) - MENU_GROUP_COMMAND:New(_group,"Pack only",mPack,self._PackCratesNearby,self,_group,_unit) MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) else MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit) @@ -5005,8 +5006,8 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit) -- one-step (enhanced) menu -------------------------------------------------------------------- local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop",mAll,self._UnloadCrates,self,Group,Unit) MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit) - MENU_GROUP_COMMAND:New(Group,"Drop only",mAll,self._UnloadCrates,self,Group,Unit) self.CrateGroupList=self.CrateGroupList or{} self.CrateGroupList[Unit:GetName()]={} @@ -5027,8 +5028,8 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit) table.insert(self.CrateGroupList[Unit:GetName()],chunk) local setIndex=#self.CrateGroupList[Unit:GetName()] local mSet=MENU_GROUP:New(Group,label,dropCratesMenu) + MENU_GROUP_COMMAND:New(Group,"Drop",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex) - MENU_GROUP_COMMAND:New(Group,"Drop only",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex) i=i+needed else local chunk={} @@ -5094,7 +5095,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID) return self end - -- Drop ONLY the FIRST cargo in that chunk + -- Drop the FIRST cargo in that chunk local foundCargo = chunk[1] if not foundCargo then self:_SendMessage(string.format("No troop cargo at chunk %d!", chunkID), 10, false, Group) @@ -8397,4 +8398,4 @@ end ------------------------------------------------------------------- -- End Ops.CTLD.lua -------------------------------------------------------------------- \ No newline at end of file +------------------------------------------------------------------- From b6074a4795fe0776b111a49a2c5b61885308c683 Mon Sep 17 00:00:00 2001 From: leka1986 Date: Sun, 4 May 2025 10:38:44 +0200 Subject: [PATCH 20/50] VS Code pointed out some errors, like duplicated values in tables. This is first time I do changes through VS Code, Hope for the best --- Moose Development/Debugger/debugger.lua | 2 +- Moose Development/Moose/AI/AI_Formation.lua | 2 -- Moose Development/Moose/Actions/Act_Account.lua | 2 +- Moose Development/Moose/DCS.lua | 2 +- Moose Development/Moose/Functional/Fox.lua | 1 - Moose Development/Moose/Tasking/Task_CARGO.lua | 2 +- 6 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Moose Development/Debugger/debugger.lua b/Moose Development/Debugger/debugger.lua index a5f606f74..c8150ad13 100644 --- a/Moose Development/Debugger/debugger.lua +++ b/Moose Development/Debugger/debugger.lua @@ -1953,7 +1953,7 @@ local function refct_from_id(id) -- refct = refct_from_id(CTypeID) unsigned = refct.unsigned, size = bit.band(bit.rshift(ctype.info, 16), 127), } - refct.bool, refct.const, refct.volatile, refct.unsigned = nil + refct.bool, refct.const, refct.volatile, refct.unsigned = nil, nil, nil, nil end if CT[4] then -- Merge sibling attributes onto this type. diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index e42bd3a8f..4d5257eb1 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -158,7 +158,6 @@ AI_FORMATION.__Enum.Mode = { -- @field #number GroundRadar -- @field #number Ground AI_FORMATION.__Enum.ReportType = { - Airborne = "*", Airborne = "A", GroundRadar = "R", Ground = "G", @@ -1222,7 +1221,6 @@ function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2) local CVI = { x = CV2.x + CS * 10 * math.sin(Ca), y = GH2.y + Inclination, -- + FollowFormation.y, - y = GH2.y, z = CV2.z + CS * 10 * math.cos(Ca), } diff --git a/Moose Development/Moose/Actions/Act_Account.lua b/Moose Development/Moose/Actions/Act_Account.lua index 5b809af44..04b59fa9f 100644 --- a/Moose Development/Moose/Actions/Act_Account.lua +++ b/Moose Development/Moose/Actions/Act_Account.lua @@ -133,7 +133,7 @@ do -- ACT_ACCOUNT -- @param #string Event -- @param #string From -- @param #string To - function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event ) + function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To ) self:__NoMore( 1 ) end diff --git a/Moose Development/Moose/DCS.lua b/Moose Development/Moose/DCS.lua index 8e01b8a73..ca7ec0a95 100644 --- a/Moose Development/Moose/DCS.lua +++ b/Moose Development/Moose/DCS.lua @@ -198,7 +198,7 @@ end -- env do -- radio - ---@type radio + --@type radio -- @field #radio.modulation modulation --- diff --git a/Moose Development/Moose/Functional/Fox.lua b/Moose Development/Moose/Functional/Fox.lua index 38d8eb585..9496f272d 100644 --- a/Moose Development/Moose/Functional/Fox.lua +++ b/Moose Development/Moose/Functional/Fox.lua @@ -141,7 +141,6 @@ FOX = { explosiondist = 200, explosiondist2 = 500, bigmissilemass = 50, - destroy = nil, dt50 = 5, dt10 = 1, dt05 = 0.5, diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index e2839d64e..76a3b9e9a 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -1176,7 +1176,7 @@ do -- TASK_CARGO end - ---@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green + --@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green function TASK_CARGO:SetSmokeColor(SmokeColor) -- Makes sure Coloe is set if SmokeColor == nil then From 0468bacc0bc7820b08e14b5e421e384f24e9c7e6 Mon Sep 17 00:00:00 2001 From: leka1986 Date: Sun, 11 May 2025 21:15:31 +0200 Subject: [PATCH 21/50] Fix Line 77390: attempt to index local 'zonecoord' (a nil value) --- Moose Development/Moose/Ops/CTLD.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 487230947..4da45c663 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -5981,6 +5981,7 @@ function CTLD:SmokeZoneNearBy(Unit, Flare) end end local zonecoord = zone:GetCoordinate() + if zonecoord then local active = CZone.active local color = CZone.color local distance = self:_GetDistance(zonecoord,unitcoord) @@ -5997,6 +5998,7 @@ function CTLD:SmokeZoneNearBy(Unit, Flare) self:_SendMessage(string.format("Roger, %s zone %s!",txt, zonename), 10, false, Group) smoked = true end + end end end if not smoked then From 804004198bd4413b5106d5bd44dc5a3a374c2fc8 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 12 May 2025 17:49:25 +0200 Subject: [PATCH 22/50] #MANTIS - Update docu --- Moose Development/Moose/Functional/Mantis.lua | 41 ++++++------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 9a412d768..b815ab352 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -74,10 +74,9 @@ -- -- * Moose derived Modular, Automatic and Network capable Targeting and Interception System. -- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy. --- * **Automatic mode** (default since 0.8) will set-up your SAM site network automatically for you --- * **Classic mode** behaves like before --- * Leverage evasiveness from SEAD, leverage attack range setting --- * Automatic setup of SHORAD based on groups of the class "short-range" +-- * **Automatic mode** (default) will set-up your SAM site network automatically for you. +-- * Leverage evasiveness from SEAD, leverage attack range setting. +-- * Automatic setup of SHORAD based on groups of the class "short-range". -- -- # 0. Base considerations and naming conventions -- @@ -136,7 +135,8 @@ -- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above. -- Set up your EWR system in the mission editor. Name the groups using a systematic approach like above. Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc. -- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself. --- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one** group per SAM location. SA-15 TOR systems offer a good missile defense. +-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one unit ** per group (multiple groups) for the SAM location. +-- Else, evasive manoevers might club up all defenders in one place. Red SA-15 TOR systems offer a good missile defense. -- -- [optional] Set up your HQ. Can be any group, e.g. a command vehicle. -- @@ -188,7 +188,7 @@ -- -- ## 2.1 Auto mode features -- --- ### 2.1.1 You can now add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones: +-- ### 2.1.1 You can add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones: -- -- -- Parameters are tables of Core.Zone#ZONE objects! -- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when @@ -205,9 +205,6 @@ -- ### 2.1.3 SHORAD/Point defense will automatically be added from SAM sites of type "point" or if the range is less than 5km or if the type is AAA. -- -- ### 2.1.4 Advanced features --- --- -- Option to switch off auto mode **before** you start MANTIS (not recommended) --- mybluemantis.automode = false -- -- -- Option to set the scale of the activation range, i.e. don't activate at the fringes of max range, defaults below. -- -- also see engagerange below. @@ -220,6 +217,12 @@ -- -- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire. -- mybluemantis.checkforfriendlies = true +-- +-- ### 2.1.6 Shoot & Scoot +-- +-- -- Option to make the (driveable) SHORAD units drive around and shuffle positions +-- -- We use a SET_ZONE for that, number of zones to consider defaults to three, Random is true for random coordinates and Formation is e.g. "Vee". +-- mybluemantis:AddScootZones(ZoneSet, Number, Random, Formation) -- -- # 3. Default settings [both modes unless stated otherwise] -- @@ -242,26 +245,8 @@ -- E.g. mymantis:SetAdvancedMode( true, 90 ) -- -- Use this option if you want to make use of or allow advanced SEAD tactics. --- --- # 5. Integrate SHORAD [classic mode, not necessary in automode, not recommended for manual setup] --- --- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs manually. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in --- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so: --- --- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart() --- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue") --- -- now set up MANTIS --- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs") --- mymantis:AddShorad(myshorad,720) --- mymantis:Start() -- --- If you systematically name your SHORAD groups starting with "Blue SHORAD" you'll need exactly **one** SHORAD instance to manage all SHORAD groups. --- --- (Optionally) you can remove the link later on with --- --- mymantis:RemoveShorad() --- --- # 6. Integrated SEAD +-- # 5. Integrated SEAD -- -- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up! -- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM From 3b50fee5a0b5dffa0f1d39b0e3f805696a8ba010 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 12 May 2025 17:50:37 +0200 Subject: [PATCH 23/50] #CTLD - extract troops, check for groupname in task properties of PLAYERTASKs, so the right people rescue the correct group --- Moose Development/Moose/Ops/CTLD.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 4da45c663..5b2ecc4ef 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -7217,13 +7217,17 @@ end -- right subtype? if Event == subtype and not task:IsDone() then local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case .... - --self:T2({Name=Groupname,Property=task:GetProperty("ExtractName")}) - local okaygroup = string.find(Groupname,task:GetProperty("ExtractName"),1,true) - if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and okaygroup then - if task.Clients:HasUniqueID(playername) then - -- success - task:__Success(-1) + self:T2({Name=Groupname,Property=task:GetProperty("ExtractName")}) + if task:GetProperty("ExtractName") then + local okaygroup = string.find(Groupname,task:GetProperty("ExtractName"),1,true) + if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and okaygroup then + if task.Clients:HasUniqueID(playername) then + -- success + task:__Success(-1) + end end + else + self:T({Text="'ExtractName' Property not set",Name=Groupname,Property=task.Type}) end end end From 20406e40ca67d7f153340f4267c3bb22b8559402 Mon Sep 17 00:00:00 2001 From: shaji Date: Thu, 15 May 2025 01:17:55 +0200 Subject: [PATCH 24/50] [FIXED] Kola Airbase name "Alakourtti" to "Alakurtti" --- Moose Development/Moose/Wrapper/Airbase.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 0e3e8d9e3..c7d576e38 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -790,7 +790,7 @@ AIRBASE.Sinai = { -- * AIRBASE.Kola.Vidsel -- * AIRBASE.Kola.Vuojarvi -- * AIRBASE.Kola.Andoya --- * AIRBASE.Kola.Alakourtti +-- * AIRBASE.Kola.Alakurtti -- * AIRBASE.Kola.Kittila -- * AIRBASE.Kola.Bardufoss -- * AIRBASE.Kola.Alta @@ -820,7 +820,7 @@ AIRBASE.Kola = { ["Vidsel"] = "Vidsel", ["Vuojarvi"] = "Vuojarvi", ["Andoya"] = "Andoya", - ["Alakourtti"] = "Alakourtti", + ["Alakurtti"] = "Alakurtti", ["Kittila"] = "Kittila", ["Bardufoss"] = "Bardufoss", ["Alta"] = "Alta", From db869bcb6d08134392c235166f007c1df71c697d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 08:51:26 +0200 Subject: [PATCH 25/50] #MANTIS - Make DLINK caching (DEV version) configureable --- Moose Development/Moose/Functional/Mantis.lua | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index b815ab352..81f2c3d63 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -22,7 +22,7 @@ -- @module Functional.Mantis -- @image Functional.Mantis.jpg -- --- Last Update: Apr 2025 +-- Last Update: May 2025 ------------------------------------------------------------------------- --- **MANTIS** class, extends Core.Base#BASE @@ -62,7 +62,8 @@ -- @field #table FilterZones Table of Core.Zone#ZONE Zones Consider SAM groups in this zone(s) only for this MANTIS instance, must be handed as #table of Zone objects. -- @field #boolean SmokeDecoy If true, smoke short range SAM units as decoy if a plane is in firing range. -- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White --- @field #number checkcounter Counter for SAM Table refreshes +-- @field #number checkcounter Counter for SAM Table refreshes. +-- @field #number DLinkCacheTime Seconds after which cached contacts in DLink will decay. -- @extends Core.Base#BASE @@ -321,6 +322,7 @@ MANTIS = { SmokeDecoy = false, SmokeDecoyColor = SMOKECOLOR.White, checkcounter = 1, + DLinkCacheTime = 120, } --- Advanced state enumerator @@ -612,7 +614,8 @@ do self.advAwacs = false end - + self:SetDLinkCacheTime() + -- Set the string id for output to DCS.log file. self.lid=string.format("MANTIS %s | ", self.name) @@ -676,7 +679,7 @@ do -- TODO Version -- @field #string version - self.version="0.9.28" + self.version="0.9.29" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -1026,6 +1029,15 @@ do end return self end + + --- Function to set how long INTEL DLINK remembers contacts. + -- @param #MANTIS self + -- @param #number seconds Remember this many seconds + -- @return #MANTIS self + function MANTIS:SetDLinkCacheTime(seconds) + self.DLinkCacheTime = math.abs(seconds or 120) + return self + end --- Function to set the detection interval -- @param #MANTIS self @@ -1418,7 +1430,9 @@ do --IntelTwo:SetClusterRadius(5000) IntelTwo:Start() - local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,300) + local CacheTime = self.DLinkCacheTime or 120 + local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,CacheTime) + IntelDlink:__Start(1) self:SetUsingDLink(IntelDlink) From f8947aab9c4956d738d87511452f2b346aa564da Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 08:51:44 +0200 Subject: [PATCH 26/50] #MANTIS - Make DLINK caching (DEV version) configureable --- Moose Development/Moose/Ops/Intelligence.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index f9996cf91..a893557b3 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -2324,7 +2324,7 @@ INTEL_DLINK = { verbose = 0, lid = nil, alias = nil, - cachetime = 300, + cachetime = 120, interval = 20, contacts = {}, clusters = {}, @@ -2333,7 +2333,7 @@ INTEL_DLINK = { --- Version string -- @field #string version -INTEL_DLINK.version = "0.0.1" +INTEL_DLINK.version = "0.0.2" --- Function to instantiate a new object -- @param #INTEL_DLINK self @@ -2385,7 +2385,7 @@ function INTEL_DLINK:New(Intels, Alias, Interval, Cachetime) end -- Cache time - self.cachetime = Cachetime or 300 + self:SetDLinkCacheTime(Cachetime or 120) -- Interval self.interval = Interval or 20 @@ -2477,6 +2477,16 @@ function INTEL_DLINK:onafterStart(From, Event, To) return self end + --- Function to set how long INTEL DLINK remembers contacts. + -- @param #INTEL_DLINK self + -- @param #number seconds Remember this many seconds. Defaults to 180. + -- @return #INTEL_DLINK self + function INTEL_DLINK:SetDLinkCacheTime(seconds) + self.cachetime = math.abs(seconds or 120) + self:I(self.lid.."Caching for "..self.cachetime.." seconds.") + return self + end + --- Function to collect data from the various #INTEL -- @param #INTEL_DLINK self -- @param #string From The From state From ebb94c07b34962cbe8cc00be3ff4929ef42ce9a6 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 10:05:11 +0200 Subject: [PATCH 27/50] Small fix --- Moose Development/Moose/Ops/Intelligence.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Intelligence.lua b/Moose Development/Moose/Ops/Intelligence.lua index a893557b3..f582f0675 100644 --- a/Moose Development/Moose/Ops/Intelligence.lua +++ b/Moose Development/Moose/Ops/Intelligence.lua @@ -2384,15 +2384,15 @@ function INTEL_DLINK:New(Intels, Alias, Interval, Cachetime) self.alias="SPECTRE" end - -- Cache time - self:SetDLinkCacheTime(Cachetime or 120) - -- Interval self.interval = Interval or 20 -- Set some string id for output to DCS.log file. self.lid=string.format("INTEL_DLINK %s | ", self.alias) + -- Cache time + self:SetDLinkCacheTime(Cachetime or 120) + -- Start State. self:SetStartState("Stopped") From d7defe6f7fa5b9732ae3c37575c7f33b1d4f9a05 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 11:42:05 +0200 Subject: [PATCH 28/50] xx --- Moose Development/Moose/Functional/Mantis.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 81f2c3d63..989b400e0 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -133,8 +133,7 @@ -- -- # 0.1 Set-up in the mission editor -- --- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above. --- Set up your EWR system in the mission editor. Name the groups using a systematic approach like above. Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc. +-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc. -- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself. -- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one unit ** per group (multiple groups) for the SAM location. -- Else, evasive manoevers might club up all defenders in one place. Red SA-15 TOR systems offer a good missile defense. @@ -1032,10 +1031,11 @@ do --- Function to set how long INTEL DLINK remembers contacts. -- @param #MANTIS self - -- @param #number seconds Remember this many seconds + -- @param #number seconds Remember this many seconds, at least 5 seconds. -- @return #MANTIS self function MANTIS:SetDLinkCacheTime(seconds) self.DLinkCacheTime = math.abs(seconds or 120) + if self.DLinkCacheTime < 5 then self.DLinkCacheTime = 5 end return self end From 1bfb4fc4e1272fbb84329097dece8fb73dd0260c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 11:42:27 +0200 Subject: [PATCH 29/50] Small fix --- Moose Development/Moose/Ops/PlayerTask.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 8c6361a48..ce95f00a4 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -556,6 +556,7 @@ end -- @param #PLAYERTASK self -- @param #SET_BASE CaptureSquadGroupNamePrefix The prefix of the group name that needs to capture the zone. -- @param #number Coalition The coalition that needs to capture the zone. +-- @param #boolean CheckClientInZone If true, a CLIENT assigned to this task also needs to be in the zone for the task to be successful. -- @return #PLAYERTASK self -- @usage -- -- We can use either STATIC, SET_STATIC, SCENERY or SET_SCENERY as target objects. @@ -570,20 +571,20 @@ end -- -- -- We set CaptureSquadGroupNamePrefix the group name prefix as set in the ME or the spawn of the group that need to be present at the OpsZone like a capture squad, -- -- and set the capturing Coalition in order to trigger a successful task. --- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE) +-- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE, false) -- -- playerTaskManager:AddPlayerTaskToQueue(mytask) -function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition) +function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone) local task = self task:AddConditionSuccess( function(target) if target:IsInstanceOf("OPSZONE") then - return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, true) + return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true) elseif target:IsInstanceOf("SET_OPSZONE") then local successes = 0 local isClientInZone = false target:ForEachZone(function(opszone) - if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition) then + if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true) then successes = successes + 1 end From 4bab2ee1deb41274a143a17253b56b88f2a59098 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 13:19:42 +0200 Subject: [PATCH 30/50] Add deprecated banner --- Moose Development/Moose/AI/AI_A2A_Cap.lua | 4 +++- Moose Development/Moose/AI/AI_A2A_Dispatcher.lua | 4 +++- Moose Development/Moose/AI/AI_A2A_Gci.lua | 2 ++ Moose Development/Moose/AI/AI_A2A_Patrol.lua | 2 ++ Moose Development/Moose/AI/AI_A2G_BAI.lua | 4 +++- Moose Development/Moose/AI/AI_A2G_CAS.lua | 2 ++ Moose Development/Moose/AI/AI_A2G_Dispatcher.lua | 2 ++ Moose Development/Moose/AI/AI_A2G_SEAD.lua | 2 ++ Moose Development/Moose/AI/AI_Air.lua | 1 + Moose Development/Moose/AI/AI_Air_Dispatcher.lua | 2 ++ Moose Development/Moose/AI/AI_Air_Engage.lua | 4 +++- Moose Development/Moose/AI/AI_Air_Patrol.lua | 2 ++ Moose Development/Moose/AI/AI_Air_Squadron.lua | 4 +++- Moose Development/Moose/AI/AI_BAI.lua | 2 ++ Moose Development/Moose/AI/AI_Balancer.lua | 5 +++-- Moose Development/Moose/AI/AI_CAP.lua | 2 ++ Moose Development/Moose/AI/AI_CAS.lua | 3 +++ Moose Development/Moose/AI/AI_Cargo.lua | 4 +++- Moose Development/Moose/AI/AI_Cargo_APC.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Airplane.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua | 2 ++ .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 2 ++ .../Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Helicopter.lua | 2 ++ Moose Development/Moose/AI/AI_Cargo_Ship.lua | 2 ++ Moose Development/Moose/AI/AI_Escort.lua | 2 ++ Moose Development/Moose/AI/AI_Escort_Dispatcher.lua | 2 ++ .../Moose/AI/AI_Escort_Dispatcher_Request.lua | 2 ++ Moose Development/Moose/AI/AI_Escort_Request.lua | 2 ++ Moose Development/Moose/AI/AI_Formation.lua | 2 ++ Moose Development/Moose/AI/AI_Patrol.lua | 2 ++ Moose Development/Moose/Actions/Act_Account.lua | 8 +++++--- Moose Development/Moose/Actions/Act_Assign.lua | 2 ++ Moose Development/Moose/Actions/Act_Assist.lua | 1 + Moose Development/Moose/Actions/Act_Route.lua | 2 ++ Moose Development/Moose/Cargo/Cargo.lua | 2 ++ Moose Development/Moose/Cargo/CargoCrate.lua | 3 +++ Moose Development/Moose/Cargo/CargoGroup.lua | 2 ++ Moose Development/Moose/Cargo/CargoSlingload.lua | 2 ++ Moose Development/Moose/Cargo/CargoUnit.lua | 2 ++ Moose Development/Moose/Functional/MissileTrainer.lua | 2 ++ Moose Development/Moose/Functional/ZoneGoalCargo.lua | 2 ++ Moose Development/Moose/Tasking/CommandCenter.lua | 2 ++ Moose Development/Moose/Tasking/DetectionManager.lua | 2 ++ Moose Development/Moose/Tasking/Mission.lua | 2 ++ Moose Development/Moose/Tasking/Task.lua | 2 ++ Moose Development/Moose/Tasking/TaskInfo.lua | 2 ++ Moose Development/Moose/Tasking/Task_A2A.lua | 3 +++ Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_A2G.lua | 3 +++ Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_CARGO.lua | 2 ++ .../Moose/Tasking/Task_Capture_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_Capture_Zone.lua | 2 ++ Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua | 2 ++ Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua | 2 ++ Moose Development/Moose/Tasking/Task_Cargo_Transport.lua | 2 ++ Moose Development/Moose/Tasking/Task_Manager.lua | 2 ++ 60 files changed, 132 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 0c8aff8fa..693895d6d 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -17,7 +17,9 @@ --- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. --- +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- -- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index bbfaa868b..8e8e3df05 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -32,7 +32,9 @@ -- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx) -- -- === --- +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # QUICK START GUIDE -- -- There are basically two classes available to model an A2A defense system. diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua index 626e36d60..807fa9b78 100644 --- a/Moose Development/Moose/AI/AI_A2A_Gci.lua +++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua @@ -19,6 +19,8 @@ --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event. -- -- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua index 1e66eb167..d858fb9e2 100644 --- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua +++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua @@ -15,6 +15,8 @@ --- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- -- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_A2G_BAI.lua b/Moose Development/Moose/AI/AI_A2G_BAI.lua index 28acea07f..729dbf5c2 100644 --- a/Moose Development/Moose/AI/AI_A2G_BAI.lua +++ b/Moose Development/Moose/AI/AI_A2G_BAI.lua @@ -16,7 +16,9 @@ -- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. --- +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # Developer Note -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE diff --git a/Moose Development/Moose/AI/AI_A2G_CAS.lua b/Moose Development/Moose/AI/AI_A2G_CAS.lua index 7bae80ea3..830eb8b66 100644 --- a/Moose Development/Moose/AI/AI_A2G_CAS.lua +++ b/Moose Development/Moose/AI/AI_A2G_CAS.lua @@ -19,6 +19,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua index 0396e4e9f..5aff7ad4f 100644 --- a/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2G_Dispatcher.lua @@ -36,6 +36,8 @@ -- -- # QUICK START GUIDE -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The following class is available to model an A2G defense system. -- -- AI_A2G_DISPATCHER is the main A2G defense class that models the A2G defense system. diff --git a/Moose Development/Moose/AI/AI_A2G_SEAD.lua b/Moose Development/Moose/AI/AI_A2G_SEAD.lua index 42662862c..bf876db35 100644 --- a/Moose Development/Moose/AI/AI_A2G_SEAD.lua +++ b/Moose Development/Moose/AI/AI_A2G_SEAD.lua @@ -20,6 +20,8 @@ --- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event. -- -- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. diff --git a/Moose Development/Moose/AI/AI_Air.lua b/Moose Development/Moose/AI/AI_Air.lua index d3d11cf16..1b0bf8cac 100644 --- a/Moose Development/Moose/AI/AI_Air.lua +++ b/Moose Development/Moose/AI/AI_Air.lua @@ -15,6 +15,7 @@ --- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) -- -- # 1) AI_AIR constructor -- diff --git a/Moose Development/Moose/AI/AI_Air_Dispatcher.lua b/Moose Development/Moose/AI/AI_Air_Dispatcher.lua index 9e5939aa0..ad309f0c2 100644 --- a/Moose Development/Moose/AI/AI_Air_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Air_Dispatcher.lua @@ -36,6 +36,8 @@ -- -- # QUICK START GUIDE -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The following class is available to model an AIR defense system. -- -- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system. diff --git a/Moose Development/Moose/AI/AI_Air_Engage.lua b/Moose Development/Moose/AI/AI_Air_Engage.lua index ff3327421..772f10b2e 100644 --- a/Moose Development/Moose/AI/AI_Air_Engage.lua +++ b/Moose Development/Moose/AI/AI_Air_Engage.lua @@ -13,12 +13,14 @@ --- @type AI_AIR_ENGAGE +--- @type AI_AIR_ENGAGE -- @extends AI.AI_AIR#AI_AIR --- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event. -- -- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits. diff --git a/Moose Development/Moose/AI/AI_Air_Patrol.lua b/Moose Development/Moose/AI/AI_Air_Patrol.lua index 5b0abe72e..3e57476c5 100644 --- a/Moose Development/Moose/AI/AI_Air_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Air_Patrol.lua @@ -15,6 +15,8 @@ --- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- -- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_Air_Squadron.lua b/Moose Development/Moose/AI/AI_Air_Squadron.lua index 6651a92a5..7356c1baa 100644 --- a/Moose Development/Moose/AI/AI_Air_Squadron.lua +++ b/Moose Development/Moose/AI/AI_Air_Squadron.lua @@ -13,7 +13,7 @@ --- @type AI_AIR_SQUADRON +--- @type AI_AIR_SQUADRON -- @extends Core.Base#BASE @@ -21,6 +21,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/AI/AI_BAI.lua b/Moose Development/Moose/AI/AI_BAI.lua index 6b2a1dfe3..3037feb18 100644 --- a/Moose Development/Moose/AI/AI_BAI.lua +++ b/Moose Development/Moose/AI/AI_BAI.lua @@ -38,6 +38,8 @@ --- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_BAI\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_Balancer.lua b/Moose Development/Moose/AI/AI_Balancer.lua index 34afc35d0..b3c7fe1d1 100644 --- a/Moose Development/Moose/AI/AI_Balancer.lua +++ b/Moose Development/Moose/AI/AI_Balancer.lua @@ -33,8 +33,9 @@ -- @field Wrapper.Group#GROUP Test -- @extends Core.Fsm#FSM_SET - ---- Monitors and manages as many replacement AI groups as there are +--- ![Banner Image](..\Images\deprecated.png) +-- +-- Monitors and manages as many replacement AI groups as there are -- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players. -- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions. -- diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua index dc0a843a8..70f6fb438 100644 --- a/Moose Development/Moose/AI/AI_CAP.lua +++ b/Moose Development/Moose/AI/AI_CAP.lua @@ -39,6 +39,8 @@ --- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group} -- and automatically engage any airborne enemies that are within a certain range or within a certain zone. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_CAP\Dia3.JPG) -- -- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event. diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua index 832cc6bd5..1c99401a8 100644 --- a/Moose Development/Moose/AI/AI_CAS.lua +++ b/Moose Development/Moose/AI/AI_CAS.lua @@ -38,6 +38,9 @@ -- @extends AI.AI_Patrol#AI_PATROL_ZONE --- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}. +-- +-- ![Banner Image](..\Images\deprecated.png) +-- -- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone. -- -- ![HoldAndEngage](..\Presentations\AI_CAS\Dia3.JPG) diff --git a/Moose Development/Moose/AI/AI_Cargo.lua b/Moose Development/Moose/AI/AI_Cargo.lua index 0bd6ab9ea..eac91c668 100644 --- a/Moose Development/Moose/AI/AI_Cargo.lua +++ b/Moose Development/Moose/AI/AI_Cargo.lua @@ -9,12 +9,14 @@ -- @module AI.AI_Cargo -- @image Cargo.JPG --- @type AI_CARGO +--- @type AI_CARGO -- @extends Core.Fsm#FSM_CONTROLLABLE --- Base class for the dynamic cargo handling capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation. -- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework. -- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo. diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 6088ea865..ee026c599 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -15,6 +15,8 @@ --- Brings a dynamic cargo handling capability for an AI vehicle group. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework. diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 79d1b6307..4db63ee86 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -14,6 +14,8 @@ --- Brings a dynamic cargo handling capability for an AI airplane group. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases. -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 71b7f9f43..b63c76192 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -22,6 +22,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # The dispatcher concept. -- -- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index ab25a8e60..73d27da45 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -36,6 +36,8 @@ --- A dynamic cargo transportation capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua index a971936f6..cc4835576 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -30,6 +30,8 @@ --- Brings a dynamic cargo handling capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_DISPATCHER_AIRPLANE module is derived from the AI_CARGO_DISPATCHER module. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index c391324e4..182987d70 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -31,6 +31,8 @@ --- A dynamic cargo handling capability for AI helicopter groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua index 152ea7881..906d0801d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua @@ -29,6 +29,8 @@ --- A dynamic cargo transportation capability for AI groups. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation. -- -- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module. diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index b91c0db38..c0c0c1403 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -15,6 +15,8 @@ --- Brings a dynamic cargo handling capability for an AI helicopter group. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation. -- -- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework. diff --git a/Moose Development/Moose/AI/AI_Cargo_Ship.lua b/Moose Development/Moose/AI/AI_Cargo_Ship.lua index 669da09b5..2073c7a27 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Ship.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Ship.lua @@ -14,6 +14,8 @@ --- Brings a dynamic cargo handling capability for an AI naval group. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Naval ships can be utilized to transport cargo around the map following naval shipping lanes. -- The AI_CARGO_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework. -- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo. diff --git a/Moose Development/Moose/AI/AI_Escort.lua b/Moose Development/Moose/AI/AI_Escort.lua index ad325ed94..c32312f27 100644 --- a/Moose Development/Moose/AI/AI_Escort.lua +++ b/Moose Development/Moose/AI/AI_Escort.lua @@ -25,6 +25,8 @@ -- -- Allows you to interact with escorting AI on your flight and take the lead. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10). -- -- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes. diff --git a/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua b/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua index ff4c0ddfe..d2366568f 100644 --- a/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Escort_Dispatcher.lua @@ -23,6 +23,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua b/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua index 0b3180910..14e8661a6 100644 --- a/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Dispatcher_Request.lua @@ -21,6 +21,8 @@ --- Models the assignment of AI escorts to player flights upon request using the radio menu. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # Developer Note -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE diff --git a/Moose Development/Moose/AI/AI_Escort_Request.lua b/Moose Development/Moose/AI/AI_Escort_Request.lua index 08bee2f64..511e7ec2c 100644 --- a/Moose Development/Moose/AI/AI_Escort_Request.lua +++ b/Moose Development/Moose/AI/AI_Escort_Request.lua @@ -25,6 +25,8 @@ -- -- Allows you to interact with escorting AI on your flight and take the lead. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10). -- -- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes. diff --git a/Moose Development/Moose/AI/AI_Formation.lua b/Moose Development/Moose/AI/AI_Formation.lua index 4d5257eb1..4496ab65b 100644 --- a/Moose Development/Moose/AI/AI_Formation.lua +++ b/Moose Development/Moose/AI/AI_Formation.lua @@ -40,6 +40,8 @@ --- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions. -- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!! diff --git a/Moose Development/Moose/AI/AI_Patrol.lua b/Moose Development/Moose/AI/AI_Patrol.lua index 408e3b1a6..e8d21ed44 100644 --- a/Moose Development/Moose/AI/AI_Patrol.lua +++ b/Moose Development/Moose/AI/AI_Patrol.lua @@ -48,6 +48,8 @@ --- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ![Process](..\Presentations\AI_PATROL\Dia3.JPG) -- -- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event. diff --git a/Moose Development/Moose/Actions/Act_Account.lua b/Moose Development/Moose/Actions/Act_Account.lua index 04b59fa9f..9a26f437c 100644 --- a/Moose Development/Moose/Actions/Act_Account.lua +++ b/Moose Development/Moose/Actions/Act_Account.lua @@ -1,6 +1,6 @@ --- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs. -- --- ![Banner Image](..\Presentations\ACT_ACCOUNT\Dia1.JPG) +-- ![Banner Image](..\Images\deprecated.png) -- -- === -- @@ -8,9 +8,11 @@ -- @image MOOSE.JPG do -- ACT_ACCOUNT - + --- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS} - -- + -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- ## ACT_ACCOUNT state machine: -- -- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. diff --git a/Moose Development/Moose/Actions/Act_Assign.lua b/Moose Development/Moose/Actions/Act_Assign.lua index 3b261cfb1..1f99b86e7 100644 --- a/Moose Development/Moose/Actions/Act_Assign.lua +++ b/Moose Development/Moose/Actions/Act_Assign.lua @@ -1,6 +1,8 @@ --- (SP) (MP) (FSM) Accept or reject process for player (task) assignments. -- -- === +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS} -- diff --git a/Moose Development/Moose/Actions/Act_Assist.lua b/Moose Development/Moose/Actions/Act_Assist.lua index 9b4744561..badc69965 100644 --- a/Moose Development/Moose/Actions/Act_Assist.lua +++ b/Moose Development/Moose/Actions/Act_Assist.lua @@ -1,5 +1,6 @@ --- (SP) (MP) (FSM) Route AI or players through waypoints or to zones. -- +-- ![Banner Image](..\Images\deprecated.png) -- ## ACT_ASSIST state machine: -- -- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur. diff --git a/Moose Development/Moose/Actions/Act_Route.lua b/Moose Development/Moose/Actions/Act_Route.lua index b387b6584..548c6a846 100644 --- a/Moose Development/Moose/Actions/Act_Route.lua +++ b/Moose Development/Moose/Actions/Act_Route.lua @@ -2,6 +2,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS} -- -- ## ACT_ROUTE state machine: diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 413beb514..76307dd78 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -2,6 +2,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # 1) MOOSE Cargo System. -- -- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities. diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 2dc94cd5a..7048e503f 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -22,6 +22,9 @@ do -- CARGO_CRATE -- @type CARGO_CRATE -- @extends Cargo.Cargo#CARGO_REPRESENTABLE + --- + -- ![Banner Image](..\Images\deprecated.png) + -- --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers. -- diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index c2d9b26a2..4532a21fa 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -26,6 +26,8 @@ do -- CARGO_GROUP -- @extends Cargo.Cargo#CARGO_REPORTABLE --- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. + -- + -- ![Banner Image](..\Images\deprecated.png) -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. -- -- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo: diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index ad26e8868..a8cb5022a 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -32,6 +32,8 @@ do -- CARGO_SLINGLOAD -- -- # Developer Note -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index a76469870..bc504d003 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -30,6 +30,8 @@ do -- CARGO_UNIT -- -- # Developer Note -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/Functional/MissileTrainer.lua b/Moose Development/Moose/Functional/MissileTrainer.lua index f52363ba2..42626071c 100644 --- a/Moose Development/Moose/Functional/MissileTrainer.lua +++ b/Moose Development/Moose/Functional/MissileTrainer.lua @@ -53,6 +53,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE. -- Therefore, this class is considered to be deprecated and superseded by the [Functional.Fox](https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html) class, which provides the same functionality. -- diff --git a/Moose Development/Moose/Functional/ZoneGoalCargo.lua b/Moose Development/Moose/Functional/ZoneGoalCargo.lua index 7a19ed02a..2e803b2a3 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCargo.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCargo.lua @@ -7,6 +7,8 @@ -- -- # Developer Note -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE -- Therefore, this class is considered to be deprecated -- diff --git a/Moose Development/Moose/Tasking/CommandCenter.lua b/Moose Development/Moose/Tasking/CommandCenter.lua index 873279e4a..30d285682 100644 --- a/Moose Development/Moose/Tasking/CommandCenter.lua +++ b/Moose Development/Moose/Tasking/CommandCenter.lua @@ -29,6 +29,8 @@ --- Governs multiple missions, the tasking and the reporting. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- Command centers govern missions, communicates the task assignments between human players of the coalition, and manages the menu flow. -- It can assign a random task to a player when requested. diff --git a/Moose Development/Moose/Tasking/DetectionManager.lua b/Moose Development/Moose/Tasking/DetectionManager.lua index da560e5d0..a1c4505d5 100644 --- a/Moose Development/Moose/Tasking/DetectionManager.lua +++ b/Moose Development/Moose/Tasking/DetectionManager.lua @@ -5,6 +5,8 @@ -- The @{#DETECTION_MANAGER} class defines the core functions to report detected objects to groups. -- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- 1.1) DETECTION_MANAGER constructor: -- ----------------------------------- -- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance. diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua index 1c65725d2..0c5b76ac3 100644 --- a/Moose Development/Moose/Tasking/Mission.lua +++ b/Moose Development/Moose/Tasking/Mission.lua @@ -27,6 +27,8 @@ --- Models goals to be achieved and can contain multiple tasks to be executed to achieve the goals. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- A mission contains multiple tasks and can be of different task types. -- These tasks need to be assigned to human players to be executed. -- diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua index 21be7dfd8..be3e86f2d 100644 --- a/Moose Development/Moose/Tasking/Task.lua +++ b/Moose Development/Moose/Tasking/Task.lua @@ -12,6 +12,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- # 1) Tasking from a player perspective. -- -- Tasking can be controlled by using the "other" menu in the radio menu of the player group. diff --git a/Moose Development/Moose/Tasking/TaskInfo.lua b/Moose Development/Moose/Tasking/TaskInfo.lua index 4007230dc..effcdf698 100644 --- a/Moose Development/Moose/Tasking/TaskInfo.lua +++ b/Moose Development/Moose/Tasking/TaskInfo.lua @@ -17,6 +17,8 @@ --- -- # TASKINFO class, extends @{Core.Base#BASE} -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ## The TASKINFO class implements the methods to contain information and display information of a task. -- -- # Developer Note diff --git a/Moose Development/Moose/Tasking/Task_A2A.lua b/Moose Development/Moose/Tasking/Task_A2A.lua index a43c79c9f..6ba36b054 100644 --- a/Moose Development/Moose/Tasking/Task_A2A.lua +++ b/Moose Development/Moose/Tasking/Task_A2A.lua @@ -20,6 +20,9 @@ do -- TASK_A2A --- Defines Air To Air tasks for a @{Core.Set} of Target Units, -- based on the tasking capabilities defined in @{Tasking.Task#TASK}. + -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The TASK_A2A is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- -- * **None**: Start of the process diff --git a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua index 9b0f8f5b5..69c29d731 100644 --- a/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2A_Dispatcher.lua @@ -30,6 +30,8 @@ do -- TASK_A2A_DISPATCHER -- @extends Tasking.DetectionManager#DETECTION_MANAGER --- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Core.Set} of EWR installation groups. + -- + -- ![Banner Image](..\Images\deprecated.png) -- -- ![Banner Image](..\Presentations\TASK_A2A_DISPATCHER\Dia3.JPG) -- diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua index 84bdcf360..f39c4968c 100644 --- a/Moose Development/Moose/Tasking/Task_A2G.lua +++ b/Moose Development/Moose/Tasking/Task_A2G.lua @@ -20,6 +20,9 @@ do -- TASK_A2G --- The TASK_A2G class defines Air To Ground tasks for a @{Core.Set} of Target Units, -- based on the tasking capabilities defined in @{Tasking.Task#TASK}. + -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- -- * **None**: Start of the process diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua index a98477d86..9fc410de1 100644 --- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua @@ -33,6 +33,8 @@ do -- TASK_A2G_DISPATCHER -- @extends Tasking.DetectionManager#DETECTION_MANAGER --- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Functional.Detection} object. + -- + -- ![Banner Image](..\Images\deprecated.png) -- -- It uses the Tasking System within the MOOSE framework, which is a multi-player Tasking Orchestration system. -- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon, diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index 76a3b9e9a..526a508d4 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -10,6 +10,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- ## Test Missions: -- -- Test missions can be located on the main GITHUB site. diff --git a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua index be2086a2f..5ede27694 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Dispatcher.lua @@ -76,6 +76,8 @@ do -- TASK_CAPTURE_DISPATCHER --- Implements the dynamic dispatching of capture zone tasks. -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The **TASK_CAPTURE_DISPATCHER** allows you to setup various tasks for let human -- players capture zones in a co-operation effort. -- diff --git a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua index bd0637a9d..82265c8ae 100644 --- a/Moose Development/Moose/Tasking/Task_Capture_Zone.lua +++ b/Moose Development/Moose/Tasking/Task_Capture_Zone.lua @@ -20,6 +20,8 @@ do -- TASK_ZONE_GOAL --- # TASK_ZONE_GOAL class, extends @{Tasking.Task#TASK} -- + -- ![Banner Image](..\Images\deprecated.png) + -- -- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone. -- The TASK_ZONE_GOAL is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses: -- diff --git a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua index f0c14b227..e216c6ea2 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_CSAR.lua @@ -44,6 +44,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- Please read through the @{Tasking.Task_CARGO} process to understand the mechanisms of tasking and cargo tasking and handling. -- -- The cargo will be a downed pilot, which is located somwhere on the battlefield. Use the menus system and facilities to diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua index d60318573..e50dbbfeb 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Dispatcher.lua @@ -2,6 +2,8 @@ -- -- The **TASK_CARGO_DISPATCHER** allows you to setup various tasks for let human -- players transport cargo as part of a task. +-- +-- ![Banner Image](..\Images\deprecated.png) -- -- The cargo dispatcher will implement for you mechanisms to create cargo transportation tasks: -- diff --git a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua index 6f8137c6a..5f6fb6e51 100644 --- a/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua +++ b/Moose Development/Moose/Tasking/Task_Cargo_Transport.lua @@ -1,5 +1,7 @@ --- **Tasking** - Models tasks for players to transport cargo. -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- **Specific features:** -- -- * Creates a task to transport #Cargo.Cargo to and between deployment zones. diff --git a/Moose Development/Moose/Tasking/Task_Manager.lua b/Moose Development/Moose/Tasking/Task_Manager.lua index 127b455ad..7cd71c485 100644 --- a/Moose Development/Moose/Tasking/Task_Manager.lua +++ b/Moose Development/Moose/Tasking/Task_Manager.lua @@ -2,6 +2,8 @@ -- -- === -- +-- ![Banner Image](..\Images\deprecated.png) +-- -- 1) @{Tasking.Task_Manager#TASK_MANAGER} class, extends @{Core.Fsm#FSM} -- === -- The @{Tasking.Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups. From 7a5b9a75f30f7f16fece6f62eab2e74fd6033d2d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 17:07:55 +0200 Subject: [PATCH 31/50] #AIRBASE - added Syria Marka AFB --- Moose Development/Moose/Wrapper/Airbase.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index c7d576e38..aaab918bd 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -513,6 +513,7 @@ AIRBASE.TheChannel = { -- * AIRBASE.Syria.Hatzor -- * AIRBASE.Syria.Palmashim -- * AIRBASE.Syria.Tel_Nof +-- * AIRBASE.Syria.Marka -- --@field Syria AIRBASE.Syria={ @@ -586,6 +587,7 @@ AIRBASE.Syria={ ["Hatzor"] = "Hatzor", ["Palmashim"] = "Palmashim", ["Tel_Nof"] = "Tel Nof", + ["Marka"] = "Marka", } --- Airbases of the Mariana Islands map: From 66032d68949906597c35b95807b6a8b8cca89d32 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 May 2025 18:24:26 +0200 Subject: [PATCH 32/50] #EASYGCICAP - added `SetDefaultTakeOffType()` --- Moose Development/Moose/Ops/EasyGCICAP.lua | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 31b732a74..943518b2e 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -70,6 +70,7 @@ -- @field #boolean DespawnAfterLanding -- @field #boolean DespawnAfterHolding -- @field #list ListOfAuftrag +-- @field #string defaulttakeofftype Take off type -- @extends Core.Fsm#FSM --- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown. @@ -223,7 +224,8 @@ EASYGCICAP = { ReadyFlightGroups = {}, DespawnAfterLanding = false, DespawnAfterHolding = true, - ListOfAuftrag = {} + ListOfAuftrag = {}, + defaulttakeofftype = "hot", } --- Internal Squadron data type @@ -259,7 +261,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.20" +EASYGCICAP.version="0.1.21" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -312,6 +314,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName) self.DespawnAfterLanding = false self.DespawnAfterHolding = true self.ListOfAuftrag = {} + self.defaulttakeofftype = "hot" -- Set some string id for output to DCS.log file. self.lid=string.format("EASYGCICAP %s | ", self.alias) @@ -400,6 +403,16 @@ function EASYGCICAP:SetDefaultRepeatOnFailure(Retries) return self end +--- Add default take off type for the airwings. +-- @param #EASYGCICAP self +-- @param #string Takeoff Can be "hot", "cold", or "air" - default is "hot". +-- @return #EASYGCICAP self +function EASYGCICAP:SetDefaultTakeOffType(Takeoff) + self:T(self.lid.."SetDefaultTakeOffType") + self.defaulttakeofftype = Takeoff or "hot" + return self +end + --- Set default CAP Speed in knots -- @param #EASYGCICAP self -- @param #number Speed Speed defaults to 300 @@ -596,9 +609,8 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) if #self.ManagedREC > 0 then CAP_Wing:SetNumberRecon(1) end - --local PatrolCoordinateKutaisi = ZONE:New(CapZoneName):GetCoordinate() - --CAP_Wing:AddPatrolPointCAP(PatrolCoordinateKutaisi,self.capalt,UTILS.KnotsToAltKIAS(self.capspeed,self.capalt),self.capdir,self.capleg) - CAP_Wing:SetTakeoffHot() + + CAP_Wing:SetTakeoffType(self.defaulttakeofftype) CAP_Wing:SetLowFuelThreshold(0.3) CAP_Wing.RandomAssetScore = math.random(50,100) CAP_Wing:Start() From 09b7922b84494f40a33557c9759e82dc6ca46c70 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 16 May 2025 11:58:40 +0200 Subject: [PATCH 33/50] Small fixes --- Moose Development/Moose/Core/Database.lua | 2 ++ Moose Development/Moose/Functional/Mantis.lua | 26 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 4aec2393a..85bde137c 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -872,6 +872,8 @@ end -- @return Wrapper.Group#GROUP The found GROUP. function DATABASE:FindGroup( GroupName ) + if type(GroupName) ~= "string" or GroupName == "" then return end + local GroupFound = self.GROUPS[GroupName] if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 989b400e0..965762d07 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -64,6 +64,7 @@ -- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White -- @field #number checkcounter Counter for SAM Table refreshes. -- @field #number DLinkCacheTime Seconds after which cached contacts in DLink will decay. +-- @field #boolean logsamstatus Log SAM status in dcs.log every cycle if true -- @extends Core.Base#BASE @@ -322,6 +323,7 @@ MANTIS = { SmokeDecoyColor = SMOKECOLOR.White, checkcounter = 1, DLinkCacheTime = 120, + logsamstatus = false, } --- Advanced state enumerator @@ -647,6 +649,8 @@ do table.insert(self.ewr_templates,awacs) end + self.logsamstatus = false + self:T({self.ewr_templates}) self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition) @@ -678,7 +682,7 @@ do -- TODO Version -- @field #string version - self.version="0.9.29" + self.version="0.9.30" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) --- FSM Functions --- @@ -1695,7 +1699,9 @@ do local grpname = group:GetName() local grpcoord = group:GetCoordinate() local grprange, grpheight,type,blind = self:_GetSAMRange(grpname) - local radaralive = group:IsSAM() + -- TODO the below might stop working at some point after some hours, needs testing + --local radaralive = group:IsSAM() + local radaralive = true table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type}) -- make the table lighter, as I don't really use the zone here table.insert( SEAD_Grps, grpname ) if type == MANTIS.SamType.LONG and radaralive then @@ -1878,8 +1884,9 @@ do -- @param #MANTIS self -- @param Functional.Detection#DETECTION_AREAS detection Detection object -- @param #boolean dlink + -- @param #boolean reporttolog -- @return #MANTIS self - function MANTIS:_Check(detection,dlink) + function MANTIS:_Check(detection,dlink,reporttolog) self:T(self.lid .. "Check") --get detected set local detset = detection:GetDetectedItemCoordinates() @@ -1906,7 +1913,8 @@ do local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxclassic) end - if self.debug or self.verbose then + + local function GetReport() local statusreport = REPORT:New("\nMANTIS Status "..self.name) statusreport:Add("+-----------------------------+") statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred)) @@ -1915,7 +1923,15 @@ do statusreport:Add(string.format("+ SHORAD active: %2d",activeshorads)) end statusreport:Add("+-----------------------------+") + return statusreport + end + + if self.debug or self.verbose then + local statusreport = GetReport() MESSAGE:New(statusreport:Text(),10):ToAll():ToLog() + elseif reporttolog == true then + local statusreport = GetReport() + MESSAGE:New(statusreport:Text(),10):ToLog() end return self end @@ -2023,7 +2039,7 @@ do self:T({From, Event, To}) -- check detection if not self.state2flag then - self:_Check(self.Detection,self.DLink) + self:_Check(self.Detection,self.DLink,self.logsamstatus) end local EWRAlive = self:_CheckAnyEWRAlive() From b126cc00d05ec3e139864467443dbcd6177a1a21 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 16 May 2025 13:43:03 +0200 Subject: [PATCH 34/50] xx --- Moose Development/Moose/Functional/Mantis.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 965762d07..8ec4939d7 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -1863,7 +1863,7 @@ do end --end alive end --end check end --for loop - if self.debug or self.verbose then + if self.debug or self.verbose or self.logsamstatus then for _,_status in pairs(self.SamStateTracker) do if _status == "GREEN" then instatusgreen=instatusgreen+1 From 997baf21a0af023916a8b20221daa0e8dfda28f9 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 May 2025 10:04:58 +0200 Subject: [PATCH 35/50] #CSAR fix for ADF beacons --- Moose Development/Moose/Ops/CSAR.lua | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 76f6df917..f1a1578ae 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -313,7 +313,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31 --- CSAR class version. -- @field #string version -CSAR.version="1.0.31" +CSAR.version="1.0.32" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -468,7 +468,7 @@ function CSAR:New(Coalition, Template, Alias) -- added 1.0.15 self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane - self.ADFRadioPwr = 1000 + self.ADFRadioPwr = 500 -- added 1.0.16 self.PilotWeight = 80 @@ -2333,9 +2333,9 @@ end -- @param #CSAR self -- @param Wrapper.Group#GROUP _group Group #GROUP object. -- @param #number _freq Frequency to use --- @param #string _name Beacon Name to use +-- @param #string BeaconName Beacon Name to use -- @return #CSAR self -function CSAR:_AddBeaconToGroup(_group, _freq, _name) +function CSAR:_AddBeaconToGroup(_group, _freq, BeaconName) self:T(self.lid .. " _AddBeaconToGroup") if self.CreateRadioBeacons == false then return end local _group = _group @@ -2356,10 +2356,11 @@ function CSAR:_AddBeaconToGroup(_group, _freq, _name) if _radioUnit then local name = _radioUnit:GetName() local Frequency = _freq -- Freq in Hertz - local name = _radioUnit:GetName() + --local name = _radioUnit:GetName() local Sound = "l10n/DEFAULT/"..self.radioSound local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0} - trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000,_name) -- Beacon in MP only runs for exactly 30secs straight + self:I(self.lid..string.format("Added Radio Beacon %d Hertz | Name %s | Position {%d,%d,%d}",Frequency,BeaconName,vec3.x,vec3.y,vec3.z)) + trigger.action.radioTransmission(Sound, vec3, 0, true, Frequency, self.ADFRadioPwr or 500,BeaconName) -- Beacon in MP only runs for exactly 30secs straight end end @@ -2380,9 +2381,13 @@ function CSAR:_RefreshRadioBeacons() local group = pilot.group local frequency = pilot.frequency or 0 -- thanks to @Thrud local bname = pilot.BeaconName or pilot.name..math.random(1,100000) - trigger.action.stopRadioTransmission(bname) + --trigger.action.stopRadioTransmission(bname) if group and group:IsAlive() and frequency > 0 then - self:_AddBeaconToGroup(group,frequency,bname) + --self:_AddBeaconToGroup(group,frequency,bname) + else + if frequency > 0 then + trigger.action.stopRadioTransmission(bname) + end end end end From a4feafab8e9d4da5100238ebf21d80924b7cd90e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 May 2025 10:21:48 +0200 Subject: [PATCH 36/50] #POINT - improved IsDay() for Kola --- Moose Development/Moose/Core/Point.lua | 11 +++++++++-- Moose Development/Moose/Utilities/Utils.lua | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index f1aa66289..35ad76b4c 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -2992,8 +2992,10 @@ do -- COORDINATE local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff) local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff) - if sunrise == "N/R" then return false end - if sunrise == "N/S" then return true end + if type(sunrise) == "string" or type(sunset) == "string" then + if sunrise == "N/R" then return false end + if sunset == "N/S" then return true end + end local time=UTILS.ClockToSeconds(clock) @@ -3011,6 +3013,11 @@ do -- COORDINATE -- Todays sun set in sec. local sunset=self:GetSunset(true) + + if type(sunrise) == "string" or type(sunset) == "string" then + if sunrise == "N/R" then return false end + if sunset == "N/S" then return true end + end -- Seconds passed since midnight. local time=UTILS.SecondsOfToday() diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 73ce154c9..19e6889b3 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -2145,9 +2145,9 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal) local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)) if rising and cosH > 1 then - return "N/S" -- The sun never rises on this location on the specified date + return "N/R" -- The sun never rises on this location on the specified date elseif cosH < -1 then - return "N/R" -- The sun never sets on this location on the specified date + return "N/S" -- The sun never sets on this location on the specified date end -- Finish calculating H and convert into hours From d3b62d026054395599155eb9bc12a685181ad065 Mon Sep 17 00:00:00 2001 From: shaji Date: Sat, 24 May 2025 11:18:41 +0200 Subject: [PATCH 37/50] [ADDED] `TARGET:GetObjects()` and `TARGET:GetCoordinates()` in case of SET --- Moose Development/Moose/Ops/Target.lua | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index fcc108087..4863f5202 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -1715,6 +1715,26 @@ function TARGET:GetAverageCoordinate() return nil end + +--- Get coordinates of all targets. (e.g. for a SET_STATIC) +-- @param #TARGET self +-- @return #table Table with coordinates of all targets. +function TARGET:GetCoordinates() + local coordinates={} + + for _,_target in pairs(self.targets) do + local target=_target --#TARGET.Object + + local coordinate=self:GetTargetCoordinate(target) + if coordinate then + table.insert(coordinates, coordinate) + end + + end + + return coordinates +end + --- Get heading of target. -- @param #TARGET self -- @return #number Heading of the target in degrees. @@ -1968,6 +1988,21 @@ function TARGET:GetObject(RefCoordinate, Coalitions) return nil end +--- Get all target objects. +-- @param #TARGET self +-- @return #table List of target objects. +function TARGET:GetObjects() + local objects={} + + for _,_target in pairs(self.targets) do + local target=_target --#TARGET.Object + + table.insert(objects, target.Object) + end + + return objects +end + --- Count alive objects. -- @param #TARGET self -- @param #TARGET.Object Target Target objective. From 20c50c751fc7162e3218454af6a25b21ff144ead Mon Sep 17 00:00:00 2001 From: shaji Date: Sat, 24 May 2025 11:29:01 +0200 Subject: [PATCH 38/50] [ADDED] Sets target support for Auftrag STRIKE and BOMBING --- Moose Development/Moose/Ops/Auftrag.lua | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 98d42aa37..fb4d0adbe 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1717,7 +1717,7 @@ end --- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate. -- @param #AUFTRAG self --- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC or TARGET object. +-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object. -- @param #number Altitude Engage altitude in feet. Default 2000 ft. -- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options. -- @return #AUFTRAG self @@ -1749,7 +1749,7 @@ end --- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate. -- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing). -- @param #AUFTRAG self --- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC or TARGET object. +-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object. -- @param #number Altitude Engage altitude in feet. Default 25000 ft. -- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options. -- @return #AUFTRAG self @@ -6108,10 +6108,13 @@ function AUFTRAG:GetDCSMissionTask() -- BOMBING Mission -- --------------------- - local DCStask=CONTROLLABLE.TaskBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, Divebomb) + local coords = self.engageTarget:GetCoordinates() + for _, coord in pairs(coords) do + local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) + + table.insert(DCStasks, DCStask) + end - table.insert(DCStasks, DCStask) - elseif self.type==AUFTRAG.Type.STRAFING then ---------------------- @@ -6311,9 +6314,12 @@ function AUFTRAG:GetDCSMissionTask() -- STRIKE Mission -- -------------------- - local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) + local coords = self.engageTarget:GetCoordinates() + for _, coord in pairs(coords) do + local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType) - table.insert(DCStasks, DCStask) + table.insert(DCStasks, DCStask) + end elseif self.type==AUFTRAG.Type.TANKER or self.type==AUFTRAG.Type.RECOVERYTANKER then From 2fc16ba694d8d28534c0af1b11d2d7483d7d9b13 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 24 May 2025 15:53:43 +0200 Subject: [PATCH 39/50] Runway text duplication --- Moose Development/Moose/Ops/ATIS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index f53f953d0..107808898 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -2798,7 +2798,7 @@ function ATIS:onafterBroadcast( From, Event, To ) end _RUNACT = subtitle - alltext = alltext .. ";\n" .. subtitle + --alltext = alltext .. ";\n" .. subtitle -- Runway length. if self.rwylength then From 7ca219748dbb8927980f438cf4a0f2a791421367 Mon Sep 17 00:00:00 2001 From: shaji Date: Sat, 24 May 2025 19:46:20 +0200 Subject: [PATCH 40/50] [FIXED] Velocity is taking into account dead units for GROUP --- Moose Development/Moose/Wrapper/Group.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index fa597e461..44f313f27 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -912,15 +912,18 @@ function GROUP:GetVelocityVec3() if DCSGroup and DCSGroup:isExist() then local GroupUnits = DCSGroup:getUnits() - local GroupCount = #GroupUnits + local GroupCount = 0 local VelocityVec3 = { x = 0, y = 0, z = 0 } for _, DCSUnit in pairs( GroupUnits ) do - local UnitVelocityVec3 = DCSUnit:getVelocity() - VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x - VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y - VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z + if DCSUnit:isExist() and DCSUnit:isActive() then + local UnitVelocityVec3 = DCSUnit:getVelocity() + VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x + VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y + VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z + GroupCount = GroupCount + 1 + end end VelocityVec3.x = VelocityVec3.x / GroupCount @@ -1754,11 +1757,13 @@ function GROUP:GetMaxVelocity() for Index, UnitData in pairs( DCSGroup:getUnits() ) do - local UnitVelocityVec3 = UnitData:getVelocity() - local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z ) + if UnitData:isExist() and UnitData:isActive() then + local UnitVelocityVec3 = UnitData:getVelocity() + local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z ) - if UnitVelocity > GroupVelocityMax then - GroupVelocityMax = UnitVelocity + if UnitVelocity > GroupVelocityMax then + GroupVelocityMax = UnitVelocity + end end end From dd5ca93f26a69932407927e161614f57c7475d4e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 30 May 2025 11:13:50 +0200 Subject: [PATCH 41/50] CSAR Small addition --- Moose Development/Moose/Ops/CSAR.lua | 30 +++++++--------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index f1a1578ae..98b8a2128 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -313,7 +313,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31 --- CSAR class version. -- @field #string version -CSAR.version="1.0.32" +CSAR.version="1.0.33" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -2116,7 +2116,8 @@ end --- (Internal) Determine distance to closest MASH. -- @param #CSAR self -- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT --- @return #CSAR self +-- @return #number Distance in meters +-- @return #string MASH Name as string function CSAR:_GetClosestMASH(_heli) self:T(self.lid .. " _GetClosestMASH") local _mashset = self.mash -- Core.Set#SET_GROUP @@ -2128,31 +2129,13 @@ function CSAR:_GetClosestMASH(_heli) local _shortestDistance = -1 local _distance = 0 local _helicoord = _heli:GetCoordinate() - - local function GetCloseAirbase(coordinate,Coalition,Category) - - local a=coordinate:GetVec3() - local distmin=math.huge - local airbase=nil - for DCSairbaseID, DCSairbase in pairs(world.getAirbases(Coalition)) do - local b=DCSairbase:getPoint() - - local c=UTILS.VecSubstract(a,b) - local dist=UTILS.VecNorm(c) - - if dist Date: Fri, 30 May 2025 16:03:01 +0200 Subject: [PATCH 42/50] - [ADDED] Removes previous downed pilot with the same player name in Ejection event - [ADDED] `useFIFOLimitReplacement` If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached (FIFO queue), otherwise does not add downed pilots when the limit is reached. --- Moose Development/Moose/Ops/CSAR.lua | 71 +++++++++++++++++++++------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 98b8a2128..09af31eb5 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -263,6 +263,7 @@ CSAR = { rescuedpilots = 0, limitmaxdownedpilots = true, maxdownedpilots = 10, + useFIFOLimitReplacement = false, -- If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached. allheligroupset = nil, topmenuname = "CSAR", ADFRadioPwr = 1000, @@ -1144,19 +1145,8 @@ function CSAR:_EventHandler(EventData) self:T("Double Ejection!") return self end - - -- limit no of pilots in the field. - if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then - self:T("Maxed Downed Pilot!") - return self - end - - - -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case - -- might create dual pilots in edge cases - - local wetfeet = false - + + local initdcscoord = nil local initcoord = nil if _event.id == EVENTS.Ejection then @@ -1168,6 +1158,36 @@ function CSAR:_EventHandler(EventData) initcoord = COORDINATE:NewFromVec3(initdcscoord) self:T({initdcscoord}) end + + -- Remove downed pilot if already exists to replace with new one. + if _event.IniPlayerName then + local PilotTable = self.downedPilots --#CSAR.DownedPilot + local _foundPilot = nil + for _,_pilot in pairs(PilotTable) do + if _pilot.player == _event.IniPlayerName and _pilot.alive == true then + _foundPilot = _pilot + break + end + end + if _foundPilot then + self:T("Downed pilot already exists!") + _foundPilot.group:Destroy(false) + self:_RemoveNameFromDownedPilots(_foundPilot.name) + self:_CheckDownedPilotTable() + end + end + + -- limit no of pilots in the field. + if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then + self:T("Maxed Downed Pilot!") + return self + end + + + -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case + -- might create dual pilots in edge cases + + local wetfeet = false --local surface = _unit:GetCoordinate():GetSurfaceType() local surface = initcoord:GetSurfaceType() @@ -2401,11 +2421,26 @@ function CSAR:_ReachedPilotLimit() local limit = self.maxdownedpilots local islimited = self.limitmaxdownedpilots local count = self:_CountActiveDownedPilots() - if islimited and (count >= limit) then - return true - else - return false - end + if islimited and (count >= limit) then + if self.useFIFOLimitReplacement then + local oldIndex = -1 + local oldDownedPilot = nil + for _index, _downedpilot in pairs(self.downedPilots) do + oldIndex = _index + oldDownedPilot = _downedpilot + break + end + if oldDownedPilot then + oldDownedPilot.group:Destroy(false) + oldDownedPilot.alive = false + self:_CheckDownedPilotTable() + return false + end + end + return true + else + return false + end end --- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment. From bb1caa6642bce39c2ec0a109cdae83b68cad3d39 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Fri, 30 May 2025 18:37:38 +0200 Subject: [PATCH 43/50] Update CSAR.lua --- Moose Development/Moose/Ops/CSAR.lua | 71 +++++++++++++++++++++------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Ops/CSAR.lua b/Moose Development/Moose/Ops/CSAR.lua index 98b8a2128..09af31eb5 100644 --- a/Moose Development/Moose/Ops/CSAR.lua +++ b/Moose Development/Moose/Ops/CSAR.lua @@ -263,6 +263,7 @@ CSAR = { rescuedpilots = 0, limitmaxdownedpilots = true, maxdownedpilots = 10, + useFIFOLimitReplacement = false, -- If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached. allheligroupset = nil, topmenuname = "CSAR", ADFRadioPwr = 1000, @@ -1144,19 +1145,8 @@ function CSAR:_EventHandler(EventData) self:T("Double Ejection!") return self end - - -- limit no of pilots in the field. - if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then - self:T("Maxed Downed Pilot!") - return self - end - - - -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case - -- might create dual pilots in edge cases - - local wetfeet = false - + + local initdcscoord = nil local initcoord = nil if _event.id == EVENTS.Ejection then @@ -1168,6 +1158,36 @@ function CSAR:_EventHandler(EventData) initcoord = COORDINATE:NewFromVec3(initdcscoord) self:T({initdcscoord}) end + + -- Remove downed pilot if already exists to replace with new one. + if _event.IniPlayerName then + local PilotTable = self.downedPilots --#CSAR.DownedPilot + local _foundPilot = nil + for _,_pilot in pairs(PilotTable) do + if _pilot.player == _event.IniPlayerName and _pilot.alive == true then + _foundPilot = _pilot + break + end + end + if _foundPilot then + self:T("Downed pilot already exists!") + _foundPilot.group:Destroy(false) + self:_RemoveNameFromDownedPilots(_foundPilot.name) + self:_CheckDownedPilotTable() + end + end + + -- limit no of pilots in the field. + if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then + self:T("Maxed Downed Pilot!") + return self + end + + + -- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case + -- might create dual pilots in edge cases + + local wetfeet = false --local surface = _unit:GetCoordinate():GetSurfaceType() local surface = initcoord:GetSurfaceType() @@ -2401,11 +2421,26 @@ function CSAR:_ReachedPilotLimit() local limit = self.maxdownedpilots local islimited = self.limitmaxdownedpilots local count = self:_CountActiveDownedPilots() - if islimited and (count >= limit) then - return true - else - return false - end + if islimited and (count >= limit) then + if self.useFIFOLimitReplacement then + local oldIndex = -1 + local oldDownedPilot = nil + for _index, _downedpilot in pairs(self.downedPilots) do + oldIndex = _index + oldDownedPilot = _downedpilot + break + end + if oldDownedPilot then + oldDownedPilot.group:Destroy(false) + oldDownedPilot.alive = false + self:_CheckDownedPilotTable() + return false + end + end + return true + else + return false + end end --- User - Function to add onw SET_GROUP Set-up for pilot filtering and assignment. From fca6faa3a81188fbaa2fff28f3e859a2102f4c51 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 30 May 2025 20:51:04 +0200 Subject: [PATCH 44/50] xx --- Moose Development/Moose/Ops/PlayerTask.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index ce95f00a4..7c912235f 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -21,7 +21,7 @@ -- === -- @module Ops.PlayerTask -- @image OPS_PlayerTask.jpg --- @date Last Update April 2025 +-- @date Last Update May 2025 do @@ -98,7 +98,7 @@ PLAYERTASK = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.26" +PLAYERTASK.version="0.1.27" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -1951,7 +1951,7 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) self.taskinfomenu = false self.activehasinfomenu = false self.MenuName = nil - self.menuitemlimit = 5 + self.menuitemlimit = 6 self.holdmenutime = 30 self.MarkerReadOnly = false @@ -2581,7 +2581,7 @@ function PLAYERTASKCONTROLLER:SetMenuOptions(InfoMenu,ItemLimit,HoldTime) if self.activehasinfomenu then self:EnableTaskInfoMenu() end - self.menuitemlimit = ItemLimit or 5 + self.menuitemlimit = ItemLimit+1 or 6 self.holdmenutime = HoldTime or 30 return self end @@ -3486,7 +3486,7 @@ end -- @param #PLAYERTASKCONTROLLER self -- @param Ops.PlayerTask#PLAYERTASK PlayerTask -- @param #boolean Silent If true, make no "has new task" announcement --- @param #boolen TaskFilter If true, apply the white/black-list task filters here, also +-- @param #boolean TaskFilter If true, apply the white/black-list task filters here, also -- @return #PLAYERTASKCONTROLLER self -- @usage -- Example to create a PLAYERTASK of type CTLD and give Players 10 minutes to complete: From f5881eda533a97bae379e3b5d5b81cd6895fa0d1 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 1 Jun 2025 12:19:42 +0200 Subject: [PATCH 45/50] AIRBOSS - Remove useless E Messages for non-debug --- Moose Development/Moose/Ops/Airboss.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 5e6f70443..d6d7b03a7 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -8741,13 +8741,13 @@ function AIRBOSS:OnEventRemoveUnit( EventData ) -- Nil checks. if EventData == nil then - self:E( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end if EventData.IniUnit == nil then - self:E( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end From 95767c5ef45ebfdb97423c5461a4da519de6eb2a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 1 Jun 2025 12:20:08 +0200 Subject: [PATCH 46/50] AIRBOSS - Remove useless E Messages for non-debug --- Moose Development/Moose/Ops/Airboss.lua | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index f95a9ab7c..d6d7b03a7 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -3091,8 +3091,7 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum self.SRS:SetVolume(Volume or 1) --self.SRS:SetModulations(Modulations) if GoogleCreds then - self.SRS:SetProviderOptionsGoogle(GoogleCreds,GoogleCreds) - self.SRS:SetProvider(MSRS.Provider.GOOGLE) + self.SRS:SetGoogle(GoogleCreds) end if Voice then self.SRS:SetVoice(Voice) @@ -3642,7 +3641,6 @@ function AIRBOSS:onafterStart( From, Event, To ) self:HandleEvent( EVENTS.PlayerLeaveUnit, self._PlayerLeft ) self:HandleEvent( EVENTS.MissionEnd ) self:HandleEvent( EVENTS.RemoveUnit ) - self:HandleEvent( EVENTS.UnitLost, self.OnEventRemoveUnit ) -- self.StatusScheduler=SCHEDULER:New(self) -- self.StatusScheduler:Schedule(self, self._Status, {}, 1, 0.5) @@ -8743,13 +8741,13 @@ function AIRBOSS:OnEventRemoveUnit( EventData ) -- Nil checks. if EventData == nil then - self:E( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end if EventData.IniUnit == nil then - self:E( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) - self:E( EventData ) + self:T( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" ) + self:T( EventData ) return end From eeeeda4e5e1550bf2c1b2aaaebe347b93b4eb48f Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 8 Jun 2025 18:43:01 +0200 Subject: [PATCH 47/50] #POINT - Offset options for smoke --- Moose Development/Moose/Core/Point.lua | 89 ++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 35ad76b4c..a74356985 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -59,6 +59,10 @@ do -- COORDINATE -- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange. -- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white. -- * @{#COORDINATE.SmokeGreen}(): To smoke the point in green. + -- * @{#COORDINATE.SetSmokeOffsetDirection}(): To set an offset point direction for smoke. + -- * @{#COORDINATE.SetSmokeOffsetDistance}(): To set an offset point distance for smoke. + -- * @{#COORDINATE.SwitchSmokeOffsetOn}(): To set an offset point for smoke to on. + -- * @{#COORDINATE.SwitchSmokeOffsetOff}(): To set an offset point for smoke to off. -- -- ## 2.2) Flare -- @@ -2124,21 +2128,32 @@ do -- COORDINATE -- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min. -- @param #number Delay (Optional) Delay before the smoke is started in seconds. -- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins) + -- @param #boolean Offset (Optional) If true, offset the smokle a bit. + -- @param #number Direction (Optional) If Offset is true this is the direction of the offset, 1-359 (degrees). Default random. + -- @param #number Distance (Optional) If Offset is true this is the distance of the offset in meters. Default random 10-20. -- @return #COORDINATE self - function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name) - self:F2( { SmokeColor, Name, Duration, Delay } ) + function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name, Offset,Direction,Distance) + self:F2( { SmokeColor, Name, Duration, Delay, Offset } ) SmokeColor=SmokeColor or SMOKECOLOR.Green if Delay and Delay>0 then - self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name) + self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name, Direction,Distance) else -- Create a name which is used to stop the smoke manually self.firename = Name or "Smoke-"..math.random(1,100000) -- Create smoke - trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + if Offset or self.SmokeOffset then + local Angle = Direction or self:GetSmokeOffsetDirection() + local Distance = Distance or self:GetSmokeOffsetDistance() + local newpos = self:Translate(Distance,Angle,true,false) + local newvec3 = newpos:GetVec3() + trigger.action.smoke( newvec3, SmokeColor, self.firename ) + else + trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename ) + end -- Stop smoke if Duration and Duration>0 then @@ -2148,6 +2163,72 @@ do -- COORDINATE return self end + + --- Get the offset direction when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #number Direction in degrees. + function COORDINATE:GetSmokeOffsetDirection() + local direction = self.SmokeOffsetDirection or math.random(1,359) + return direction + end + + --- Set the offset direction when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @param #number Direction (Optional) This is the direction of the offset, 1-359 (degrees). Default random. + -- @return #COORDINATE self + function COORDINATE:SetSmokeOffsetDirection(Direction) + if self then + self.SmokeOffsetDirection = Direction or math.random(1,359) + return self + else + COORDINATE.SmokeOffsetDirection = Direction or math.random(1,359) + end + end + + --- Get the offset distance when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #number Distance Distance in meters. + function COORDINATE:GetSmokeOffsetDistance() + local distance = self.SmokeOffsetDistance or math.random(10,20) + return distance + end + + --- Set the offset distance when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @param #number Distance (Optional) This is the distance of the offset in meters. Default random 10-20. + -- @return #COORDINATE self + function COORDINATE:SetSmokeOffsetDistance(Distance) + if self then + self.SmokeOffsetDistance = Distance or math.random(10,20) + return self + else + COORDINATE.SmokeOffsetDistance = Distance or math.random(10,20) + end + end + + --- Set the offset on when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #COORDINATE self + function COORDINATE:SwitchSmokeOffsetOn() + if self then + self.SmokeOffset = true + return self + else + COORDINATE.SmokeOffset = true + end + end + + --- Set the offset off when using `COORDINATE:Smoke()`. + -- @param #COORDINATE self + -- @return #COORDINATE self + function COORDINATE:SwitchSmokeOffsetOff() + if self then + self.SmokeOffset = false + return self + else + COORDINATE.SmokeOffset = false + end + end --- Stops smoking the point in a color. -- @param #COORDINATE self From 26565d75499478c6d387f3aa7bfa8f173c8fa297 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 10 Jun 2025 09:25:00 +0200 Subject: [PATCH 48/50] #EASYGCICAP - Added noob/fatfinger checks for airbase static warehouses and CAP point airwing names --- Moose Development/Moose/Ops/EasyGCICAP.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/EasyGCICAP.lua b/Moose Development/Moose/Ops/EasyGCICAP.lua index 943518b2e..89a3198d2 100644 --- a/Moose Development/Moose/Ops/EasyGCICAP.lua +++ b/Moose Development/Moose/Ops/EasyGCICAP.lua @@ -261,7 +261,7 @@ EASYGCICAP = { --- EASYGCICAP class version. -- @field #string version -EASYGCICAP.version="0.1.21" +EASYGCICAP.version="0.1.22" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -582,6 +582,13 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias) local DespawnAfterLanding = self.DespawnAfterLanding local DespawnAfterHolding = self.DespawnAfterHolding + -- Check STATIC name + local check = STATIC:FindByName(Airbasename,false) + if check == nil then + MESSAGE:New(self.lid.."There's no warehouse static on the map (wrong naming?) for airbase "..tostring(Airbasename).."!",30,"CHECK"):ToAllIf(self.debug):ToLog() + return + end + -- Create Airwing local CAP_Wing = AIRWING:New(Airbasename,Alias) CAP_Wing:SetVerbosityLevel(0) @@ -816,6 +823,11 @@ function EASYGCICAP:_SetCAPPatrolPoints() self:T(self.lid.."_SetCAPPatrolPoints") for _,_data in pairs(self.ManagedCP) do local data = _data --#EASYGCICAP.CapPoint + self:T("Airbasename = "..data.AirbaseName) + if not self.wings[data.AirbaseName] then + 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 Coordinate = data.Coordinate local Altitude = data.Altitude From 0aeb1fc6afc2c3e2fcab252f43925d44b11dd0e7 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 10 Jun 2025 18:05:02 +0200 Subject: [PATCH 49/50] #UTILS - Small fix for GetReportingName to distinguish Shark from Mainstay --- Moose Development/Moose/Utilities/Utils.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 19e6889b3..f0c7b4aaf 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -1913,6 +1913,13 @@ end function UTILS.GetReportingName(Typename) local typename = string.lower(Typename) + + -- special cases - Shark and Manstay have "A-50" in the name + if string.find(typename,"ka-50",1,true) then + return "Shark" + elseif string.find(typename,"a-50",1,true) then + return "Mainstay" + end for name, value in pairs(ENUMS.ReportingName.NATO) do local svalue = string.lower(value) From 2a9a7db9b8f6c74786bbbd64dd517b9d84250d56 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 10 Jun 2025 21:58:19 +0200 Subject: [PATCH 50/50] OPSGROUP - Improved behaviour when mission is unpaused and groups are teleported --- Moose Development/Moose/Ops/Auftrag.lua | 2 ++ Moose Development/Moose/Ops/FlightGroup.lua | 3 +++ Moose Development/Moose/Ops/OpsGroup.lua | 7 +++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index fb4d0adbe..c6df7238c 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1403,6 +1403,8 @@ function AUFTRAG:NewINTERCEPT(Target) end --- **[AIR]** Create a CAP mission. +-- Assinged groups are tasked to execute a CAP mission. This consists of a DCS orbit task combined with an enroute "search and engage in zone" task. +-- **Note** that currently DCS only supports *circular* zones for the task. -- @param #AUFTRAG self -- @param Core.Zone#ZONE_RADIUS ZoneCAP Circular CAP zone. Detected targets in this zone will be engaged. -- @param #number Altitude Altitude at which to orbit in feet. Default is 10,000 ft. diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 81a19cd80..41b2fb35a 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -2002,6 +2002,9 @@ function FLIGHTGROUP:onafterElementAirborne(From, Event, To, Element) -- Debug info. self:T2(self.lid..string.format("Element airborne %s", Element.name)) + + -- Set parking spot to free. Also for FC. This is usually done after taxiing but doing it here in case the group is teleported. + self:_SetElementParkingFree(Element) -- Set element status. self:_UpdateStatus(Element, OPSGROUP.ElementStatus.AIRBORNE) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 268dfd008..0a62c204e 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -5589,10 +5589,13 @@ function OPSGROUP:onafterUnpauseMission(From, Event, To) -- Debug info. self:T(self.lid..string.format("Unpausing mission %s [%s]", mission:GetName(), mission:GetType())) + -- Set state of mission, e.g. for not teleporting again + mission.unpaused=true + -- Start mission. self:MissionStart(mission) - -- Remove mission from + -- Remove mission from pausedmissions queue for i,mid in pairs(self.pausedmissions) do --self:T(self.lid..string.format("Checking paused mission", mid)) if mid==mission.auftragsnummer then @@ -6232,7 +6235,7 @@ function OPSGROUP:RouteToMission(mission, delay) end -- Check if group is mobile. Note that some immobile units report a speed of 1 m/s = 3.6 km/h. - if self.speedMax<=3.6 or mission.teleport then + if (self.speedMax<=3.6 or mission.teleport) and not mission.unpaused then -- Teleport to waypoint coordinate. Mission will not be paused. self:Teleport(waypointcoord, nil, true)