From dcfce8b619fe582254d88ce30d35d1868ba433fa Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 7 Dec 2022 18:50:22 +0100 Subject: [PATCH 01/33] #CTLD - enforce modulation on beacons --- Moose Development/Moose/Ops/CTLD.lua | 47 +++++++++++++++++++--------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 61ff3edbf..4dabfddd4 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1015,7 +1015,16 @@ CTLD = { -- @type CTLD.ZoneBeacon -- @field #string name -- Name of zone for the coordinate -- @field #number frequency -- in mHz --- @field #number modulation -- i.e.radio.modulation.FM or radio.modulation.AM +-- @field #number modulation -- i.e.CTLD.RadioModulation.FM or CTLD.RadioModulation.AM + +--- Radio Modulation +-- @type CTLD.RadioModulation +-- @field #number AM +-- @field #number FM +CTLD.RadioModulation = { + AM = 0, + FM = 1, +} --- Zone Info. -- @type CTLD.CargoZone @@ -3440,7 +3449,7 @@ function CTLD:_GetFMBeacon(Name) table.insert(self.UsedFMFrequencies, FM) beacon.name = Name beacon.frequency = FM / 1000000 - beacon.modulation = radio.modulation.FM + beacon.modulation = CTLD.RadioModulation.FM return beacon end @@ -3460,7 +3469,7 @@ function CTLD:_GetUHFBeacon(Name) table.insert(self.UsedUHFFrequencies, UHF) beacon.name = Name beacon.frequency = UHF / 1000000 - beacon.modulation = radio.modulation.AM + beacon.modulation = CTLD.RadioModulation.AM return beacon end @@ -3481,7 +3490,7 @@ function CTLD:_GetVHFBeacon(Name) table.insert(self.UsedVHFFrequencies, VHF) beacon.name = Name beacon.frequency = VHF / 1000000 - beacon.modulation = radio.modulation.FM + beacon.modulation = CTLD.RadioModulation.FM return beacon end @@ -3690,19 +3699,25 @@ function CTLD:_AddRadioBeacon(Name, Sound, Mhz, Modulation, IsShip, IsDropped) local Sound = Sound or "beacon.ogg" if IsDropped and Zone then local ZoneCoord = Zone - local ZoneVec3 = ZoneCoord:GetVec3() + local ZoneVec3 = ZoneCoord:GetVec3(1) local Frequency = string.format("%09d",Mhz * 1000000) -- Freq in Hertz + --local Frequency = Mhz*1000000 local Sound = "l10n/DEFAULT/"..Sound - trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, Frequency, 1000) -- Beacon in MP only runs for 30secs straight - --local status = string.format("***** Beacon added Freq %s Mod %s", Mhz, UTILS.GetModulationName(Modulation)) + --local name = string.format("%s-%f-%s",Zone:GetName(),Mhz,tostring(Modulation)) + --trigger.action.stopRadioTransmission(name) + trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, tonumber(Frequency), 1000) -- Beacon in MP only runs for 30secs straight + --local status = string.format("***** Beacon added Freq %s Mod %s", Frequency, UTILS.GetModulationName(Modulation)) --MESSAGE:New(status,10,"Debug"):ToLogIf(self.debug) elseif Zone then - local ZoneCoord = Zone:GetCoordinate(2) + local ZoneCoord = Zone:GetCoordinate(1) local ZoneVec3 = ZoneCoord:GetVec3() local Frequency = string.format("%09d",Mhz * 1000000) -- Freq in Hertz + --local Frequency = Mhz*1000000 local Sound = "l10n/DEFAULT/"..Sound - trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, Frequency, 1000) -- Beacon in MP only runs for 30secs straight - --local status = string.format("***** Beacon added Freq %s Mod %s", Mhz, UTILS.GetModulationName(Modulation)) + --local name = string.format("%s-%f-%s",Zone:GetName(),Mhz,tostring(Modulation)) + --trigger.action.stopRadioTransmission(name) + trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, tonumber(Frequency), 1000) -- Beacon in MP only runs for 30secs straight + --local status = string.format("***** Beacon added Freq %s Mod %s", Frequency, UTILS.GetModulationName(Modulation)) --MESSAGE:New(status,10,"Debug"):ToLogIf(self.debug) end return self @@ -3730,10 +3745,14 @@ function CTLD:_RefreshRadioBeacons() local Name = czone.name local FM = FMbeacon.frequency -- MHz local VHF = VHFbeacon.frequency -- KHz - local UHF = UHFbeacon.frequency -- MHz - self:_AddRadioBeacon(Name,Sound,FM,radio.modulation.FM, IsShip, IsDropped) - self:_AddRadioBeacon(Name,Sound,VHF,radio.modulation.FM, IsShip, IsDropped) - self:_AddRadioBeacon(Name,Sound,UHF,radio.modulation.AM, IsShip, IsDropped) + local UHF = UHFbeacon.frequency -- MHz + -- local co = coroutine.create(self._AddRadioBeacon) + --coroutine.resume(co, self, Name,Sound,FM,CTLD.RadioModulation.FM, IsShip, IsDropped) + --coroutine.resume(co, self, Name,Sound,VHF,CTLD.RadioModulation.FM, IsShip, IsDropped) + --coroutine.resume(co, self, Name,Sound,UHF,CTLD.RadioModulation.AM, IsShip, IsDropped) + self:_AddRadioBeacon(Name,Sound,FM, CTLD.RadioModulation.FM, IsShip, IsDropped) + self:_AddRadioBeacon(Name,Sound,VHF,CTLD.RadioModulation.FM, IsShip, IsDropped) + self:_AddRadioBeacon(Name,Sound,UHF,CTLD.RadioModulation.AM, IsShip, IsDropped) end end end From cdfb47448f3612167b9e13159be9b9956eecb705 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 7 Dec 2022 18:56:08 +0100 Subject: [PATCH 02/33] #AWACS * Fix setting of CapVoices according to documentation #PLAYERRECCE * Speed up Marker Build #PLAYERTASK * Improve menu build --- Moose Development/Moose/Ops/Awacs.lua | 10 +-- Moose Development/Moose/Ops/PlayerRecce.lua | 5 +- Moose Development/Moose/Ops/PlayerTask.lua | 97 +++++++++++++-------- 3 files changed, 68 insertions(+), 44 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 12ff9b59b..f1f0551d8 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -2,9 +2,7 @@ -- -- === -- --- ## AWACS --- --- * MOOSE AI AWACS Operations using text-to-speech. +-- **AWACS** - MOOSE AI AWACS Operations using text-to-speech. -- -- === -- @@ -499,7 +497,7 @@ do -- @field #AWACS AWACS = { ClassName = "AWACS", -- #string - version = "0.2.49", -- #string + version = "0.2.50", -- #string lid = "", -- #string coalition = coalition.side.BLUE, -- #number coalitiontxt = "blue", -- #string @@ -916,7 +914,7 @@ AWACS.TaskStatus = { --@field #boolean FromAI ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO-List 0.2.42 +-- TODO-List 0.2.50 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- -- DONE - WIP - Player tasking, VID @@ -3470,7 +3468,7 @@ function AWACS:_CheckInAI(FlightGroup,Group,AuftragsNr) local CAPVoice = self.CAPVoice if self.PathToGoogleKey then - CAPVoice = AWACS.CapVoices[math.floor(math.random(1,10))] + CAPVoice = self.CapVoices[math.floor(math.random(1,10))] end FlightGroup:SetSRS(self.PathToSRS,self.CAPGender,self.CAPCulture,CAPVoice,self.Port,self.PathToGoogleKey,"FLIGHT") diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index 0d0ce1166..746fff5e3 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -366,7 +366,10 @@ function PLAYERRECCE:SetReferencePoint(Coordinate,Name) if self.RPMarker then self.RPMarker:Remove() end - local text = string.format("%s RP %s\n%s\n%s\n%s",self.Name,Name,Coordinate:ToStringLLDDM(),Coordinate:ToStringLLDMS(),Coordinate:ToStringMGRS()) + local llddm = Coordinate:ToStringLLDDM() + local lldms = Coordinate:ToStringLLDMS() + local mgrs = Coordinate:ToStringMGRS() + local text = string.format("%s RP %s\n%s\n%s\n%s",self.Name,Name,llddm,lldms,mgrs) self.RPMarker = MARKER:New(Coordinate,text) self.RPMarker:ReadOnly() self.RPMarker:ToCoalition(self.Coalition) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 0f6d95c78..1e38829c0 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -770,7 +770,7 @@ function PLAYERTASK:onafterClientAdded(From, Event, To, Client) self:T({From, Event, To}) if Client and self.verbose then local text = string.format("Player %s joined task %03d!",Client:GetPlayerName() or "Generic",self.PlayerTaskNr) - self:I(self.lid..text) + self:T(self.lid..text) end self.timestamp = timer.getAbsTime() return self @@ -925,6 +925,7 @@ do -- @field #boolean ShowMagnetic Also show magnetic angles -- @field #boolean InfoHasCoordinate -- @field #boolean InfoHasLLDDM +-- @field #table PlayerMenuTag -- @extends Core.Fsm#FSM --- @@ -1232,6 +1233,7 @@ PLAYERTASKCONTROLLER = { PlayerFlashMenu = {}, PlayerJoinMenu = {}, PlayerInfoMenu = {}, + PlayerMenuTag = {}, noflaresmokemenu = false, TransmitOnlyWithPlayers = true, buddylasing = false, @@ -2099,7 +2101,7 @@ function PLAYERTASKCONTROLLER:_GetTasksPerType() self:T(self.lid.."_GetTasksPerType") local tasktypes = self:_GetAvailableTaskTypes() - self:T({tasktypes}) + --self:T({tasktypes}) -- Sort tasks per threat level first local datatable = self.TaskQueue:GetDataTable() @@ -3120,25 +3122,26 @@ end -- @param Core.Menu#MENU_BASE topmenu -- @param #table tasktypes -- @param #table taskpertype +-- @param #string newtag -- @return #table taskinfomenu -function PLAYERTASKCONTROLLER:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype) +function PLAYERTASKCONTROLLER:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype,newtag) self:T(self.lid.."_BuildTaskInfoMenu") local taskinfomenu = nil if self.taskinfomenu then local menutaskinfo = self.gettext:GetEntry("MENUTASKINFO",self.locale) - local taskinfomenu = MENU_GROUP_DELAYED:New(group,menutaskinfo,topmenu) + local taskinfomenu = MENU_GROUP_DELAYED:New(group,menutaskinfo,topmenu):SetTag(newtag) local ittypes = {} local itaskmenu = {} + local tnow = timer.getTime() for _tasktype,_data in pairs(tasktypes) do - ittypes[_tasktype] = MENU_GROUP_DELAYED:New(group,_tasktype,taskinfomenu) + ittypes[_tasktype] = MENU_GROUP_DELAYED:New(group,_tasktype,taskinfomenu):SetTag(newtag) local tasks = taskpertype[_tasktype] or {} local n = 0 for _,_task in pairs(tasks) do _task = _task -- Ops.PlayerTask#PLAYERTASK local pilotcount = _task:CountClients() local newtext = "]" - local tnow = timer.getTime() -- marker for new tasks if tnow - _task.timestamp < 60 then newtext = "*]" @@ -3151,7 +3154,7 @@ function PLAYERTASKCONTROLLER:_BuildTaskInfoMenu(group,client,playername,topmenu text = string.format("%s (%03d) [%d%s",name,_task.PlayerTaskNr,pilotcount,newtext) end end - local taskentry = MENU_GROUP_COMMAND_DELAYED:New(group,text,ittypes[_tasktype],self._ActiveTaskInfo,self,group,client,_task) + local taskentry = MENU_GROUP_COMMAND_DELAYED:New(group,text,ittypes[_tasktype],self._ActiveTaskInfo,self,group,client,_task):SetTag(newtag) --taskentry:SetTag(playername) itaskmenu[#itaskmenu+1] = taskentry -- keep max items limit @@ -3191,6 +3194,11 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) local group = client:GetGroup() local unknown = self.gettext:GetEntry("UNKNOWN",self.locale) local playername = client:GetPlayerName() or unknown + + local oldtag = self.PlayerMenuTag[playername] + local newtag = playername..timer.getAbsTime() + self.PlayerMenuTag[playername] = newtag + if group and client then --- -- TOPMENU @@ -3202,6 +3210,8 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) if self:_CheckPlayerHasTask(playername) and not fromsuccess then playerhastask = true end local topmenu = nil + --local oldmenu = nil + local rebuilddone = false self:T("Playerhastask = "..tostring(playerhastask).." Enforced = "..tostring(enforced).." Join or Abort = "..tostring(joinorabort)) @@ -3215,16 +3225,20 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) -- 2)+3) Join or abort? if joinorabort then self.PlayerMenu[playername]:RemoveSubMenus() - self.PlayerMenu[playername]:SetTag(timer.getAbsTime()) + self.PlayerMenu[playername]:SetTag(newtag) topmenu = self.PlayerMenu[playername] elseif (not playerhastask) or enforced then -- 4) last build > 30 secs? local T0 = timer.getAbsTime() - local TDiff = T0-self.PlayerMenu[playername].MenuTag + local TDiff = T0-self.PlayerMenu[playername].PTTimeStamp self:T("TDiff = "..string.format("%.2d",TDiff)) if TDiff >= self.holdmenutime then - self.PlayerMenu[playername]:RemoveSubMenus() - self.PlayerMenu[playername]:SetTag(timer.getAbsTime()) + --self.PlayerMenu[playername]:RemoveSubMenus() + --oldmenu = self.PlayerMenu[playername] + --self.PlayerMenu[playername] = nil + self.PlayerMenu[playername] = MENU_GROUP_DELAYED:New(group,menuname,self.MenuParent) + self.PlayerMenu[playername]:SetTag(newtag) + self.PlayerMenu[playername].PTTimeStamp = timer.getAbsTime() timedbuild = true end topmenu = self.PlayerMenu[playername] @@ -3233,14 +3247,17 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) -- 1) new player# topmenu = MENU_GROUP_DELAYED:New(group,menuname,self.MenuParent) self.PlayerMenu[playername] = topmenu - self.PlayerMenu[playername]:SetTag(timer.getAbsTime()) + self.PlayerMenu[playername]:SetTag(newtag) + self.PlayerMenu[playername].PTTimeStamp = timer.getAbsTime() + enforced = true end --- -- ACTIVE TASK MENU --- if playerhastask and enforced then - --self:T("Building Active Task Menus for "..playername) + self:T("Building Active Task Menus for "..playername) + rebuilddone = true local menuactive = self.gettext:GetEntry("MENUACTIVE",self.locale) local menuinfo = self.gettext:GetEntry("MENUINFO",self.locale) local menumark = self.gettext:GetEntry("MENUMARK",self.locale) @@ -3248,44 +3265,45 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) local menuflare = self.gettext:GetEntry("MENUFLARE",self.locale) local menuabort = self.gettext:GetEntry("MENUABORT",self.locale) - local active = MENU_GROUP_DELAYED:New(group,menuactive,topmenu) - local info = MENU_GROUP_COMMAND_DELAYED:New(group,menuinfo,active,self._ActiveTaskInfo,self,group,client) - local mark = MENU_GROUP_COMMAND_DELAYED:New(group,menumark,active,self._MarkTask,self,group,client) + local active = MENU_GROUP_DELAYED:New(group,menuactive,topmenu):SetTag(newtag) + local info = MENU_GROUP_COMMAND_DELAYED:New(group,menuinfo,active,self._ActiveTaskInfo,self,group,client):SetTag(newtag) + local mark = MENU_GROUP_COMMAND_DELAYED:New(group,menumark,active,self._MarkTask,self,group,client):SetTag(newtag) if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then if self.noflaresmokemenu ~= true then -- no smoking/flaring here if A2A or designer has set noflaresmokemenu to true - local smoke = MENU_GROUP_COMMAND_DELAYED:New(group,menusmoke,active,self._SmokeTask,self,group,client) - local flare = MENU_GROUP_COMMAND_DELAYED:New(group,menuflare,active,self._FlareTask,self,group,client) + local smoke = MENU_GROUP_COMMAND_DELAYED:New(group,menusmoke,active,self._SmokeTask,self,group,client):SetTag(newtag) + local flare = MENU_GROUP_COMMAND_DELAYED:New(group,menuflare,active,self._FlareTask,self,group,client):SetTag(newtag) local IsNight = client:GetCoordinate():IsNight() if IsNight then - local light = MENU_GROUP_COMMAND_DELAYED:New(group,menuflare,active,self._IlluminateTask,self,group,client) + local light = MENU_GROUP_COMMAND_DELAYED:New(group,menuflare,active,self._IlluminateTask,self,group,client):SetTag(newtag) end end end - local abort = MENU_GROUP_COMMAND_DELAYED:New(group,menuabort,active,self._AbortTask,self,group,client) + local abort = MENU_GROUP_COMMAND_DELAYED:New(group,menuabort,active,self._AbortTask,self,group,client):SetTag(newtag) if self.activehasinfomenu and self.taskinfomenu then - --self:T("Building Active-Info Menus for "..playername) + self:T("Building Active-Info Menus for "..playername) local tasktypes = self:_GetAvailableTaskTypes() local taskpertype = self:_GetTasksPerType() if self.PlayerInfoMenu[playername] then - self.PlayerInfoMenu[playername]:RemoveSubMenus() + self.PlayerInfoMenu[playername]:RemoveSubMenus(nil,oldtag) end - self.PlayerInfoMenu[playername] = self:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype) + self.PlayerInfoMenu[playername] = self:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype,newtag) end elseif (self.TaskQueue:Count() > 0 and enforced) or (not playerhastask and (timedbuild or joinorabort)) then - --self:T("Building Join Menus for "..playername) + self:T("Building Join Menus for "..playername) + rebuilddone = true --- -- JOIN TASK MENU --- local tasktypes = self:_GetAvailableTaskTypes() local taskpertype = self:_GetTasksPerType() local menujoin = self.gettext:GetEntry("MENUJOIN",self.locale) - local joinmenu = MENU_GROUP_DELAYED:New(group,menujoin,topmenu) + local joinmenu = MENU_GROUP_DELAYED:New(group,menujoin,topmenu):SetTag(newtag) local ttypes = {} local taskmenu = {} for _tasktype,_data in pairs(tasktypes) do - ttypes[_tasktype] = MENU_GROUP_DELAYED:New(group,_tasktype,joinmenu) + ttypes[_tasktype] = MENU_GROUP_DELAYED:New(group,_tasktype,joinmenu):SetTag(newtag) local tasks = taskpertype[_tasktype] or {} local n = 0 for _,_task in pairs(tasks) do @@ -3305,7 +3323,7 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) text = string.format("%s (%03d) [%d%s",name,_task.PlayerTaskNr,pilotcount,newtext) end end - local taskentry = MENU_GROUP_COMMAND_DELAYED:New(group,text,ttypes[_tasktype],self._JoinTask,self,group,client,_task) + local taskentry = MENU_GROUP_COMMAND_DELAYED:New(group,text,ttypes[_tasktype],self._JoinTask,self,group,client,_task):SetTag(newtag) --taskentry:SetTag(playername) taskmenu[#taskmenu+1] = taskentry n = n + 1 @@ -3315,25 +3333,30 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) end end if self.taskinfomenu then - --self:T("Building Join-Info Menus for "..playername) + self:T("Building Join-Info Menus for "..playername) if self.PlayerInfoMenu[playername] then - self.PlayerInfoMenu[playername]:RemoveSubMenus() + self.PlayerInfoMenu[playername]:RemoveSubMenus(nil,oldtag) end - self.PlayerInfoMenu[playername] = self:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype) + self.PlayerInfoMenu[playername] = self:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype,newtag) end - elseif self.TaskQueue:Count() == 0 then - -- no tasks (yet) + end + if self.AllowFlash then + local flashtext = self.gettext:GetEntry("FLASHMENU",self.locale) + local flashmenu = MENU_GROUP_COMMAND_DELAYED:New(group,flashtext,topmenu,self._SwitchFlashing,self,group,client):SetTag(newtag) + end + if self.TaskQueue:Count() == 0 then + self:T("No open tasks info") local menunotasks = self.gettext:GetEntry("MENUNOTASKS",self.locale) - local joinmenu = MENU_GROUP_DELAYED:New(group,menunotasks,topmenu) + local joinmenu = MENU_GROUP_DELAYED:New(group,menunotasks,self.PlayerMenu[playername]):SetTag(newtag) + rebuilddone = true end --- -- REFRESH MENU --- - if self.AllowFlash then - local flashtext = self.gettext:GetEntry("FLASHMENU",self.locale) - local flashmenu = MENU_GROUP_COMMAND_DELAYED:New(group,flashtext,self.PlayerMenu[playername],self._SwitchFlashing,self,group,client) + if rebuilddone then + self.PlayerMenu[playername]:RemoveSubMenus(nil,oldtag) + self.PlayerMenu[playername]:Refresh() end - self.PlayerMenu[playername]:Set() end end end From 8eef039312519c87cbd92d3f79a7ac2f335dbc41 Mon Sep 17 00:00:00 2001 From: phr0gz Date: Thu, 8 Dec 2022 13:15:07 +0100 Subject: [PATCH 03/33] New CAP auftrag (#1850) Add Ability to CAP escort Ground group or helo with a new auftrag: AUFTRAG:NewCAPGROUP --- Moose Development/Moose/Ops/Auftrag.lua | 56 +++++++++++++++++++++ Moose Development/Moose/Ops/FlightGroup.lua | 2 +- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index d5e62aab1..fa2d49679 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1312,6 +1312,62 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ return mission end +--- **[AIRPANE]** Create a CAP on group mission. +-- @param #AUFTRAG self +-- @param Wrapper.Group#GROUP group. +-- @param #number Altitude Orbit altitude in feet. Default is 6,000 ft. +-- @param #number Speed Orbit speed in knots. Default 250 KIAS. +-- @param #number Leg Length of race-track in NM. Default 14 NM. +-- @param #number RelHeading Relative heading [0, 360) of race-track pattern in degrees wrt heading of the carrier. Default is heading of the carrier. +-- @param #number OffsetDist Relative distance of the first race-track point wrt to the carrier. Default 6 NM. +-- @param #number OffsetAngle Relative angle of the first race-track point wrt. to the carrier. Default 180 (behind the boat). +-- @param #number UpdateDistance Threshold distance in NM before orbit pattern is updated. Default 5 NM. +-- @param #table TargetTypes (Optional) Table of target types. Default `{"Helicopters", "Ground Units", "Light armed ships"}`. +-- @param #number EngageRange Max range in nautical miles that the escort group(s) will engage enemies. Default 32 NM (60 km). +-- @return #AUFTRAG self +function AUFTRAG:NewCAPGROUP(Grp, Altitude, Speed, RelHeading, Leg, OffsetDist, OffsetAngle, UpdateDistance, TargetTypes, EngageRange) + + -- Ensure given TargetTypes parameter is a table. + if TargetTypes then + if type(TargetTypes)~="table" then + TargetTypes={TargetTypes} + end + end + -- Six NM astern. + local OffsetVec2={r=OffsetDist or 6, phi=OffsetAngle or 180} + + -- Default leg. + Leg=Leg or 14 + + local Heading=nil + if RelHeading then + Heading=-math.abs(RelHeading) + end + + -- Create orbit mission. + local mission=AUFTRAG:NewORBIT_GROUP(Grp, Altitude, Speed, Leg, Heading, OffsetVec2, UpdateDistance) + -- Mission type CAP. + mission.type=AUFTRAG.Type.CAP + mission:_SetLogID() + + -- DCS task parameters: + local engage = EngageRange or 32 + local zoneCAPGroup = ZONE_GROUP:New("CAPGroup", Grp, UTILS.NMToMeters(engage)) + mission.engageZone=zoneCAPGroup + mission.engageTargetTypes=TargetTypes or {"Air"} + + -- Mission options: + mission.missionTask=ENUMS.MissionTask.CAP + mission.optionROE=ENUMS.ROE.OpenFire + mission.optionROT=ENUMS.ROT.EvadeFire + + mission.categories={AUFTRAG.Category.AIRCRAFT} + + mission.DCStask=mission:GetDCSMissionTask() + + return mission +end + --- **[AIR]** Create a CAS mission. -- @param #AUFTRAG self -- @param Core.Zone#ZONE_RADIUS ZoneCAS Circular CAS zone. Detected targets in this zone will be engaged. diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 3d43ee67f..3087195f6 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -908,7 +908,7 @@ function FLIGHTGROUP:Status() if mission and mission.updateDCSTask then -- Orbit missions might need updates. - if (mission:GetType()==AUFTRAG.Type.ORBIT or mission:GetType()==AUFTRAG.Type.RECOVERYTANKER) and mission.orbitVec2 then + if (mission:GetType()==AUFTRAG.Type.ORBIT or mission:GetType()==AUFTRAG.Type.RECOVERYTANKER or mission:GetType()==AUFTRAG.Type.CAP) and mission.orbitVec2 then -- Get 2D vector of orbit target. local vec2=mission:GetTargetVec2() From 84d301c67662965fc05b6a4ad278166b8c04d816 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 9 Dec 2022 12:37:39 +0100 Subject: [PATCH 04/33] #CTLD * Added disallow building in loadzones: my_ctld.nobuildinloadzones = true --- Moose Development/Moose/Ops/CTLD.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 4dabfddd4..62c0a445b 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -711,6 +711,7 @@ do -- my_ctld.droppedbeacontimeout = 600 -- dropped beacon lasts 10 minutes -- my_ctld.usesubcats = false -- use sub-category names for crates, adds an extra menu layer in "Get Crates", useful if you have > 10 crate types. -- my_ctld.placeCratesAhead = false -- place crates straight ahead of the helicopter, in a random way. If true, crates are more neatly sorted. +-- my_ctld.nobuildinloadzones = true -- forbid players to build stuff in LOAD zones if set to `true` -- -- ## 2.1 User functions -- @@ -1087,7 +1088,7 @@ CTLD.UnitTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.20" +CTLD.version="1.0.21" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1252,6 +1253,9 @@ function CTLD:New(Coalition, Prefixes, Alias) self.usesubcats = false self.subcats = {} + -- disallow building in loadzones + self.nobuildinloadzones = true + local AliaS = string.gsub(self.alias," ","_") self.filename = string.format("CTLD_%s_Persist.csv",AliaS) @@ -2102,10 +2106,10 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop) self.CargoCounter = self.CargoCounter + 1 local realcargo = nil if drop then - realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,subcat) + realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,nil,subcat) table.insert(droppedcargo,realcargo) else - realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,subcat) + realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],false,cargotype.PerCrateMass,nil,subcat) Cargo:RemoveStock() end table.insert(self.Spawned_Cargo, realcargo) @@ -2833,6 +2837,14 @@ function CTLD:_BuildCrates(Group, Unit,Engineering) return self end end + if not Engineering and self.nobuildinloadzones then + -- are we in a load zone? + local inloadzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) + if inloadzone then + self:_SendMessage("You cannot build in a loading area, Pilot!", 10, false, Group) + return self + end + end -- get nearby crates local finddist = self.CrateDistance or 35 local crates,number = self:_FindCratesNearby(Group,Unit, finddist,true) -- #table From 324739aeb9b7f61c346cabc6b0e102d257a43433 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 11 Dec 2022 15:49:50 +0100 Subject: [PATCH 05/33] #SET * Improve GetRandom() a bit --- Moose Development/Moose/Core/Set.lua | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index f3b227e24..41c0b1501 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -179,7 +179,7 @@ do -- SET_BASE return Names end - --- Return a table of the Objects in the Set. + --- Returns a table of the Objects in the Set. -- @param #SET_BASE self -- @return #SET_BASE self function SET_BASE:GetSetObjects() -- R2.3 @@ -376,7 +376,6 @@ do -- SET_BASE -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetFirst() - local ObjectName = self.Index[1] local FirstObject = self.Set[ObjectName] self:T3( { FirstObject } ) @@ -387,8 +386,8 @@ do -- SET_BASE -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetLast() - - local ObjectName = self.Index[#self.Index] + local tablemax = table.maxn(self.Index) + local ObjectName = self.Index[tablemax] local LastObject = self.Set[ObjectName] self:T3( { LastObject } ) return LastObject @@ -398,8 +397,8 @@ do -- SET_BASE -- @param #SET_BASE self -- @return Core.Base#BASE function SET_BASE:GetRandom() - - local RandomItem = self.Set[self.Index[math.random( #self.Index )]] + local tablemax = table.maxn(self.Index) + local RandomItem = self.Set[self.Index[math.random(1,tablemax)]] self:T3( { RandomItem } ) return RandomItem end @@ -408,8 +407,7 @@ do -- SET_BASE -- @param #SET_BASE self -- @return #number Count function SET_BASE:Count() - - return self.Index and #self.Index or 0 + return self.Index and table.maxn(self.Index) or 0 end --- Copies the Filter criteria from a given Set (for rebuilding a new Set based on an existing Set). @@ -6800,7 +6798,7 @@ do -- SET_SCENERY if ZoneSet then for _,_zone in pairs(ZoneSet.Set) do - --self:I("Zone type handed: "..tostring(_zone.ClassName)) + self:T("Zone type handed: "..tostring(_zone.ClassName)) table.insert(zonenames,_zone:GetName()) end self:AddSceneryByName(zonenames) @@ -6814,7 +6812,7 @@ do -- SET_SCENERY -- @param Core.Zone#ZONE Zone The zone to be scanned. Can be a ZONE_RADIUS (round) or a ZONE_POLYGON (e.g. Quad-Point) -- @return #SET_SCENERY function SET_SCENERY:NewFromZone(Zone) - local zone = Zone -- Core.Zone#ZONE_POLYGON + local zone = Zone -- Core.Zone#ZONE_RADIUS if type(Zone) == "string" then zone = ZONE:FindByName(Zone) end From 75d8d556914585167099f7ceb633e833908ec040 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 11 Dec 2022 15:50:36 +0100 Subject: [PATCH 06/33] #AWACS * Skip Task Assignement Menus if PlayerCapAssignement is false --- Moose Development/Moose/Ops/Awacs.lua | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index f1f0551d8..657d4aca6 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -17,7 +17,7 @@ -- === -- -- ### Author: **applevangelist** --- @date Last Update November 2022 +-- @date Last Update December 2022 -- @module Ops.AWACS -- @image OPS_AWACS.jpg @@ -104,7 +104,7 @@ do -- @field #boolean NoGroupTags Set to true if you don't want group tags. -- @field #boolean SuppressScreenOutput Set to true to suppress all screen output. -- @field #boolean NoMissileCalls Suppress missile callouts --- @field #boolean PlayerCapAssigment Assign players to CAP tasks when they are logged on +-- @field #boolean PlayerCapAssignment Assign players to CAP tasks when they are logged on -- @field #number GoogleTTSPadding -- @field #number WindowsTTSPadding -- @field #boolean AllowMarkers @@ -356,7 +356,7 @@ do -- testawacs.maxassigndistance = 100 -- Don't assign targets further out than this, in NM. -- testawacs.debug = false -- set to true to produce more log output. -- testawacs.NoMissileCalls = true -- suppress missile callouts --- testawacs.PlayerCapAssigment = true -- no intercept task assignments for players +-- testawacs.PlayerCapAssignment = true -- no intercept task assignments for players -- testawacs.invisible = false -- set AWACS to be invisible to hostiles -- testawacs.immortal = false -- set AWACS to be immortal -- -- By default, the radio queue is checked every 10 secs. This is altered by the calculated length of the sentence to speak @@ -578,7 +578,7 @@ AWACS = { NoMissileCalls = true, GoogleTTSPadding = 1, WindowsTTSPadding = 2.5, - PlayerCapAssigment = true, + PlayerCapAssignment = true, AllowMarkers = false, PlayerStationName = nil, GCI = false, @@ -1123,7 +1123,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station self.MenuStrict = true self.maxassigndistance = 100 --nm self.NoMissileCalls = true - self.PlayerCapAssigment = true + self.PlayerCapAssignment = true -- managed groups self.ManagedGrps = {} -- #table of #AWACS.ManagedGroup entries @@ -3587,13 +3587,15 @@ function AWACS:_SetClientMenus() local bogeydope = MENU_GROUP_COMMAND:New(cgrp,"Bogey Dope",basemenu,self._BogeyDope,self,cgrp) local picture = MENU_GROUP_COMMAND:New(cgrp,"Picture",basemenu,self._Picture,self,cgrp) local declare = MENU_GROUP_COMMAND:New(cgrp,"Declare",basemenu,self._Declare,self,cgrp) - local tasking = MENU_GROUP:New(cgrp,"Tasking",basemenu) local showtask = MENU_GROUP_COMMAND:New(cgrp,"Showtask",tasking,self._Showtask,self,cgrp) - local commit = MENU_GROUP_COMMAND:New(cgrp,"Commit",tasking,self._Commit,self,cgrp) - local unable = MENU_GROUP_COMMAND:New(cgrp,"Unable",tasking,self._Unable,self,cgrp) - local abort = MENU_GROUP_COMMAND:New(cgrp,"Abort",tasking,self._TaskAbort,self,cgrp) - --local judy = MENU_GROUP_COMMAND:New(cgrp,"Judy",tasking,self._Judy,self,cgrp) + + if self.PlayerCapAssignment then + local commit = MENU_GROUP_COMMAND:New(cgrp,"Commit",tasking,self._Commit,self,cgrp) + local unable = MENU_GROUP_COMMAND:New(cgrp,"Unable",tasking,self._Unable,self,cgrp) + local abort = MENU_GROUP_COMMAND:New(cgrp,"Abort",tasking,self._TaskAbort,self,cgrp) + --local judy = MENU_GROUP_COMMAND:New(cgrp,"Judy",tasking,self._Judy,self,cgrp) + end if self.AwacsROE == AWACS.ROE.POLICE or self.AwacsROE == AWACS.ROE.VID then local vid = MENU_GROUP:New(cgrp,"VID as",tasking) @@ -5957,7 +5959,7 @@ function AWACS:onafterStatus(From, Event, To) local AI, Humans = self:_GetIdlePilots() -- assign Pilot if there are targets and available Pilots, prefer Humans to AI -- DONE - Implemented AI First, Humans laters - need to work out how to loop the targets to assign a pilot - if outcome and #Humans > 0 and self.PlayerCapAssigment then + if outcome and #Humans > 0 and self.PlayerCapAssignment then -- add a task for AI self:_AssignPilotToTarget(Humans,targets) end From 77e7f767d82d1da286ce7cff0937db1af7f8778b Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 12 Dec 2022 16:23:47 +0100 Subject: [PATCH 07/33] #AIRBASE * docu correction --- Moose Development/Moose/Wrapper/Airbase.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index a2fd0577a..cb8e35175 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -839,7 +839,7 @@ end -- Black listed spots overrule white listed spots. -- **NOTE** that terminal IDs are not necessarily the same as those displayed in the mission editor! -- @param #AIRBASE self --- @param #table TerminalIdBlacklist Table of white listed terminal IDs. +-- @param #table TerminalIdWhitelist Table of white listed terminal IDs. -- @return #AIRBASE self -- @usage AIRBASE:FindByName("Batumi"):SetParkingSpotWhitelist({2, 3, 4}) --Only allow terminal IDs 2, 3, 4 function AIRBASE:SetParkingSpotWhitelist(TerminalIdWhitelist) From 696569f749aa11a2fabb955f216f6922feec0cec Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 12 Dec 2022 16:24:25 +0100 Subject: [PATCH 08/33] #PLAYERTASK * Added typename combos as option for menu entries --- Moose Development/Moose/Ops/PlayerTask.lua | 88 +++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 1e38829c0..b6fae66a1 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -57,6 +57,7 @@ do -- @field #table NextTaskSuccess -- @field #table NextTaskFailure -- @field #string FinalState +-- @field #string TypeName -- @extends Core.Fsm#FSM @@ -926,6 +927,7 @@ do -- @field #boolean InfoHasCoordinate -- @field #boolean InfoHasLLDDM -- @field #table PlayerMenuTag +-- @field #boolean UseTypeNames -- @extends Core.Fsm#FSM --- @@ -1112,6 +1114,13 @@ do -- BRIEFING = "Briefing", -- TARGETLOCATION ="Target location", -- COORDINATE = "Coordinate", +-- INFANTRY = "Infantry", +-- TECHNICAL = "Technical", +-- ARTILLERY = "Artillery", +-- TANKS = "Tanks", +-- AIRDEFENSE = "Airdefense", +-- SAM = "SAM", +-- GROUP = "Group", -- }, -- -- e.g. @@ -1243,6 +1252,7 @@ PLAYERTASKCONTROLLER = { ShowMagnetic = true, InfoHasLLDDM = false, InfoHasCoordinate = false, + UseTypeNames = false, } --- @@ -1341,6 +1351,13 @@ PLAYERTASKCONTROLLER.Messages = { BRIEFING = "Briefing", TARGETLOCATION ="Target location", COORDINATE = "Coordinate", + INFANTRY = "Infantry", + TECHNICAL = "Technical", + ARTILLERY = "Artillery", + TANKS = "Tanks", + AIRDEFENSE = "Airdefense", + SAM = "SAM", + GROUP = "Group", }, DE = { TASKABORT = "Auftrag abgebrochen!", @@ -1406,12 +1423,19 @@ PLAYERTASKCONTROLLER.Messages = { BRIEFING = "Briefing", TARGETLOCATION ="Zielposition", COORDINATE = "Koordinate", + INFANTRY = "Infantrie", + TECHNICAL = "Technische", + ARTILLERY = "Artillerie", + TANKS = "Panzer", + AIRDEFENSE = "Flak", + SAM = "Luftabwehr", + GROUP = "Einheit", }, } --- PLAYERTASK class version. -- @field #string version -PLAYERTASKCONTROLLER.version="0.1.51" +PLAYERTASKCONTROLLER.version="0.1.52" --- Create and run a new TASKCONTROLLER instance. -- @param #PLAYERTASKCONTROLLER self @@ -1469,6 +1493,8 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) self.noflaresmokemenu = false self.ShowMagnetic = true + + self.UseTypeNames = false if ClientFilter then self.ClientSet = SET_CLIENT:New():FilterCoalitions(string.lower(self.CoalitionName)):FilterActive(true):FilterPrefixes(ClientFilter):FilterStart() @@ -1607,6 +1633,24 @@ function PLAYERTASKCONTROLLER:_InitLocalization() return self end +--- [User] Show target menu entries of type names for GROUND targets (off by default!), e.g. "Tank Group..." +-- @param #PLAYERTASKCONTROLLER self +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:SetEnableUseTypeNames() + self:T(self.lid.."SetEnableUseTypeNames") + self.UseTypeNames = true + return self +end + +--- [User] Do not show target menu entries of type names for GROUND targets +-- @param #PLAYERTASKCONTROLLER self +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:SetDisableUseTypeNames() + self:T(self.lid.."SetDisableUseTypeNames") + self.UseTypeNames = false + return self +end + --- [User] Set flash directions option for player (player based info) -- @param #PLAYERTASKCONTROLLER self -- @param #boolean OnOff Set to `true` to switch on and `false` to switch off. Default is OFF. @@ -2134,7 +2178,7 @@ end function PLAYERTASKCONTROLLER:_CheckTargetQueue() self:T(self.lid.."_CheckTargetQueue") if self.TargetQueue:Count() > 0 then - local object = self.TargetQueue:Pull() + local object = self.TargetQueue:Pull() -- Wrapper.Positionable#POSITIONABLE local target = TARGET:New(object) if object.menuname then target.menuname = object.menuname @@ -2142,6 +2186,38 @@ function PLAYERTASKCONTROLLER:_CheckTargetQueue() target.freetext = object.freetext end end + + if self.UseTypeNames and object:IsGround() then + -- * Threat level 0: Unit is unarmed. + -- * Threat level 1: Unit is infantry. + -- * Threat level 2: Unit is an infantry vehicle. + -- * Threat level 3: Unit is ground artillery. + -- * Threat level 4: Unit is a tank. + -- * Threat level 5: Unit is a modern tank or ifv with ATGM. + -- * Threat level 6: Unit is a AAA. + -- * Threat level 7: Unit is a SAM or manpad, IR guided. + -- * Threat level 8: Unit is a Short Range SAM, radar guided. + -- * Threat level 9: Unit is a Medium Range SAM, radar guided. + -- * Threat level 10: Unit is a Long Range SAM, radar guided. + local threat = object:GetThreatLevel() + local typekey = "INFANTRY" + if threat == 0 or threat == 2 then + typekey = "TECHNICAL" + elseif threat == 3 then + typekey = "ARTILLERY" + elseif threat == 4 or threat == 5 then + typekey = "TANKS" + elseif threat == 6 or threat == 7 then + typekey = "AIRDEFENSE" + elseif threat >= 8 then + typekey = "SAM" + end + local typename = self.gettext:GetEntry(typekey,self.locale) + local gname = self.gettext:GetEntry("GROUP",self.locale) + target.TypeName = string.format("%s %s",typename,gname) + --self:T(self.lid.."Target TypeName = "..target.TypeName) + end + self:_AddTask(target) end return self @@ -2616,6 +2692,7 @@ function PLAYERTASKCONTROLLER:_AddTask(Target) end task.coalition = self.Coalition + task.TypeName = Target.TypeName if type == AUFTRAG.Type.BOMBRUNWAY then -- task to handle event shot @@ -3154,6 +3231,13 @@ function PLAYERTASKCONTROLLER:_BuildTaskInfoMenu(group,client,playername,topmenu text = string.format("%s (%03d) [%d%s",name,_task.PlayerTaskNr,pilotcount,newtext) end end + if self.UseTypeNames then + if _task.TypeName then + --local name = self.gettext:GetEntry(_task.TypeName,self.locale) + text = string.format("%s (%03d) [%d%s",_task.TypeName,_task.PlayerTaskNr,pilotcount,newtext) + --self:T(self.lid.."Menu text = "..text) + end + end local taskentry = MENU_GROUP_COMMAND_DELAYED:New(group,text,ittypes[_tasktype],self._ActiveTaskInfo,self,group,client,_task):SetTag(newtag) --taskentry:SetTag(playername) itaskmenu[#itaskmenu+1] = taskentry From 089467c15a72a818990a70e798efcbb442be8d1e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 14 Dec 2022 09:41:35 +0100 Subject: [PATCH 09/33] #AI\_A2A\_GCICAP * Fix demo mission link --- Moose Development/Moose/AI/AI_A2A_Dispatcher.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 889ebe631..d0d1a940a 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -3940,11 +3940,7 @@ do -- -- # Demo Missions -- - -- ### [AI\_A2A\_GCICAP for Caucasus](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-200%20-%20AI_A2A%20-%20GCICAP%20Demonstration) - -- ### [AI\_A2A\_GCICAP for NTTR](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-210%20-%20NTTR%20AI_A2A_GCICAP%20Demonstration) - -- ### [AI\_A2A\_GCICAP for Normandy](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching/AID-220%20-%20NORMANDY%20AI_A2A_GCICAP%20Demonstration) - -- - -- ### [AI\_A2A\_GCICAP for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching) + -- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching) -- -- === -- From 178e4ceb7f5fb4e1efabbdfeace55cce023b7639 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 14 Dec 2022 11:42:12 +0100 Subject: [PATCH 10/33] #PLAYERTASKCONTROLLER * Added PLAYERTASKCONTROLLER:AddPlayerTaskToQueue(PlayerTask,Silent,TaskFilter) TaskFilter switch --- Moose Development/Moose/Ops/PlayerTask.lua | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index b6fae66a1..675f69db9 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -1435,7 +1435,7 @@ PLAYERTASKCONTROLLER.Messages = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASKCONTROLLER.version="0.1.52" +PLAYERTASKCONTROLLER.version="0.1.53" --- Create and run a new TASKCONTROLLER instance. -- @param #PLAYERTASKCONTROLLER self @@ -2731,6 +2731,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 -- @return #PLAYERTASKCONTROLLER self -- @usage -- Example to create a PLAYERTASK of type CTLD and give Players 10 minutes to complete: @@ -2751,9 +2752,17 @@ end -- ) -- -- taskmanager:AddPlayerTaskToQueue(PlayerTask) -function PLAYERTASKCONTROLLER:AddPlayerTaskToQueue(PlayerTask,Silent) +function PLAYERTASKCONTROLLER:AddPlayerTaskToQueue(PlayerTask,Silent,TaskFilter) self:T(self.lid.."AddPlayerTaskToQueue") if PlayerTask and PlayerTask.ClassName and PlayerTask.ClassName == "PLAYERTASK" then + if TaskFilter then + if self.UseWhiteList and (not self:_CheckTaskTypeAllowed(PlayerTask.Type)) then + return self + end + if self.UseBlackList and self:_CheckTaskTypeDisallowed(PlayerTask.Type) then + return self + end + end PlayerTask:_SetController(self) PlayerTask:SetCoalition(self.Coalition) self.TaskQueue:Push(PlayerTask) From 1fac6b7c937b205365f630fd65250e27a3c452ee Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 14 Dec 2022 14:48:20 +0100 Subject: [PATCH 11/33] #SET_CLIENT * Added `FilterCallsigns()` and `FilterPlayernames()` --- Moose Development/Moose/Core/Set.lua | 72 +++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 41c0b1501..8785850f3 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -3808,6 +3808,8 @@ do -- SET_CLIENT Countries = nil, ClientPrefixes = nil, Zones = nil, + Playernames = nil, + Callsigns = nil, }, FilterMeta = { Coalitions = { @@ -3880,6 +3882,40 @@ do -- SET_CLIENT return ClientFound end + --- Builds a set of clients of certain callsigns. + -- @param #SET_CLIENT self + -- @param #string Callsigns Can be a single string e.g. "Ford", or a table of strings e.g. {"Uzi","Enfield","Chevy"}. Refers to the callsigns as they can be set in the mission editor. + -- @return #SET_CLIENT self + function SET_CLIENT:FilterCallsigns( Callsigns ) + if not self.Filter.Callsigns then + self.Filter.Callsigns = {} + end + if type( Callsigns ) ~= "table" then + Callsigns = { Callsigns } + end + for callsignID, callsign in pairs( Callsigns ) do + self.Filter.Callsigns[callsign] = callsign + end + return self + end + + --- Builds a set of clients of certain playernames. + -- @param #SET_CLIENT self + -- @param #string Playernames Can be a single string e.g. "Apple", or a table of strings e.g. {"Walter","Hermann","Gonzo"}. Useful if you have e.g. a common squadron prefix. + -- @return #SET_CLIENT self + function SET_CLIENT:FilterPlayernames( Playernames ) + if not self.Filter.Playernames then + self.Filter.Playernames = {} + end + if type( Playernames ) ~= "table" then + Playernames = { Playernames } + end + for PlayernameID, playername in pairs( Playernames ) do + self.Filter.Playernames[playername] = playername + end + return self + end + --- Builds a set of clients of coalitions. -- Possible current coalitions are red, blue and neutral. -- @param #SET_CLIENT self @@ -4235,20 +4271,44 @@ do -- SET_CLIENT self:T( { "Evaluated Prefix", MClientPrefix } ) MClientInclude = MClientInclude and MClientPrefix end - end if self.Filter.Zones then local MClientZone = false for ZoneName, Zone in pairs( self.Filter.Zones ) do - self:T3( "Zone:", ZoneName ) - local unit = MClient:GetClientGroupUnit() - if unit and unit:IsInZone(Zone) then - MClientZone = true - end + self:T3( "Zone:", ZoneName ) + local unit = MClient:GetClientGroupUnit() + if unit and unit:IsInZone(Zone) then + MClientZone = true + end end MClientInclude = MClientInclude and MClientZone end + if self.Filter.Playernames then + local MClientPlayername = false + local playername = MClient:GetPlayerName() or "Unknown" + for _,_Playername in pairs(self.Filter.Playernames) do + if playername and string.find(playername,_Playername) then + MClientPlayername = true + end + end + self:T( { "Evaluated Playername", MClientPlayername } ) + MClientInclude = MClientInclude and MClientPlayername + end + + if self.Filter.Callsigns then + local MClientCallsigns = false + local callsign = MClient:GetCallsign() + for _,_Callsign in pairs(self.Filter.Callsigns) do + if callsign and string.find(callsign,_Callsign) then + MClientCallsigns = true + end + end + self:T( { "Evaluated Callsign", MClientCallsigns } ) + MClientInclude = MClientInclude and MClientCallsigns + end + + end self:T2( MClientInclude ) return MClientInclude end From d5028d86dffa671804e7aa77800d23a8ebbd2fae Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 Dec 2022 11:49:28 +0100 Subject: [PATCH 12/33] #SET_CLIENT * small addition --- Moose Development/Moose/Core/Set.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 8785850f3..a3c404bbe 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4203,9 +4203,10 @@ do -- SET_CLIENT if self.Filter.Active ~= nil then local MClientActive = false - if self.Filter.Active == false or (self.Filter.Active == true and MClient:IsActive() == true) then + if self.Filter.Active == false or (self.Filter.Active == true and MClient:IsActive() == true and MClient:IsAlive() == true) then MClientActive = true end + --self:I( { "Evaluated Active", MClientActive } ) MClientInclude = MClientInclude and MClientActive end @@ -4287,6 +4288,7 @@ do -- SET_CLIENT if self.Filter.Playernames then local MClientPlayername = false local playername = MClient:GetPlayerName() or "Unknown" + --self:I(playername) for _,_Playername in pairs(self.Filter.Playernames) do if playername and string.find(playername,_Playername) then MClientPlayername = true @@ -4299,6 +4301,7 @@ do -- SET_CLIENT if self.Filter.Callsigns then local MClientCallsigns = false local callsign = MClient:GetCallsign() + --self:I(callsign) for _,_Callsign in pairs(self.Filter.Callsigns) do if callsign and string.find(callsign,_Callsign) then MClientCallsigns = true From a3fd583d9d80f796cc85af1da9e6cb17b1d4c51f Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 Dec 2022 11:50:05 +0100 Subject: [PATCH 13/33] #PLAYERTASK * additions for multiple setups --- Moose Development/Moose/Ops/PlayerTask.lua | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 675f69db9..08468cb48 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -1435,14 +1435,14 @@ PLAYERTASKCONTROLLER.Messages = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASKCONTROLLER.version="0.1.53" +PLAYERTASKCONTROLLER.version="0.1.54" --- Create and run a new TASKCONTROLLER instance. -- @param #PLAYERTASKCONTROLLER self -- @param #string Name Name of this controller -- @param #number Coalition of this controller, e.g. coalition.side.BLUE -- @param #string Type Type of the tasks controlled, defaults to PLAYERTASKCONTROLLER.Type.A2G --- @param #string ClientFilter (optional) Additional prefix filter for the SET_CLIENT +-- @param #string ClientFilter (optional) Additional prefix filter for the SET_CLIENT. Can be handed as @{Core.Set#SET_CLIENT} also. -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) @@ -1495,10 +1495,18 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) self.ShowMagnetic = true self.UseTypeNames = false + + local IsClientSet = false + + if ClientFilter and type(ClientFilter) == "table" and ClientFilter.ClassName and ClientFilter.ClassName == "SET_CLIENT" then + -- we have a predefined SET_CLIENT + self.ClientSet = ClientFilter + IsClientSet = true + end - if ClientFilter then + if ClientFilter and not IsClientSet then self.ClientSet = SET_CLIENT:New():FilterCoalitions(string.lower(self.CoalitionName)):FilterActive(true):FilterPrefixes(ClientFilter):FilterStart() - else + elseif not IsClientSet then self.ClientSet = SET_CLIENT:New():FilterCoalitions(string.lower(self.CoalitionName)):FilterActive(true):FilterStart() end @@ -2007,6 +2015,9 @@ function PLAYERTASKCONTROLLER:_EventHandler(EventData) end elseif EventData.id == EVENTS.PlayerEnterAircraft and EventData.IniCoalition == self.Coalition then if EventData.IniPlayerName and EventData.IniGroup and self.UseSRS then + if self.ClientSet:IsNotInSet(CLIENT:FindByName(EventData.IniUnitName)) then + return self + end self:T(self.lid.."Event for player: "..EventData.IniPlayerName) local frequency = self.Frequency local freqtext = "" @@ -3282,7 +3293,7 @@ function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) end for _,_client in pairs(clients) do - if _client then + if _client and _client:IsAlive() then local client = _client -- Wrapper.Client#CLIENT local group = client:GetGroup() local unknown = self.gettext:GetEntry("UNKNOWN",self.locale) @@ -3768,7 +3779,7 @@ function PLAYERTASKCONTROLLER:onafterStatus(From, Event, To) self:_BuildMenus(nil,enforcedmenu) if self.verbose then - local text = string.format("New Targets: %02d | Active Tasks: %02d | Active Players: %02d | Assigned Tasks: %02d",targetcount,taskcount,playercount,assignedtasks) + local text = string.format("%s | New Targets: %02d | Active Tasks: %02d | Active Players: %02d | Assigned Tasks: %02d",self.MenuName, targetcount,taskcount,playercount,assignedtasks) self:I(text) end From 80e3b157caf51f99e161e9e632ac81a308ede594 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 15 Dec 2022 18:28:06 +0100 Subject: [PATCH 14/33] #UTILS * UTILS.LoadSetOfStatics(Path,Filename) ignore statics which do not exist --- Moose Development/Moose/Utilities/Utils.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index dd073f753..0e3b3d37d 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -2414,11 +2414,14 @@ function UTILS.LoadSetOfStatics(Path,Filename) local dataset = UTILS.Split(_entry,",") -- staticname,position.x,position.y,position.z local staticname = dataset[1] - local posx = tonumber(dataset[2]) - local posy = tonumber(dataset[3]) - local posz = tonumber(dataset[4]) - local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) - datatable:AddObject(STATIC:FindByName(staticname,false)) + --local posx = tonumber(dataset[2]) + --local posy = tonumber(dataset[3]) + --local posz = tonumber(dataset[4]) + --local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) + local StaticObject = STATIC:FindByName(staticname,false) + if StaticObject then + datatable:AddObject(StaticObject) + end end else return nil From fea1839c06a7608182a465a1852800a07e3b43bb Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 16 Dec 2022 18:43:50 +0100 Subject: [PATCH 15/33] #AIRBASE * Added Rio Chico Airfield --- 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 cb8e35175..bb355c1a6 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -510,6 +510,7 @@ AIRBASE.MarianaIslands = { -- * AIRBASE.SouthAtlantic.Porvenir_Airfield -- * AIRBASE.SouthAtlantic.Almirante_Schroeders -- * AIRBASE.SouthAtlantic.Rio_Turbio +-- * AIRBASE.SouthAtlantic.Rio_Chico_Airfield -- --@field MarianaIslands AIRBASE.SouthAtlantic={ @@ -532,6 +533,7 @@ AIRBASE.SouthAtlantic={ ["Porvenir_Airfield"]="Porvenir Airfield", ["Almirante_Schroeders"]="Almirante Schroeders", ["Rio_Turbio"]="Rio Turbio", + ["Rio_Chico"] = "Rio Chico", } --- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy". From 6e26e7eac322e4b49d2f718e5fb645931977a20a Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 19 Dec 2022 13:08:35 +0100 Subject: [PATCH 16/33] #AUFTRAG * Fix for orbit racetrack missing coordinate object --- Moose Development/Moose/Ops/Auftrag.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index fa2d49679..c05fa5a4c 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -6087,7 +6087,7 @@ function AUFTRAG:GetDCSMissionTask() --end -- Create orbit task. - local DCStask=CONTROLLABLE.TaskOrbit(nil, COORDINATE:NewFromVec2(orbitVec2), self.orbitAltitude, self.orbitSpeed, orbitRaceTrack) + local DCStask=CONTROLLABLE.TaskOrbit(nil, COORDINATE:NewFromVec2(orbitVec2), self.orbitAltitude, self.orbitSpeed, COORDINATE:NewFromVec2(orbitRaceTrack)) -- Add DCS task. table.insert(DCStasks, DCStask) From 5010cdff71b1467642719406104384e7db1dd69d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 19 Dec 2022 14:04:30 +0100 Subject: [PATCH 17/33] #CTLD * Fix to also save crates which have not been moved --- Moose Development/Moose/Ops/CTLD.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 62c0a445b..17149318d 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1088,7 +1088,7 @@ CTLD.UnitTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.21" +CTLD.version="1.0.22" --- Instantiate a new CTLD. -- @param #CTLD self @@ -2106,6 +2106,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop) self.CargoCounter = self.CargoCounter + 1 local realcargo = nil if drop then + --CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory) realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,nil,subcat) table.insert(droppedcargo,realcargo) else @@ -4778,7 +4779,7 @@ end for _,_cargo in pairs (stcstable) do local cargo = _cargo -- #CTLD_CARGO local object = cargo:GetPositionable() -- Wrapper.Static#STATIC - if object and object:IsAlive() and cargo:WasDropped() then + if object and object:IsAlive() and (cargo:WasDropped() or not cargo:HasMoved()) then statics[#statics+1] = cargo end end From 8df6e2dd57400d3d252d1da6eb3c7c1dc7cd44c2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 19 Dec 2022 16:12:04 +0100 Subject: [PATCH 18/33] #UNIT * Improve GetGroup() as after Dec/22 patch geGroup() might be nil # SET_UNIT * Improved Docu --- Moose Development/Moose/Core/Set.lua | 7 +------ Moose Development/Moose/Wrapper/Unit.lua | 25 ++++++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index a3c404bbe..cf370d4ce 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1952,12 +1952,7 @@ do -- SET_UNIT -- * @{#SET_UNIT.ForEachUnit}: Calls a function for each alive unit it finds within the SET_UNIT. -- * @{#SET_UNIT.ForEachUnitInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence completely in a @{Core.Zone}, providing the UNIT object and optional parameters to the called function. -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate the SET_UNIT and call an iterator function for each **alive** UNIT object presence not in a @{Core.Zone}, providing the UNIT object and optional parameters to the called function. - -- - -- Planned iterators methods in development are (so these are not yet available): - -- - -- * @{#SET_UNIT.ForEachUnitInUnit}: Calls a function for each unit contained within the SET_UNIT. - -- * @{#SET_UNIT.ForEachUnitCompletelyInZone}: Iterate and call an iterator function for each **alive** UNIT presence completely in a @{Core.Zone}, providing the UNIT and optional parameters to the called function. - -- * @{#SET_UNIT.ForEachUnitNotInZone}: Iterate and call an iterator function for each **alive** UNIT presence not in a @{Core.Zone}, providing the UNIT and optional parameters to the called function. + -- * @{#SET_UNIT:ForEachUnitPerThreatLevel}: Iterate the SET_UNIT **sorted *per Threat Level** and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters -- -- ## 5) SET_UNIT atomic methods -- diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 59474de9c..11326a4a6 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -629,22 +629,27 @@ end --- Returns the unit's group if it exist and nil otherwise. -- @param Wrapper.Unit#UNIT self -- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist. +--- Returns the unit's group if it exists and nil otherwise. +-- @param Wrapper.Unit#UNIT self +-- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist. function UNIT:GetGroup() - self:F2( self.UnitName ) - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitGroup = GROUP:FindByName( DCSUnit:getGroup():getName() ) + self:F2( self.UnitName ) + local UnitGroup = GROUP:FindByName(self.GroupName) + if UnitGroup then return UnitGroup + else + local DCSUnit = self:GetDCSObject() + if DCSUnit then + local grp = DCSUnit:getGroup() + if grp then + local UnitGroup = GROUP:FindByName( grp:getName() ) + return UnitGroup + end + end end - return nil end - --- Need to add here functions to check if radar is on and which object etc. - --- Returns the prefix name of the DCS Unit. A prefix name is a part of the name before a '#'-sign. -- DCS Units spawned with the @{Core.Spawn#SPAWN} class contain a '#'-sign to indicate the end of the (base) DCS Unit name. -- The spawn sequence number and unit number are contained within the name after the '#' sign. From 79e99dcb388839a062c75f9a41152c2064ec5867 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 20 Dec 2022 16:05:50 +0100 Subject: [PATCH 19/33] #PLAYERTASK * Added `GetTarget()` --- Moose Development/Moose/Ops/PlayerTask.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 08468cb48..3485cd4c1 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -96,7 +96,7 @@ PLAYERTASK = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASK.version="0.1.10" +PLAYERTASK.version="0.1.11" --- Generic task condition. -- @type PLAYERTASK.Condition @@ -285,6 +285,14 @@ function PLAYERTASK:GetCoalition() return self.coalition end +--- [User] Get the Ops.Target#TARGET object for this task +-- @param #PLAYERTASK self +-- @return Ops.Target#TARGET Target +function PLAYERTASK:GetTarget() + self:T(self.lid.."GetTarget") + return self.Target +end + --- [USER] Add a free text description to this task. -- @param #PLAYERTASK self -- @param #string Text From b501eec3065937b3de71a4ceeb83b6051795d720 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 20 Dec 2022 18:18:24 +0100 Subject: [PATCH 20/33] #AUFTRAG * Fix Orbit w&w/o racetrack --- Moose Development/Moose/Ops/Auftrag.lua | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index c05fa5a4c..52904d0ec 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -6075,20 +6075,15 @@ function AUFTRAG:GetDCSMissionTask() -- Race-track vector. orbitRaceTrack=UTILS.Vec2Translate(orbitVec2, self.orbitLeg, heading) end - - -- Debug - --UTILS.RemoveMark(self.orbitCenterMarkID) - --self.orbitCenterMarkID=COORDINATE:NewFromVec2(orbitVec2):MarkToAll("Orbit Center") - - -- Debug show arrow. - --if orbitRaceTrack then - --UTILS.RemoveMark(self.orbitArrowMarkID) - --self.orbitArrowMarkID=COORDINATE:NewFromVec2(orbitVec2):ArrowToAll(COORDINATE:NewFromVec2(orbitRaceTrack)) - --end + + local orbitRaceTrackCoord = nil + if orbitRaceTrack then + orbitRaceTrackCoord = COORDINATE:NewFromVec2(orbitRaceTrack) + end -- Create orbit task. - local DCStask=CONTROLLABLE.TaskOrbit(nil, COORDINATE:NewFromVec2(orbitVec2), self.orbitAltitude, self.orbitSpeed, COORDINATE:NewFromVec2(orbitRaceTrack)) - + local DCStask=CONTROLLABLE.TaskOrbit(nil, COORDINATE:NewFromVec2(orbitVec2), self.orbitAltitude, self.orbitSpeed, orbitRaceTrackCoord) + -- Add DCS task. table.insert(DCStasks, DCStask) From ef5ea01bc195531b09d68c1bee3d832f7dfa8af5 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 Dec 2022 12:53:08 +0100 Subject: [PATCH 21/33] #TARGET * Fixes for Scenery and Static Objects --- Moose Development/Moose/Ops/Target.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index 012eb7542..96b96715b 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -617,7 +617,7 @@ function TARGET:onafterStatus(From, Event, To) -- Log output verbose=1. if self.verbose>=1 then local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.N0, self:GetLife(), self:GetLife0(), self:GetDamage()) - if self:CountTargets() == 0 then + if self:CountTargets() == 0 or self:GetDamage() >= 100 then text=text.." Dead!" elseif damaged then text=text.." Damaged!" @@ -636,7 +636,7 @@ function TARGET:onafterStatus(From, Event, To) self:I(self.lid..text) end - if self:CountTargets() == 0 then + if self:CountTargets() == 0 or self:GetDamage() >= 100 then self:Dead() end @@ -935,6 +935,9 @@ function TARGET:_AddObject(Object) target.Coordinate=scenery:GetCoordinate() target.Life0=scenery:GetLife0() + + if target.Life0==0 then target.Life0 = 1 end + target.Life=scenery:GetLife() target.N0=target.N0+1 @@ -1071,7 +1074,9 @@ function TARGET:GetTargetLife(Target) elseif Target.Type==TARGET.ObjectType.STATIC then if Target.Object and Target.Object:IsAlive() then - return 1 + local life=Target.Object:GetLife() + return life + --return 1 else return 0 end From 6f0ba337c400f1ce1644bad501cb59f401ddee0e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 Dec 2022 12:55:01 +0100 Subject: [PATCH 22/33] #SET_SCENERY * Added GetAliveSet() --- Moose Development/Moose/Core/Set.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index cf370d4ce..82a7d65a5 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -6990,7 +6990,29 @@ do -- SET_SCENERY return CountU end + + --- Get a table of alive objects. + -- @param #SET_GROUP self + -- @return #table Table of alive objects + -- @return Core.Set#SET_SCENERY SET of alive objects + function SET_SCENERY:GetAliveSet() + self:F2() + local AliveSet = SET_SCENERY:New() + + -- Clean the Set before returning with only the alive Groups. + for GroupName, GroupObject in pairs( self.Set ) do + local GroupObject = GroupObject -- Wrapper.Group#GROUP + if GroupObject then + if GroupObject:IsAlive() then + AliveSet:Add( GroupName, GroupObject ) + end + end + end + + return AliveSet.Set or {}, AliveSet + end + --- Iterate the SET_SCENERY and call an iterator function for each **alive** SCENERY, providing the SCENERY and optional parameters. -- @param #SET_SCENERY self -- @param #function IteratorFunction The function that will be called when there is an alive SCENERY in the SET_SCENERY. The function needs to accept a SCENERY parameter. From 4a299ea53ff7fbf5991cef6bc777d4856d0956f5 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 Dec 2022 14:05:58 +0100 Subject: [PATCH 23/33] #CTLD * Added option to inject troops into helos --- Moose Development/Moose/Ops/CTLD.lua | 69 ++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 17149318d..4b90a90f5 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1088,7 +1088,7 @@ CTLD.UnitTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.22" +CTLD.version="1.0.23" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1648,12 +1648,54 @@ function CTLD:_SendMessage(Text, Time, Clearscreen, Group) return self end +--- (Internal) Find a troops CTLD_CARGO object in stock +-- @param #CTLD self +-- @param #string Name of the object +-- @return #CTLD_CARGO Cargo object, nil if it cannot be found +function CTLD:_FindTroopsCargoObject(Name) + self:T(self.lid .. " _FindTroopsCargoObject") + local cargo = nil + for _,_cargo in pairs(self.Cargo_Troops)do + local cargo = _cargo -- #CTLD_CARGO + if cargo.Name == Name then + return cargo + end + end + return nil +end + +--- (User) Pre-load troops into a helo, e.g. for airstart. Unit **must** be alive in-game, i.e. player has taken the slot! +-- @param #CTLD self +-- @param Wrapper.Unit#UNIT Unit The unit to load into, can be handed as Wrapper.Client#CLIENT object +-- @param #string Troopname The name of the Troops to be loaded. Must be created prior in the CTLD setup! +-- @return #CTLD self +-- @usage +-- local client = UNIT:FindByName("Helo-1-1") +-- if client and client:IsAlive() then +-- myctld:PreloadTroops(client,"Infantry") +-- end +function CTLD:PreloadTroops(Unit,Troopname) + self:T(self.lid .. " PreloadTroops") + local name = Troopname or "Unknown" + if Unit and Unit:IsAlive() then + local cargo = self:_FindTroopsCargoObject(name) + local group = Unit:GetGroup() + if cargo then + self:_LoadTroops(group,Unit,cargo,true) + else + self:E(self.lid.." Troops preload - Cargo Object "..name.." not found!") + end + end + return self +end + --- (Internal) Function to load troops into a heli. -- @param #CTLD self -- @param Wrapper.Group#GROUP Group -- @param Wrapper.Unit#UNIT Unit -- @param #CTLD_CARGO Cargotype -function CTLD:_LoadTroops(Group, Unit, Cargotype) +-- @param #boolean Inject +function CTLD:_LoadTroops(Group, Unit, Cargotype, Inject) self:T(self.lid .. " _LoadTroops") -- check if we have stock local instock = Cargotype:GetStock() @@ -1661,7 +1703,7 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype) local cgotype = Cargotype:GetType() local cgonetmass = Cargotype:GetNetMass() local maxloadable = self:_GetMaxLoadableMass(Unit) - if type(instock) == "number" and tonumber(instock) <= 0 and tonumber(instock) ~= -1 then + if type(instock) == "number" and tonumber(instock) <= 0 and tonumber(instock) ~= -1 and not Inject then -- nothing left over self:_SendMessage(string.format("Sorry, all %s are gone!", cgoname), 10, false, Group) return self @@ -1669,21 +1711,22 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype) -- landed or hovering over load zone? local grounded = not self:IsUnitInAir(Unit) local hoverload = self:CanHoverLoad(Unit) - --local dooropen = UTILS.IsLoadingDoorOpen(Unit:GetName()) and self.pilotmustopendoors -- check if we are in LOAD zone local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) if not inzone then inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP) end - if not inzone then - self:_SendMessage("You are not close enough to a logistics zone!", 10, false, Group) - if not self.debug then return self end - elseif not grounded and not hoverload then - self:_SendMessage("You need to land or hover in position to load!", 10, false, Group) - if not self.debug then return self end - elseif self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then - self:_SendMessage("You need to open the door(s) to load troops!", 10, false, Group) - if not self.debug then return self end + if not Inject then + if not inzone then + self:_SendMessage("You are not close enough to a logistics zone!", 10, false, Group) + if not self.debug then return self end + elseif not grounded and not hoverload then + self:_SendMessage("You need to land or hover in position to load!", 10, false, Group) + if not self.debug then return self end + elseif self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then + self:_SendMessage("You need to open the door(s) to load troops!", 10, false, Group) + if not self.debug then return self end + end end -- load troops into heli local group = Group -- Wrapper.Group#GROUP From f26ff52712f8d98af471733b4f872520b45a258c Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Wed, 21 Dec 2022 14:09:47 +0100 Subject: [PATCH 24/33] #UNIT * Docu fix --- Moose Development/Moose/Wrapper/Unit.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 11326a4a6..8cf7c9226 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -629,9 +629,6 @@ end --- Returns the unit's group if it exist and nil otherwise. -- @param Wrapper.Unit#UNIT self -- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist. ---- Returns the unit's group if it exists and nil otherwise. --- @param Wrapper.Unit#UNIT self --- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist. function UNIT:GetGroup() self:F2( self.UnitName ) local UnitGroup = GROUP:FindByName(self.GroupName) From 535060153a3bf227ccf541e24448c20f612f47d8 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Fri, 23 Dec 2022 13:39:00 +0100 Subject: [PATCH 25/33] CTLD #1851 Add variable for a sound path (#1852) CTLD #1851 Add variable for a sound path - defaults to `self.RadioPath = "l10n/DEFAULT/"` --- Moose Development/Moose/Ops/CTLD.lua | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 4b90a90f5..d70a0a17f 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -1088,7 +1088,7 @@ CTLD.UnitTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.23" +CTLD.version="1.0.24" --- Instantiate a new CTLD. -- @param #CTLD self @@ -1171,6 +1171,7 @@ function CTLD:New(Coalition, Prefixes, Alias) -- radio beacons self.RadioSound = "beacon.ogg" + self.RadioPath = "l10n/DEFAULT/" -- zones stuff self.pickupZones = {} @@ -3757,24 +3758,14 @@ function CTLD:_AddRadioBeacon(Name, Sound, Mhz, Modulation, IsShip, IsDropped) local ZoneCoord = Zone local ZoneVec3 = ZoneCoord:GetVec3(1) local Frequency = string.format("%09d",Mhz * 1000000) -- Freq in Hertz - --local Frequency = Mhz*1000000 - local Sound = "l10n/DEFAULT/"..Sound - --local name = string.format("%s-%f-%s",Zone:GetName(),Mhz,tostring(Modulation)) - --trigger.action.stopRadioTransmission(name) + local Sound = self.RadioPath..Sound trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, tonumber(Frequency), 1000) -- Beacon in MP only runs for 30secs straight - --local status = string.format("***** Beacon added Freq %s Mod %s", Frequency, UTILS.GetModulationName(Modulation)) - --MESSAGE:New(status,10,"Debug"):ToLogIf(self.debug) elseif Zone then local ZoneCoord = Zone:GetCoordinate(1) local ZoneVec3 = ZoneCoord:GetVec3() local Frequency = string.format("%09d",Mhz * 1000000) -- Freq in Hertz - --local Frequency = Mhz*1000000 - local Sound = "l10n/DEFAULT/"..Sound - --local name = string.format("%s-%f-%s",Zone:GetName(),Mhz,tostring(Modulation)) - --trigger.action.stopRadioTransmission(name) + local Sound = self.RadioPath..Sound trigger.action.radioTransmission(Sound, ZoneVec3, Modulation, false, tonumber(Frequency), 1000) -- Beacon in MP only runs for 30secs straight - --local status = string.format("***** Beacon added Freq %s Mod %s", Frequency, UTILS.GetModulationName(Modulation)) - --MESSAGE:New(status,10,"Debug"):ToLogIf(self.debug) end return self end From 9619b11c58a9ef67982daa312bd30199924d008d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 23 Dec 2022 13:42:08 +0100 Subject: [PATCH 26/33] #CTLD * add sound folder path option --- Moose Development/Moose/Ops/CTLD.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index d70a0a17f..677c810e8 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -3770,6 +3770,31 @@ function CTLD:_AddRadioBeacon(Name, Sound, Mhz, Modulation, IsShip, IsDropped) return self end +--- Set folder path where the CTLD sound files are located **within you mission (miz) file**. +-- The default path is "l10n/DEFAULT/" but sound files simply copied there will be removed by DCS the next time you save the mission. +-- However, if you create a new folder inside the miz file, which contains the sounds, it will not be deleted and can be used. +-- @param #CTLD self +-- @param #string FolderPath The path to the sound files, e.g. "CTLD_Soundfiles/". +-- @return #CTLD self +function CTLD:SetSoundfilesFolder( FolderPath ) + self:T(self.lid .. " SetSoundfilesFolder") + -- Check that it ends with / + if FolderPath then + local lastchar = string.sub( FolderPath, -1 ) + if lastchar ~= "/" then + FolderPath = FolderPath .. "/" + end + end + + -- Folderpath. + self.RadioPath = FolderPath + + -- Info message. + self:I( self.lid .. string.format( "Setting sound files folder to: %s", self.RadioPath ) ) + + return self +end + --- (Internal) Function to refresh radio beacons -- @param #CTLD self function CTLD:_RefreshRadioBeacons() From f1e0bacadbdaddef40a0c46315dede79c90683ad Mon Sep 17 00:00:00 2001 From: phr0gz Date: Fri, 23 Dec 2022 13:44:38 +0100 Subject: [PATCH 27/33] CAPGROUP (#1853) Fix help typo --- Moose Development/Moose/Ops/Auftrag.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Auftrag.lua b/Moose Development/Moose/Ops/Auftrag.lua index 52904d0ec..9f4fe0d93 100644 --- a/Moose Development/Moose/Ops/Auftrag.lua +++ b/Moose Development/Moose/Ops/Auftrag.lua @@ -1312,13 +1312,13 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ return mission end ---- **[AIRPANE]** Create a CAP on group mission. +--- **[AIR]** Create a CAP mission on a group. -- @param #AUFTRAG self --- @param Wrapper.Group#GROUP group. +-- @param Wrapper.Group#GROUP Grp. -- @param #number Altitude Orbit altitude in feet. Default is 6,000 ft. -- @param #number Speed Orbit speed in knots. Default 250 KIAS. --- @param #number Leg Length of race-track in NM. Default 14 NM. -- @param #number RelHeading Relative heading [0, 360) of race-track pattern in degrees wrt heading of the carrier. Default is heading of the carrier. +-- @param #number Leg Length of race-track in NM. Default 14 NM. -- @param #number OffsetDist Relative distance of the first race-track point wrt to the carrier. Default 6 NM. -- @param #number OffsetAngle Relative angle of the first race-track point wrt. to the carrier. Default 180 (behind the boat). -- @param #number UpdateDistance Threshold distance in NM before orbit pattern is updated. Default 5 NM. From cd4844d26c58c0566712d9f6343b8442b855e0cd Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 24 Dec 2022 12:03:04 +0100 Subject: [PATCH 28/33] #EVENT * Small fix for hit event on coordinates --- Moose Development/Moose/Core/Event.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 9b334bf2a..595e094f4 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -1224,7 +1224,7 @@ function EVENT:onEvent( Event ) if Event.TgtObjectCategory == Object.Category.STATIC then -- get base data Event.TgtDCSUnit = Event.target - if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object + if Event.target:isExist() and Event.id ~= 33 and not Event.TgtObjectCategory == Object.Category.COORDINATE then -- leave out ejected seat object Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() Event.TgtUnitName = Event.TgtDCSUnitName Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false ) From 9facf07955e4a28b0570d7d49af79bb9c511918e Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Sun, 25 Dec 2022 14:18:53 +0100 Subject: [PATCH 29/33] ATIS - added basic FARP support (#1854) ATIS - added basic FARP support, only works with SRS --- Moose Development/Moose/Ops/ATIS.lua | 169 +++++++++++++++------------ 1 file changed, 93 insertions(+), 76 deletions(-) diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index d4c20f948..e65a2ac71 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -94,6 +94,7 @@ -- @field #boolean ReportmBar Report mBar/hpa even if not metric, i.e. for Mirage flights -- @field #boolean TransmitOnlyWithPlayers For SRS - If true, only transmit if there are alive Players. -- @field #string SRSText Text of the complete SRS message (if done at least once, else nil) +-- @field #boolean ATISforFARPs Will be set to true if the base given is a FARP/Helipad -- @extends Core.Fsm#FSM --- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde @@ -309,6 +310,19 @@ -- atis:Start() -- -- This uses a male voice with US accent. It requires SRS to be installed in the `D:\DCS\_SRS\` directory. Not that backslashes need to be escaped or simply use slashes (as in linux). +-- +-- ## FARPS +-- +-- ATIS is working with FARPS, but this requires the usage of SRS. The airbase name for the `New()-method` is the UNIT name of the FARP: +-- +-- atis = ATIS:New("FARP Gold",119,radio.modulation.AM) +-- atis:SetMetricUnits() +-- atis:SetTransmitOnlyWithPlayers(true) +-- atis:SetReportmBar(true) +-- atis:SetTowerFrequencies(127.50) +-- atis:SetSRS("D:\\DCS\\_SRS\\", "male", "en-US",nil,5002) +-- atis:SetAdditionalInformation("Welcome to the Jungle!") +-- atis:__Start(3) -- -- @field #ATIS ATIS = { @@ -351,6 +365,7 @@ ATIS = { relHumidity = nil, ReportmBar = false, TransmitOnlyWithPlayers = false, + ATISforFARPs = false, } --- NATO alphabet. @@ -593,7 +608,7 @@ _ATIS = {} --- ATIS class version. -- @field #string version -ATIS.version = "0.9.12" +ATIS.version = "0.9.14" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -1049,7 +1064,7 @@ end -- -- * 186° on the Caucaus map -- * 192° on the Nevada map --- * 170° on the Normany map +-- * 170° on the Normandy map -- * 182° on the Persian Gulf map -- -- Likewise, to convert *true* into *magnetic* heading, one has to substract easterly and add westerly variation. @@ -1257,11 +1272,18 @@ end function ATIS:onafterStart( From, Event, To ) -- Check that this is an airdrome. - if self.airbase:GetAirbaseCategory() ~= Airbase.Category.AIRDROME then - self:E( self.lid .. string.format( "ERROR: Cannot start ATIS for airbase %s! Only AIRDROMES are supported but NOT FARPS or SHIPS.", self.airbasename ) ) + if self.airbase:GetAirbaseCategory() == Airbase.Category.SHIP then + self:E( self.lid .. string.format( "ERROR: Cannot start ATIS for airbase %s! Only AIRDROMES are supported but NOT SHIPS.", self.airbasename ) ) return end - + + -- Check that if is a Helipad. + if self.airbase:GetAirbaseCategory() == Airbase.Category.HELIPAD then + self:E( self.lid .. string.format( "EXPERIMENTAL: Starting ATIS for Helipad %s! SRS must be ON", self.airbasename ) ) + self.ATISforFARPs = true + self.useSRS = true + end + -- Info. self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) ) @@ -1473,10 +1495,19 @@ function ATIS:onafterBroadcast( From, Event, To ) -------------- --- Runway --- -------------- - - local runwayLanding, rwyLandingLeft=self:GetActiveRunway() - local runwayTakeoff, rwyTakeoffLeft=self:GetActiveRunway(true) - + + + local runwayLanding, rwyLandingLeft + local runwayTakeoff, rwyTakeoffLeft + + if self.airbase:GetAirbaseCategory() == Airbase.Category.HELIPAD then + runwayLanding, rwyLandingLeft="PAD 01",false + runwayTakeoff, rwyTakeoffLeft="PAD 02",false + else + runwayLanding, rwyLandingLeft=self:GetActiveRunway() + runwayTakeoff, rwyTakeoffLeft=self:GetActiveRunway(true) + end + ------------ --- Time --- ------------ @@ -1790,7 +1821,7 @@ function ATIS:onafterBroadcast( From, Event, To ) -- Airbase name subtitle = string.format( "%s", self.airbasename ) - if self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil then + if (not self.ATISforFARPs) and self.airbasename:find( "AFB" ) == nil and self.airbasename:find( "Airport" ) == nil and self.airbasename:find( "Airstrip" ) == nil and self.airbasename:find( "airfield" ) == nil and self.airbasename:find( "AB" ) == nil then subtitle = subtitle .. " Airport" end if not self.useSRS then @@ -1865,8 +1896,6 @@ function ATIS:onafterBroadcast( From, Event, To ) end end alltext = alltext .. ";\n" .. subtitle - --self:I("Line 1811") - --self:I(alltext) -- Visibility if self.metric then @@ -1884,8 +1913,6 @@ function ATIS:onafterBroadcast( From, Event, To ) end end alltext = alltext .. ";\n" .. subtitle - --self:I("Line 1830") - --self:I(alltext) subtitle = "" -- Weather phenomena @@ -1987,10 +2014,8 @@ function ATIS:onafterBroadcast( From, Event, To ) end end end - --self:I("Line 1932") alltext = alltext .. ";\n" .. subtitle - --self:I(alltext) subtitle = "" -- Temperature if self.TDegF then @@ -2019,9 +2044,7 @@ function ATIS:onafterBroadcast( From, Event, To ) self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 ) end end - --self:I("Line 1962") alltext = alltext .. ";\n" .. subtitle - --self:I(alltext) -- Dew point if self.TDegF then @@ -2050,8 +2073,6 @@ function ATIS:onafterBroadcast( From, Event, To ) self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 ) end end - --self:I("Line 1992") - --self:I(alltext) alltext = alltext .. ";\n" .. subtitle -- Altimeter QNH/QFE. @@ -2117,69 +2138,68 @@ function ATIS:onafterBroadcast( From, Event, To ) end end end - --self:I("Line 2049") - --self:I(alltext) alltext = alltext .. ";\n" .. subtitle - -- Active runway. - local subtitle=string.format("Active runway %s", runwayLanding) - if rwyLandingLeft==true then - subtitle=subtitle.." Left" - elseif rwyLandingLeft==false then - subtitle=subtitle.." Right" - end - local _RUNACT = subtitle - if not self.useSRS then - self:Transmission(ATIS.Sound.ActiveRunway, 1.0, subtitle) - self.radioqueue:Number2Transmission(runwayLanding) + if not self.ATISforFARPs then + -- Active runway. + local subtitle=string.format("Active runway %s", runwayLanding) if rwyLandingLeft==true then - self:Transmission(ATIS.Sound.Left, 0.2) + subtitle=subtitle.." Left" elseif rwyLandingLeft==false then - self:Transmission(ATIS.Sound.Right, 0.2) + subtitle=subtitle.." Right" end - end - alltext = alltext .. ";\n" .. subtitle - - -- Runway length. - if self.rwylength then - - local runact = self.airbase:GetActiveRunway( self.runwaym2t ) - local length = runact.length - if not self.metric then - length = UTILS.MetersToFeet( length ) - end - - -- Length in thousands and hundrets of ft/meters. - local L1000, L0100 = self:_GetThousandsAndHundreds( length ) - - -- Subtitle. - local subtitle = string.format( "Runway length %d", length ) - if self.metric then - subtitle = subtitle .. " meters" - else - subtitle = subtitle .. " feet" - end - - -- Transmit. + local _RUNACT = subtitle if not self.useSRS then - self:Transmission( ATIS.Sound.RunwayLength, 1.0, subtitle ) - if tonumber( L1000 ) > 0 then - self.radioqueue:Number2Transmission( L1000 ) - self:Transmission( ATIS.Sound.Thousand, 0.1 ) - end - if tonumber( L0100 ) > 0 then - self.radioqueue:Number2Transmission( L0100 ) - self:Transmission( ATIS.Sound.Hundred, 0.1 ) - end - if self.metric then - self:Transmission( ATIS.Sound.Meters, 0.1 ) - else - self:Transmission( ATIS.Sound.Feet, 0.1 ) + self:Transmission(ATIS.Sound.ActiveRunway, 1.0, subtitle) + self.radioqueue:Number2Transmission(runwayLanding) + if rwyLandingLeft==true then + self:Transmission(ATIS.Sound.Left, 0.2) + elseif rwyLandingLeft==false then + self:Transmission(ATIS.Sound.Right, 0.2) end end alltext = alltext .. ";\n" .. subtitle + + -- Runway length. + if self.rwylength then + + local runact = self.airbase:GetActiveRunway( self.runwaym2t ) + local length = runact.length + if not self.metric then + length = UTILS.MetersToFeet( length ) + end + + -- Length in thousands and hundrets of ft/meters. + local L1000, L0100 = self:_GetThousandsAndHundreds( length ) + + -- Subtitle. + local subtitle = string.format( "Runway length %d", length ) + if self.metric then + subtitle = subtitle .. " meters" + else + subtitle = subtitle .. " feet" + end + + -- Transmit. + if not self.useSRS then + self:Transmission( ATIS.Sound.RunwayLength, 1.0, subtitle ) + if tonumber( L1000 ) > 0 then + self.radioqueue:Number2Transmission( L1000 ) + self:Transmission( ATIS.Sound.Thousand, 0.1 ) + end + if tonumber( L0100 ) > 0 then + self.radioqueue:Number2Transmission( L0100 ) + self:Transmission( ATIS.Sound.Hundred, 0.1 ) + end + if self.metric then + self:Transmission( ATIS.Sound.Meters, 0.1 ) + else + self:Transmission( ATIS.Sound.Feet, 0.1 ) + end + end + alltext = alltext .. ";\n" .. subtitle + end end - -- Airfield elevation if self.elevation then @@ -2246,9 +2266,7 @@ function ATIS:onafterBroadcast( From, Event, To ) end -- ILS - --self:I({ils=self.ils}) local ils=self:GetNavPoint(self.ils, runwayLanding, rwyLandingLeft) - --self:I({ils=ils,runwayLanding=runwayLanding, rwyLandingLeft=rwyLandingLeft}) if ils then subtitle = string.format( "ILS frequency %.2f MHz", ils.frequency ) if not self.useSRS then @@ -2263,7 +2281,6 @@ function ATIS:onafterBroadcast( From, Event, To ) self:Transmission( ATIS.Sound.MegaHertz, 0.2 ) end alltext = alltext .. ";\n" .. subtitle - --self:I(alltext) end -- Outer NDB From 41eec658e06bffceb022c238484931b0bcff4052 Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 28 Dec 2022 15:40:40 +0100 Subject: [PATCH 30/33] UTILS - Update Load/Save Groups and Statics (#1857) Addresses #1855 and #1856 Added options to save groups in a structrued manner, allowing to despawn specific unit-types on a reload. Optionally, cinematic effects like smoke and fires can be put in place of despawned units. For statics, an option to replace them with dead statics has been added, and also cinematic effects. --- Moose Development/Moose/Utilities/Utils.lua | 243 +++++++++++++++++--- 1 file changed, 212 insertions(+), 31 deletions(-) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 0e3b3d37d..5889b8dd9 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -2177,10 +2177,29 @@ function UTILS.CheckFileExists(Path,Filename) end end +--- Function to obtain a table of typenames from the group given with the number of units of the same type in the group. +-- @param Wrapper.Group#GROUP Group The group to list +-- @return #table Table of typnames and typename counts, e.g. `{["KAMAZ Truck"]=3,["ATZ-5"]=1}` +function UTILS.GetCountPerTypeName(Group) + local units = Group:GetUnits() + local TypeNameTable = {} + for _,_unt in pairs (units) do + local unit = _unt -- Wrapper.Unit#UNIT + local typen = unit:GetTypeName() + if not TypeNameTable[typen] then + TypeNameTable[typen] = 1 + else + TypeNameTable[typen] = TypeNameTable[typen] + 1 + end + end + return TypeNameTable +end + --- Function to save the state of a list of groups found by name -- @param #table List Table of strings with groupnames -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Filename The name of the file. +-- @param #boolean Structured Append the data with a list of typenames in the group plus their count. -- @return #boolean outcome True if saving is successful, else false. -- @usage -- We will go through the list and find the corresponding group and save the current group size (0 when dead). @@ -2188,7 +2207,7 @@ end -- Position is still saved for your usage. -- The idea is to reduce the number of units when reloading the data again to restart the saved mission. -- The data will be a simple comma separated list of groupname and size, with one header line. -function UTILS.SaveStationaryListOfGroups(List,Path,Filename) +function UTILS.SaveStationaryListOfGroups(List,Path,Filename,Structured) local filename = Filename or "StateListofGroups" local data = "--Save Stationary List of Groups: "..Filename .."\n" for _,_group in pairs (List) do @@ -2196,7 +2215,16 @@ function UTILS.SaveStationaryListOfGroups(List,Path,Filename) if group and group:IsAlive() then local units = group:CountAliveUnits() local position = group:GetVec3() - data = string.format("%s%s,%d,%d,%d,%d\n",data,_group,units,position.x,position.y,position.z) + if Structured then + local structure = UTILS.GetCountPerTypeName(group) + local strucdata = "" + for typen,anzahl in pairs (structure) do + strucdata = strucdata .. typen .. "=="..anzahl..";" + end + data = string.format("%s%s,%d,%d,%d,%d,%s\n",data,_group,units,position.x,position.y,position.z,strucdata) + else + data = string.format("%s%s,%d,%d,%d,%d\n",data,_group,units,position.x,position.y,position.z) + end else data = string.format("%s%s,0,0,0,0\n",data,_group) end @@ -2210,6 +2238,7 @@ end -- @param Core.Set#SET_BASE Set of objects to save -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Filename The name of the file. +-- @param #boolean Structured Append the data with a list of typenames in the group plus their count. -- @return #boolean outcome True if saving is successful, else false. -- @usage -- We will go through the set and find the corresponding group and save the current group size and current position. @@ -2219,7 +2248,7 @@ end -- **Note** Do NOT use dashes or hashes in group template names (-,#)! -- The data will be a simple comma separated list of groupname and size, with one header line. -- The current task/waypoint/etc cannot be restored. -function UTILS.SaveSetOfGroups(Set,Path,Filename) +function UTILS.SaveSetOfGroups(Set,Path,Filename,Structured) local filename = Filename or "SetOfGroups" local data = "--Save SET of groups: "..Filename .."\n" local List = Set:GetSetObjects() @@ -2233,7 +2262,16 @@ function UTILS.SaveSetOfGroups(Set,Path,Filename) end local units = group:CountAliveUnits() local position = group:GetVec3() - data = string.format("%s%s,%s,%d,%d,%d,%d\n",data,name,template,units,position.x,position.y,position.z) + if Structured then + local structure = UTILS.GetCountPerTypeName(group) + local strucdata = "" + for typen,anzahl in pairs (structure) do + strucdata = strucdata .. typen .. "=="..anzahl..";" + end + data = string.format("%s%s,%s,%d,%d,%d,%d,%s\n",data,name,template,units,position.x,position.y,position.z,strucdata) + else + data = string.format("%s%s,%s,%d,%d,%d,%d\n",data,name,template,units,position.x,position.y,position.z) + end end end -- save the data @@ -2297,8 +2335,41 @@ end -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Filename The name of the file. -- @param #boolean Reduce If false, existing loaded groups will not be reduced to fit the saved number. +-- @param #boolean Structured (Optional, needs Reduce = true) If true, and the data has been saved as structure before, remove the correct unit types as per the saved list. +-- @param #boolean Cinematic (Optional, needs Structured = true) If true, place a fire/smoke effect on the dead static position. +-- @param #number Effect (Optional for Cinematic) What effect to use. Defaults to a random effect. Smoke presets are: 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 for Cinematic) What smoke density to use, can be 0 to 1. Defaults to 0.5. -- @return #table Table of data objects (tables) containing groupname, coordinate and group object. Returns nil when file cannot be read. -function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce) +-- @return #table When using Cinematic: table of names of smoke and fire objects, so they can be extinguished with `COORDINATE.StopBigSmokeAndFire( name )` +function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce,Structured,Cinematic,Effect,Density) + + local fires = {} + + local function Smokers(name,coord,effect,density) + local eff = math.random(8) + if type(effect) == "number" then eff = effect end + coord:BigSmokeAndFire(eff,density,name) + table.insert(fires,name) + end + + local function Cruncher(group,typename,anzahl) + local units = group:GetUnits() + local reduced = 0 + for _,_unit in pairs (units) do + local typo = _unit:GetTypeName() + if typename == typo then + if Cinematic then + local coordinate = _unit:GetCoordinate() + local name = _unit:GetName() + Smokers(name,coordinate,Effect,Density) + end + _unit:Destroy(false) + reduced = reduced + 1 + if reduced == anzahl then break end + end + end + end + local reduce = true if Reduce == false then reduce = false end local filename = Filename or "StateListofGroups" @@ -2315,18 +2386,48 @@ function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce) local posx = tonumber(dataset[3]) local posy = tonumber(dataset[4]) local posz = tonumber(dataset[5]) + local structure = dataset[6] + --BASE:I({structure}) local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) local data = { groupname=groupname, size=size, coordinate=coordinate, group=GROUP:FindByName(groupname) } if reduce then local actualgroup = GROUP:FindByName(groupname) if actualgroup and actualgroup:IsAlive() and actualgroup:CountAliveUnits() > size then - local reduction = actualgroup:CountAliveUnits() - size - BASE:I("Reducing groupsize by ".. reduction .. " units!") - -- reduce existing group - local units = actualgroup:GetUnits() - local units2 = UTILS.ShuffleTable(units) -- randomize table - for i=1,reduction do - units2[i]:Destroy(false) + if Structured and structure then + --BASE:I("Reducing group structure!") + local loadedstructure = {} + local strcset = UTILS.Split(structure,";") + for _,_data in pairs(strcset) do + local datasplit = UTILS.Split(_data,"==") + loadedstructure[datasplit[1]] = tonumber(datasplit[2]) + end + --BASE:I({loadedstructure}) + local originalstructure = UTILS.GetCountPerTypeName(actualgroup) + --BASE:I({originalstructure}) + for _name,_number in pairs(originalstructure) do + local loadednumber = 0 + if loadedstructure[_name] then + loadednumber = loadedstructure[_name] + end + local reduce = false + if loadednumber < _number then reduce = true end + + --BASE:I(string.format("Looking at: %s | Original number: %d | Loaded number: %d | Reduce: %s",_name,_number,loadednumber,tostring(reduce))) + + if reduce then + Cruncher(actualgroup,_name,_number-loadednumber) + end + + end + else + local reduction = actualgroup:CountAliveUnits() - size + --BASE:I("Reducing groupsize by ".. reduction .. " units!") + -- reduce existing group + local units = actualgroup:GetUnits() + local units2 = UTILS.ShuffleTable(units) -- randomize table + for i=1,reduction do + units2[i]:Destroy(false) + end end end end @@ -2335,19 +2436,52 @@ function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce) else return nil end - return datatable + return datatable,fires end --- Load back a SET of groups from file. -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Filename The name of the file. -- @param #boolean Spawn If set to false, do not re-spawn the groups loaded in location and reduce to size. +-- @param #boolean Structured (Optional, needs Spawn=true)If true, and the data has been saved as structure before, remove the correct unit types as per the saved list. +-- @param #boolean Cinematic (Optional, needs Structured=true) If true, place a fire/smoke effect on the dead static position. +-- @param #number Effect (Optional for Cinematic) What effect to use. Defaults to a random effect. Smoke presets are: 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 for Cinematic) What smoke density to use, can be 0 to 1. Defaults to 0.5. -- @return Core.Set#SET_GROUP Set of GROUP objects. -- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate, template=template }` -function UTILS.LoadSetOfGroups(Path,Filename,Spawn) +-- @return #table When using Cinematic: table of names of smoke and fire objects, so they can be extinguished with `COORDINATE.StopBigSmokeAndFire( name )` +function UTILS.LoadSetOfGroups(Path,Filename,Spawn,Structured,Cinematic,Effect,Density) + + local fires = {} + + local function Smokers(name,coord,effect,density) + local eff = math.random(8) + if type(effect) == "number" then eff = effect end + coord:BigSmokeAndFire(eff,density,name) + table.insert(fires,name) + end + + local function Cruncher(group,typename,anzahl) + local units = group:GetUnits() + local reduced = 0 + for _,_unit in pairs (units) do + local typo = _unit:GetTypeName() + if typename == typo then + if Cinematic then + local coordinate = _unit:GetCoordinate() + local name = _unit:GetName() + Smokers(name,coordinate,Effect,Density) + end + _unit:Destroy(false) + reduced = reduced + 1 + if reduced == anzahl then break end + end + end + end + local spawn = true if Spawn == false then spawn = false end - BASE:I("Spawn = "..tostring(spawn)) + --BASE:I("Spawn = "..tostring(spawn)) local filename = Filename or "SetOfGroups" local setdata = SET_GROUP:New() local datatable = {} @@ -2364,6 +2498,7 @@ function UTILS.LoadSetOfGroups(Path,Filename,Spawn) local posx = tonumber(dataset[4]) local posy = tonumber(dataset[5]) local posz = tonumber(dataset[6]) + local structure = dataset[7] local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) local group=nil local data = { groupname=groupname, size=size, coordinate=coordinate, template=template } @@ -2376,12 +2511,40 @@ function UTILS.LoadSetOfGroups(Path,Filename,Spawn) setdata:AddObject(spwndgrp) local actualsize = spwndgrp:CountAliveUnits() if actualsize > size then - local reduction = actualsize-size - -- reduce existing group - local units = spwndgrp:GetUnits() - local units2 = UTILS.ShuffleTable(units) -- randomize table - for i=1,reduction do - units2[i]:Destroy(false) + if Structured and structure then + --BASE:I("Reducing group structure!") + local loadedstructure = {} + local strcset = UTILS.Split(structure,";") + for _,_data in pairs(strcset) do + local datasplit = UTILS.Split(_data,"==") + loadedstructure[datasplit[1]] = tonumber(datasplit[2]) + end + --BASE:I({loadedstructure}) + local originalstructure = UTILS.GetCountPerTypeName(spwndgrp) + --BASE:I({originalstructure}) + for _name,_number in pairs(originalstructure) do + local loadednumber = 0 + if loadedstructure[_name] then + loadednumber = loadedstructure[_name] + end + local reduce = false + if loadednumber < _number then reduce = true end + + --BASE:I(string.format("Looking at: %s | Original number: %d | Loaded number: %d | Reduce: %s",_name,_number,loadednumber,tostring(reduce))) + + if reduce then + Cruncher(spwndgrp,_name,_number-loadednumber) + end + + end + else + local reduction = actualsize-size + -- reduce existing group + local units = spwndgrp:GetUnits() + local units2 = UTILS.ShuffleTable(units) -- randomize table + for i=1,reduction do + units2[i]:Destroy(false) + end end end end @@ -2393,7 +2556,7 @@ function UTILS.LoadSetOfGroups(Path,Filename,Spawn) return nil end if spawn then - return setdata + return setdata,fires else return datatable end @@ -2412,12 +2575,7 @@ function UTILS.LoadSetOfStatics(Path,Filename) table.remove(loadeddata, 1) for _id,_entry in pairs (loadeddata) do local dataset = UTILS.Split(_entry,",") - -- staticname,position.x,position.y,position.z local staticname = dataset[1] - --local posx = tonumber(dataset[2]) - --local posy = tonumber(dataset[3]) - --local posz = tonumber(dataset[4]) - --local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz}) local StaticObject = STATIC:FindByName(staticname,false) if StaticObject then datatable:AddObject(StaticObject) @@ -2433,9 +2591,15 @@ end -- @param #string Path The path to use. Use double backslashes \\\\ on Windows filesystems. -- @param #string Filename The name of the file. -- @param #boolean Reduce If false, do not destroy the units with size=0. --- @return #table Table of data objects (tables) containing staticname, size (0=dead else 1), coordinate and the static object. +-- @param #boolean Dead (Optional, needs Reduce = true) If Dead is true, re-spawn the dead object as dead and do not just delete it. +-- @param #boolean Cinematic (Optional, needs Dead = true) If true, place a fire/smoke effect on the dead static position. +-- @param #number Effect (Optional for Cinematic) What effect to use. Defaults to a random effect. Smoke presets are: 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 for Cinematic) What smoke density to use, can be 0 to 1. Defaults to 0.5. +-- @return #table Table of data objects (tables) containing staticname, size (0=dead else 1), coordinate and the static object. Dead objects will have coordinate points `{x=0,y=0,z=0}` +-- @return #table When using Cinematic: table of names of smoke and fire objects, so they can be extinguished with `COORDINATE.StopBigSmokeAndFire( name )` -- Returns nil when file cannot be read. -function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce) +function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce,Dead,Cinematic,Effect,Density) + local fires = {} local reduce = true if Reduce == false then reduce = false end local filename = Filename or "StateListofStatics" @@ -2458,14 +2622,31 @@ function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce) if size==0 and reduce then local static = STATIC:FindByName(staticname,false) if static then - static:Destroy(false) + if Dead then + local deadobject = SPAWNSTATIC:NewFromStatic(staticname,static:GetCountry()) + deadobject:InitDead(true) + local heading = static:GetHeading() + local coord = static:GetCoordinate() + static:Destroy(false) + deadobject:SpawnFromCoordinate(coord,heading,staticname) + if Cinematic then + local effect = math.random(8) + if type(Effect) == "number" then + effect = Effect + end + coord:BigSmokeAndFire(effect,Density,staticname) + table.insert(fires,staticname) + end + else + static:Destroy(false) + end end end end else return nil end - return datatable + return datatable,fires end --- Heading Degrees (0-360) to Cardinal From 8661d07e1e2cdd7f0e3ee47ba501bb3771b55a18 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 29 Dec 2022 16:33:13 +0100 Subject: [PATCH 31/33] #ATIS * Make SRS say TACAN and FARP and not spell the single characters --- Moose Development/Moose/Ops/ATIS.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moose Development/Moose/Ops/ATIS.lua b/Moose Development/Moose/Ops/ATIS.lua index e65a2ac71..96794d939 100644 --- a/Moose Development/Moose/Ops/ATIS.lua +++ b/Moose Development/Moose/Ops/ATIS.lua @@ -2416,6 +2416,8 @@ function ATIS:onafterReport( From, Event, To, Text ) local text = string.gsub( text, "mmHg", "millimeters of Mercury" ) local text = string.gsub( text, "hPa", "hectopascals" ) local text = string.gsub( text, "m/s", "meters per second" ) + local text = string.gsub( text, "TACAN", "tackan" ) + local text = string.gsub( text, "FARP", "farp" ) -- Replace ";" by "." local text = string.gsub( text, ";", " . " ) From 820279151869dbacaf1fe8e011f73f846b4c1496 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 29 Dec 2022 16:33:43 +0100 Subject: [PATCH 32/33] #AWACS * Added option for helos to sign-in #ATIS * Make SRS say TACAN and FARP and not spell the single characters --- Moose Development/Moose/Ops/Awacs.lua | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/Awacs.lua b/Moose Development/Moose/Ops/Awacs.lua index 657d4aca6..4b682296b 100644 --- a/Moose Development/Moose/Ops/Awacs.lua +++ b/Moose Development/Moose/Ops/Awacs.lua @@ -112,6 +112,7 @@ do -- @field #boolean GCI Act as GCI -- @field Wrapper.Group#GROUP GCIGroup EWR group object for GCI ops -- @field #string locale Localization +-- @field #boolean IncludeHelicopters -- @extends Core.Fsm#FSM @@ -365,6 +366,7 @@ do -- testawacs.GoogleTTSPadding = 1 -- seconds -- testawacs.WindowsTTSPadding = 2.5 -- seconds -- testawacs.PikesSpecialSwitch = false -- if set to true, AWACS will omit the "doing xy knots" on the station assignement callout +-- testawacs.IncludeHelicopters = false -- if set to true, Helicopter pilots will also get the AWACS Menu and options -- -- ## 9.2 Bespoke random voices for AI CAP (Google TTS only) -- @@ -497,7 +499,7 @@ do -- @field #AWACS AWACS = { ClassName = "AWACS", -- #string - version = "0.2.50", -- #string + version = "0.2.51", -- #string lid = "", -- #string coalition = coalition.side.BLUE, -- #number coalitiontxt = "blue", -- #string @@ -584,6 +586,7 @@ AWACS = { GCI = false, GCIGroup = nil, locale = "en", + IncludeHelicopters = false, } --- @@ -914,13 +917,13 @@ AWACS.TaskStatus = { --@field #boolean FromAI ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO-List 0.2.50 +-- TODO-List 0.2.51 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- -- DONE - WIP - Player tasking, VID -- DONE - Localization (sensible?) -- TODO - (LOW) LotATC --- TODO - SW Optimization +-- DONE - SW Optimization -- WONTDO - Maybe check in AI only when airborne -- DONE - remove SSML tag when not on google (currently sometimes spoken) -- DONE - Maybe - Assign specific number of AI CAP to a station @@ -951,6 +954,7 @@ AWACS.TaskStatus = { -- DONE - Shift Length AWACS/AI -- DONE - (WIP) Reporting -- DONE - Do not report non-airborne groups +-- DONE - Added option for helos ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor @@ -5534,6 +5538,20 @@ end -- FSM Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- [Internal] onbeforeStart +-- @param #AWACS self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #AWACS self +function AWACS:onbeforeStart(From,Event,to) + self:T({From, Event, To}) + if self.IncludeHelicopters then + self.clientset:FilterCategories("helicopter") + end + return self +end + --- [Internal] onafterStart -- @param #AWACS self -- @param #string From From 5a44948050f9467fb7bafda5a8cac90a81eb428e Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Fri, 30 Dec 2022 17:40:10 +0100 Subject: [PATCH 33/33] #FLIGHTGROUP * Make one is local --- 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 3087195f6..6bcfcd5d1 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -712,7 +712,7 @@ end -- @param #FLIGHTGROUP self -- @return #boolean If true, has landed somewhere. function FLIGHTGROUP:IsLandedAt() - is=self:Is("LandedAt") + local is=self:Is("LandedAt") return is end