From a42ff854063af7cf9fbe8833d4345f66e6d136a2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 1 Oct 2022 16:03:05 +0200 Subject: [PATCH 1/9] #PLAYERRECCE * Integrated SRS * Integrated PLAYERTASKCONTROLLER (optional), can upload target data from Recce --- Moose Development/Moose/Ops/PlayerRecce.lua | 459 ++++++++++++++++---- 1 file changed, 373 insertions(+), 86 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index c808a9f83..64ad35b8f 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -5,6 +5,7 @@ -- * Allow a player in the Gazelle to detect, smoke, flare, lase and report ground units to others. -- * Implements visual detection from the helo -- * Implements optical detection via the Vivianne system and lasing +-- * Upload target info to a PLAYERTASKCONTROLLER Instance -- -- === -- @@ -52,6 +53,14 @@ -- @field #number lasingtime -- @field #table AutoLase -- @field Core.Set#SET_CLIENT AttackSet +-- @field #boolean TransmitOnlyWithPlayers +-- @field Sound.SRS#MSRS SRS +-- @field Sound.SRS#MSRSQUEUE SRSQueue +-- @field #boolean UseController +-- @field Ops.PlayerTask#PLAYERTASKCONTROLLER Controller +-- @field #boolean ShortCallsign +-- @field #boolean Keepnumber +-- @field #table CallsignTranslations -- @extends Core.Fsm#FSM --- @@ -74,7 +83,7 @@ PLAYERRECCE = { ClassName = "PLAYERRECCE", verbose = true, lid = nil, - version = "0.0.1", + version = "0.0.5", ViewZone = {}, ViewZoneVisual = {}, PlayerSet = nil, @@ -88,6 +97,12 @@ PLAYERRECCE = { lasingtime = 60, AutoLase = {}, AttackSet = nil, + TransmitOnlyWithPlayers = true, + UseController = false, + Controller = nil, + ShortCallsign = true, + Keepnumber = true, + CallsignTranslations = nil, } --- @@ -130,8 +145,11 @@ PLAYERRECCE.CanLase = { ["SA342L"] = true, } ---- +--- Create and rund a new PlayerRecce instance. -- @param #PLAYERRECCE self +-- @param #string Name The name of this instance +-- @param #number Coalition, e.g. coalition.side.BLUE +-- @param Core.Set#SET_CLIENT PlayerSet The set of pilots working as recce -- @return #PLAYERRECCE self function PLAYERRECCE:New(Name, Coalition, PlayerSet) @@ -177,9 +195,15 @@ function PLAYERRECCE:New(Name, Coalition, PlayerSet) local starttime = math.random(5,10) self:__Status(-starttime) + self:I(self.lid..self.version.." Started.") + return self end +------------------------------------------------------------------------------------------ +-- TODO: Functions +------------------------------------------------------------------------------------------ + --- [Internal] Event handling -- @param #PLAYERRECCE self -- @param Core.Event#EVENTDATA EventData @@ -188,7 +212,7 @@ function PLAYERRECCE:_EventHandler(EventData) self:T(self.lid.."_EventHandler: "..EventData.id) if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then if EventData.IniPlayerName then - self:I(self.lid.."Event for player: "..EventData.IniPlayerName) + self:T(self.lid.."Event for player: "..EventData.IniPlayerName) if self.ClientMenus[EventData.IniPlayerName] then self.ClientMenus[EventData.IniPlayerName]:Remove() end @@ -198,7 +222,7 @@ function PLAYERRECCE:_EventHandler(EventData) end elseif EventData.id == EVENTS.PlayerEnterAircraft and EventData.IniCoalition == self.Coalition then if EventData.IniPlayerName and EventData.IniGroup and self.UseSRS then - self:I(self.lid.."Event for player: "..EventData.IniPlayerName) + self:T(self.lid.."Event for player: "..EventData.IniPlayerName) self.UnitLaserCodes[EventData.IniPlayerName] = 1688 self.ClientMenus[EventData.IniPlayerName] = nil self.LaserSpots[EventData.IniPlayerName] = nil @@ -209,6 +233,37 @@ function PLAYERRECCE:_EventHandler(EventData) return self end +--- (Internal) Function to determine clockwise direction to target. +-- @param #PLAYERRECCE self +-- @param Wrapper.Unit#UNIT unit The Helicopter +-- @param Wrapper.Unit#UNIT target The downed Group +-- @return #number direction +function PLAYERRECCE:_GetClockDirection(unit, target) + self:T(self.lid .. " _GetClockDirection") + + local _playerPosition = unit:GetCoordinate() -- get position of helicopter + local _targetpostions = target:GetCoordinate() -- get position of downed pilot + local _heading = unit:GetHeading() -- heading + local DirectionVec3 = _playerPosition:GetDirectionVec3( _targetpostions ) + local Angle = _playerPosition:GetAngleDegrees( DirectionVec3 ) + local clock = 12 + local hours = 0 + if _heading and Angle then + clock = 12 + --if angle == 0 then angle = 360 end + clock = _heading-Angle + hours = (clock/30)*-1 + clock = 12+hours + clock = UTILS.Round(clock,0) + if clock > 12 then clock = clock-12 end + end + if self.debug then + local text = string.format("Heading = %d, Angle = %d, Hours= %d, Clock = %d",_heading,Angle,hours,clock) + self:I(self.lid .. text) + end + return clock +end + --- [User] Set a table of possible laser codes. -- Each new RECCE can select a code from this table, default is 1688. -- @param #PLAYERRECCE self @@ -219,6 +274,16 @@ function PLAYERRECCE:SetLaserCodes( LaserCodes ) return self end +--- [User] Set PlayerTaskController. Allows to upload target reports to the controller, in turn creating tasks for other players. +-- @param #PLAYERRECCE self +-- @param Ops.PlayerTask#PLAYERTASKCONTROLLER Controller +-- @return #PLAYERRECCE +function PLAYERRECCE:SetPlayerTaskController(Controller) + self.UseController = true + self.Controller = Controller + return self +end + --- [User] Set a set of clients which will receive target reports -- @param #PLAYERRECCE self -- @param Core.Set#SET_CLIENT AttackSet @@ -236,7 +301,7 @@ end -- @return #number maxview in meters. -- @return #boolean cameraison If true, camera is on, else off. function PLAYERRECCE:_GetGazelleVivianneSight(Gazelle) - self:I(self.lid.."GetGazelleVivianneSight") + self:T(self.lid.."GetGazelleVivianneSight") local unit = Gazelle -- Wrapper.Unit#UNIT if unit and unit:IsAlive() then local dcsunit = Unit.getByName(Gazelle:GetName()) @@ -273,7 +338,7 @@ end -- @param #boolean vivoff Camera on or off -- @return #number maxview Max view distance in meters function PLAYERRECCE:_GetActualMaxLOSight(unit,vheading, vnod, vivoff) - self:I(self.lid.."_GetActualMaxLOSight") + self:T(self.lid.."_GetActualMaxLOSight") if vivoff then return 0 end local maxview = 0 if unit and unit:IsAlive() then @@ -295,6 +360,24 @@ function PLAYERRECCE:_GetActualMaxLOSight(unit,vheading, vnod, vivoff) return maxview end +--- [User] Set callsign options for TTS output. See @{Wrapper.Group#GROUP.GetCustomCallSign}() on how to set customized callsigns. +-- @param #PLAYERRECCE self +-- @param #boolean ShortCallsign If true, only call out the major flight number +-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name for players as-is, no amendments or numbers. +-- @param #table CallsignTranslations (optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized +-- callsigns from playername or group name. +-- @return #PLAYERRECCE self +function PLAYERRECCE:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations) + if not ShortCallsign or ShortCallsign == false then + self.ShortCallsign = false + else + self.ShortCallsign = true + end + self.Keepnumber = Keepnumber or false + self.CallsignTranslations = CallsignTranslations + return self +end + --- [Internal] Build a ZONE_POLYGON from a given viewport of a unit -- @param #PLAYERRECCE self -- @param Wrapper.Unit#UNIT unit The unit which is looking @@ -306,7 +389,7 @@ end -- @param #boolean draw Draw the zone on the F10 map -- @return Core.Zone#ZONE_POLYGON ViewZone or nil if camera is off function PLAYERRECCE:_GetViewZone(unit, vheading, vnod, maxview, angle, camon, draw) - self:I(self.lid.."_GetViewZone") + self:T(self.lid.."_GetViewZone") local viewzone = nil if not camon then return nil end if unit and unit:IsAlive() then @@ -340,7 +423,7 @@ end --@return Core.Set#SET_UNIT Set of targets, can be empty! --@return #number count Count of targets function PLAYERRECCE:_GetTargetSet(unit,camera) - self:I(self.lid.."_GetTargetSet") + self:T(self.lid.."_GetTargetSet") local finaltargets = SET_UNIT:New() local finalcount = 0 local heading,nod,maxview,angle = 0,30,5000,10 @@ -365,7 +448,7 @@ function PLAYERRECCE:_GetTargetSet(unit,camera) -- determine what we can see local startpos = unit:GetCoordinate() local targetset = SET_UNIT:New():FilterCategories("ground"):FilterActive(true):FilterZones({zone}):FilterCoalitions(redcoalition):FilterOnce() - self:I("Prefilter Target Count = "..targetset:CountAlive()) + self:T("Prefilter Target Count = "..targetset:CountAlive()) -- TODO - Threat level filter? -- TODO - Min distance from unit? targetset:ForEach( @@ -373,13 +456,13 @@ function PLAYERRECCE:_GetTargetSet(unit,camera) local _unit = _unit -- Wrapper.Unit#UNIT local _unitpos = _unit:GetCoordinate() if startpos:IsLOS(_unitpos) then - self:I("Adding to final targets: ".._unit:GetName()) + self:T("Adding to final targets: ".._unit:GetName()) finaltargets:Add(_unit:GetName(),_unit) end end ) finalcount = finaltargets:CountAlive() - self:I(string.format("%s Unit: %s | Targets in view %s",self.lid,name,finalcount)) + self:T(string.format("%s Unit: %s | Targets in view %s",self.lid,name,finalcount)) end return finaltargets, finalcount, zone end @@ -389,7 +472,7 @@ end --@param Core.Set#SET_UNIT targetset Set of targets, can be empty! --@return Wrapper.Unit#UNIT Target function PLAYERRECCE:_GetHVTTarget(targetset) - self:I(self.lid.."_GetHVTTarget") + self:T(self.lid.."_GetHVTTarget") -- get one target -- local target = targetset:GetRandom() -- Wrapper.Unit#UNIT @@ -426,7 +509,7 @@ end --@param Core.Set#SET_UNIT targetset Set of targets, can be empty! --@return #PLAYERRECCE self function PLAYERRECCE:_LaseTarget(client,targetset) - self:I(self.lid.."_LaseTarget") + self:T(self.lid.."_LaseTarget") -- get one target local target = self:_GetHVTTarget(targetset) -- Wrapper.Unit#UNIT local playername = client:GetPlayerName() @@ -475,7 +558,7 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_SetClientLaserCode(client,group,playername,code) - self:I(self.lid.."_SetClientLaserCode") + self:T(self.lid.."_SetClientLaserCode") self.UnitLaserCodes[playername] = code or 1688 if self.ClientMenus[playername] then self.ClientMenus[playername]:Remove() @@ -491,7 +574,7 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_SwitchOnStation(client,group,playername) - self:I(self.lid.."_SwitchOnStation") + self:T(self.lid.."_SwitchOnStation") if not self.OnStation[playername] then self.OnStation[playername] = true self:__RecceOnStation(-1,client,playername) @@ -513,7 +596,7 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_SwitchLasing(client,group,playername) - self:I(self.lid.."_SwitchLasing") + self:T(self.lid.."_SwitchLasing") if not self.AutoLase[playername] then self.AutoLase[playername] = true MESSAGE:New("Lasing is now ON",10,self.Name or "FACA"):ToClient(client) @@ -546,7 +629,7 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_SmokeTargets(client,group,playername) - self:I(self.lid.."_SmokeTargets") + self:T(self.lid.."_SmokeTargets") local cameraset = self:_GetTargetSet(client,true) -- Core.Set#SET_UNIT local visualset = self:_GetTargetSet(client,false) -- Core.Set#SET_UNIT cameraset:AddSet(visualset) @@ -590,7 +673,7 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_FlareTargets(client,group,playername) - self:I(self.lid.."_SmokeTargets") + self:T(self.lid.."_FlareTargets") local cameraset = self:_GetTargetSet(client,true) -- Core.Set#SET_UNIT local visualset = self:_GetTargetSet(client,false) -- Core.Set#SET_UNIT cameraset:AddSet(visualset) @@ -627,6 +710,26 @@ function PLAYERRECCE:_FlareTargets(client,group,playername) return self end +--- [Internal] +-- @param #PLAYERRECCE self +-- @param Wrapper.Client#CLIENT client +-- @param Wrapper.Group#GROUP group +-- @param #string playername +-- @return #PLAYERRECCE self +function PLAYERRECCE:_UploadTargets(client,group,playername) + self:T(self.lid.."_UploadTargets") + local targetset, number = self:_GetTargetSet(client,true) + local vtargetset, vnumber = self:_GetTargetSet(client,false) + local totalset = SET_UNIT:New() + totalset:AddSet(targetset) + totalset:AddSet(vtargetset) + if totalset:CountAlive() > 0 then + self.Controller:AddTarget(totalset) + self:__TargetReportSent(1,client,playername,totalset) + end + return self +end + --- [Internal] -- @param #PLAYERRECCE self -- @param Wrapper.Client#CLIENT client @@ -634,7 +737,7 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_ReportLaserTargets(client,group,playername) -self:I(self.lid.."_ReportLaserTargets") +self:T(self.lid.."_ReportLaserTargets") local targetset, number = self:_GetTargetSet(client,true) if number > 0 and self.AutoLase[playername] then local Settings = ( client and _DATABASE:GetPlayerSettings( playername ) ) or _SETTINGS @@ -675,7 +778,7 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_ReportVisualTargets(client,group,playername) - self:I(self.lid.."_ReportVisualTargets") + self:T(self.lid.."_ReportVisualTargets") local targetset, number = self:_GetTargetSet(client,false) if number > 0 then local Settings = ( client and _DATABASE:GetPlayerSettings( playername ) ) or _SETTINGS @@ -711,7 +814,7 @@ end -- @param #PLAYERRECCE self -- @param #PLAYERRECCE self function PLAYERRECCE:_BuildMenus() - self:I(self.lid.."_BuildMenus") + self:T(self.lid.."_BuildMenus") local clients = self.PlayerSet -- Core.Set#SET_CLIENT local clientset = clients:GetSetObjects() for _,_client in pairs(clientset) do @@ -724,7 +827,7 @@ function PLAYERRECCE:_BuildMenus() local group = client:GetGroup() if not self.ClientMenus[playername] then local canlase = self.CanLase[client:GetTypeName()] - self.ClientMenus[playername] = MENU_GROUP:New(group,self.Name or "RECCE") + self.ClientMenus[playername] = MENU_GROUP:New(group,self.MenuName or self.Name or "RECCE") local txtonstation = self.OnStation[playername] and "ON" or "OFF" local text = string.format("Switch On-Station (%s)",txtonstation) local onstationmenu = MENU_GROUP_COMMAND:New(group,text,self.ClientMenus[playername],self._SwitchOnStation,self,client,group,playername) @@ -741,6 +844,10 @@ function PLAYERRECCE:_BuildMenus() local reportL = MENU_GROUP_COMMAND:New(group,"Laser Target",targetmenu,self._ReportLaserTargets,self,client,group,playername) end local reportV = MENU_GROUP_COMMAND:New(group,"Visual Targets",targetmenu,self._ReportVisualTargets,self,client,group,playername) + if self.UseController then + local text = string.format("Target Upload to %s",self.Controller.MenuName or self.Controller.Name) + local upload = MENU_GROUP_COMMAND:New(group,text,targetmenu,self._UploadTargets,self,client,group,playername) + end if canlase then local lasecodemenu = MENU_GROUP:New(group,"Set Laser Code",self.ClientMenus[playername]) local codemenu = {} @@ -766,18 +873,20 @@ end -- @param #string playername -- @return #PLAYERRECCE self function PLAYERRECCE:_CheckNewTargets(targetset,client,playername) - self:I(self.lid.."_CheckNewTargets") - targetset:ForEachUnit( + self:T(self.lid.."_CheckNewTargets") + targetset:ForEach( function(unit) if unit and unit:IsAlive() then + self:T("Report unit: "..unit:GetName()) if not unit.PlayerRecceDetected then + self:T("New unit: "..unit:GetName()) unit.PlayerRecceDetected = { detected = true, recce = client, playername = playername, timestamp = timer.getTime() } - self:__TargetDetected(-1,unit,client,playername) + self:TargetDetected(unit,client,playername) end end end @@ -785,7 +894,92 @@ function PLAYERRECCE:_CheckNewTargets(targetset,client,playername) return self end ---- [Internal] +--- [User] Set SRS TTS details - see @{Sound.SRS} for details +-- @param #PLAYERRECCE self +-- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations! +-- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies! +-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone" +-- @param #string Gender (Optional) Defaults to "male" +-- @param #string Culture (Optional) Defaults to "en-US" +-- @param #number Port (Optional) Defaults to 5002 +-- @param #string Voice (Optional) Use a specifc voice with the @{Sound.SRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`. +-- Note that this must be installed on your windows system. Can also be Google voice types, if you are using Google TTS. +-- @param #number Volume (Optional) Volume - between 0.0 (silent) and 1.0 (loudest) +-- @param #string PathToGoogleKey (Optional) Path to your google key if you want to use google TTS +-- @return #PLAYERRECCE self +function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey) + self:T(self.lid.."SetSRS") + self.PathToSRS = PathToSRS or "C:\\Program Files\\DCS-SimpleRadio-Standalone" -- + self.Gender = Gender or "male" -- + self.Culture = Culture or "en-US" -- + self.Port = Port or 5002 -- + self.Voice = Voice -- + self.PathToGoogleKey = PathToGoogleKey -- + self.Volume = Volume or 1.0 -- + self.UseSRS = true + self.Frequency = Frequency or {127,251} -- + self.BCFrequency = self.Frequency + self.Modulation = Modulation or {radio.modulation.FM,radio.modulation.AM} -- + self.BCModulation = self.Modulation + -- set up SRS + self.SRS=MSRS:New(self.PathToSRS,self.Frequency,self.Modulation,self.Volume) + self.SRS:SetCoalition(self.Coalition) + self.SRS:SetLabel(self.MenuName or self.Name) + self.SRS:SetGender(self.Gender) + self.SRS:SetCulture(self.Culture) + self.SRS:SetPort(self.Port) + self.SRS:SetVoice(self.Voice) + if self.PathToGoogleKey then + self.SRS:SetGoogle(self.PathToGoogleKey) + end + self.SRSQueue = MSRSQUEUE:New(self.MenuName or self.Name) + self.SRSQueue:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers) + return self +end + +--- [User] For SRS - Switch to only transmit if there are players on the server. +-- @param #PLAYERRECCE self +-- @param #boolean Switch If true, only send SRS if there are alive Players. +-- @return #PLAYERRECCE self +function PLAYERRECCE:SetTransmitOnlyWithPlayers(Switch) + self.TransmitOnlyWithPlayers = Switch + if self.SRSQueue then + self.SRSQueue:SetTransmitOnlyWithPlayers(Switch) + end + return self +end + +--- [User] Set the top menu name to a custom string. +-- @param #PLAYERRECCE self +-- @param #string Name The name to use as the top menu designation. +-- @return #PLAYERRECCE self +function PLAYERRECCE:SetMenuName(Name) + self:T(self.lid.."SetMenuName: "..Name) + self.MenuName = Name + return self +end + +--- [Internal] Get text for text-to-speech. +-- Numbers are spaced out, e.g. "Heading 180" becomes "Heading 1 8 0 ". +-- @param #PLAYERRECCE self +-- @param #string text Original text. +-- @return #string Spoken text. +function PLAYERRECCE:_GetTextForSpeech(text) + + -- Space out numbers. + text=string.gsub(text,"%d","%1 ") + -- get rid of leading or trailing spaces + text=string.gsub(text,"^%s*","") + text=string.gsub(text,"%s*$","") + + return text +end + +------------------------------------------------------------------------------------------ +-- TODO: FSM Functions +------------------------------------------------------------------------------------------ + +--- [Internal] Status Loop -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -801,6 +995,7 @@ function PLAYERRECCE:onafterStatus(From, Event, To) local client = Client -- Wrapper.Client#CLIENT local playername = client:GetPlayerName() if client and client:IsAlive() and self.OnStation[playername] then + -- targets on camera local targetset, targetcount, tzone = self:_GetTargetSet(client,true) if targetset then @@ -811,7 +1006,17 @@ function PLAYERRECCE:onafterStatus(From, Event, To) self.ViewZone[playername]=tzone:DrawZone(self.Coalition,{0,0,1},nil,nil,nil,1) end end - self:I({targetcount=targetcount}) + self:T({targetcount=targetcount}) + -- lase targets on camera + if targetcount > 0 then + if self.CanLase[client:GetTypeName()] and self.AutoLase[playername] then + -- DONE move to lase at will + self:_LaseTarget(client,targetset) + end + end + -- Report new targets + self:_CheckNewTargets(targetset,client,playername) + -- visual targets local vistargetset, vistargetcount, viszone = self:_GetTargetSet(client,false) if vistargetset then @@ -822,17 +1027,8 @@ function PLAYERRECCE:onafterStatus(From, Event, To) self.ViewZoneVisual[playername]=viszone:DrawZone(self.Coalition,{1,0,0},nil,nil,nil,3) end end - self:I({targetcount=targetcount}) - -- lase targets on camera - if targetcount > 0 then - if self.CanLase[client:GetTypeName()] and self.AutoLase[playername] then - -- DONE move to lase at will - self:_LaseTarget(client,targetset) - end - end - -- Report new targets - targetset:AddSet(vistargetset) - self:_CheckNewTargets(targetset,client,playername) + self:T({visualtargetcount=vistargetcount}) + self:_CheckNewTargets(vistargetset,client,playername) end end ) @@ -841,7 +1037,7 @@ function PLAYERRECCE:onafterStatus(From, Event, To) return self end ---- [Internal] +--- [Internal] Recce on station -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -850,16 +1046,30 @@ end -- @param #string Playername -- @return #PLAYERRECCE self function PLAYERRECCE:onafterRecceOnStation(From, Event, To, Client, Playername) - self:I({From, Event, To}) - local callsign = Client:GetGroup():GetCustomCallSign(true,true) + self:T({From, Event, To}) + local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) - local text = string.format("All stations, FACA %s on station\nat %s!",callsign, coordtext) - MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + if self.debug then + local text = string.format("All stations, FACA %s on station\nat %s!",callsign, coordtext) + MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + end + local text1 = "Party time!" + local text2 = string.format("All stations, FACA %s on station\nat %s!",callsign, coordtext) + local text2tts = string.format("All stations, FACA %s on station at %s!",callsign, coordtext) + text2tts = self:_GetTextForSpeech(text2tts) + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2,{grp},text1,10) + self.SRSQueue:NewTransmission(text2tts,nil,self.SRS,nil,1,{grp},text2,10) + else + MESSAGE:New(text1,10,self.Name or "FACA"):ToClient(Client) + MESSAGE:New(text2,10,self.Name or "FACA"):ToClient(Client) + end return self end ---- [Internal] +--- [Internal] Recce off station -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -868,16 +1078,28 @@ end -- @param #string Playername -- @return #PLAYERRECCE self function PLAYERRECCE:onafterRecceOffStation(From, Event, To, Client, Playername) - self:I({From, Event, To}) - local callsign = Client:GetGroup():GetCustomCallSign(true,true) + self:T({From, Event, To}) + local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) - local text = string.format("All stations, FACA %s leaving station\nat %s, going home!",callsign, coordtext) - MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + local text = string.format("All stations, FACA %s leaving station\nat %s, good bye!",callsign, coordtext) + local texttts = string.format("All stations, FACA %s leaving station at %s, good bye!",callsign, coordtext) + texttts = self:_GetTextForSpeech(texttts) + if self.debug then + MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + end + local text1 = "Going home!" + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2,{grp},text1,10) + self.SRSQueue:NewTransmission(texttts,nil,self.SRS,nil,2,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end return self end ---- [Internal] +--- [Internal] Target Detected -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -887,15 +1109,36 @@ end -- @param #string Playername -- @return #PLAYERRECCE self function PLAYERRECCE:onafterTargetDetected(From, Event, To, Target, Client, Playername) - self:I({From, Event, To}) - if self.debug then - local text = string.format("New target %s detected by %s!",Target:GetTypeName(),Playername) - MESSAGE:New(text,10,self.Name or "FACA"):ToCoalition(self.Coalition) + self:T({From, Event, To}) + local dunits = "meters" + local targetdirection = self:_GetClockDirection(Client,Target) + local targetdistance = Client:GetCoordinate():Get2DDistance(Target:GetCoordinate()) or 100 + local Settings = Client and _DATABASE:GetPlayerSettings(Playername) or _SETTINGS -- Core.Settings#SETTINGS + local Threatlvl = Target:GetThreatLevel() + local ThreatTxt = "Low" + if Threatlvl >=7 then + ThreatTxt = "Medium" + elseif Threatlvl >=3 then + ThreatTxt = "High" + end + if Settings:IsMetric() then + targetdistance = UTILS.Round(targetdistance,-2) + else + targetdistance = UTILS.Round(UTILS.MetersToFeet(targetdistance),-2) + dunits = "feet" + end + local text = string.format("Target! %s! %s o\'clock, %d %s!", ThreatTxt,targetdirection, targetdistance, dunits) + local ttstext = string.format("Target! %s! %s oh clock, %d %s!", ThreatTxt, targetdirection, targetdistance, dunits) + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) end return self end ---- [Internal] +--- [Internal] Targets Smoked -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -905,16 +1148,26 @@ end -- @param Core.Set#SET_UNIT TargetSet -- @return #PLAYERRECCE self function PLAYERRECCE:onafterTargetsSmoked(From, Event, To, Client, Playername, TargetSet) - self:I({From, Event, To}) - local callsign = Client:GetGroup():GetCustomCallSign(true,true) + self:T({From, Event, To}) + local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) - local text = string.format("All stations, FACA %s smoked targets\nat %s!",callsign, coordtext) - MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + if self.debug then + local text = string.format("All stations, FACA %s smoked targets\nat %s!",callsign, coordtext) + MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + end + local text = "Smoke on!" + local ttstext = "Smoke and Mirrors!" + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end return self end ---- [Internal] +--- [Internal] Targets Flared -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -924,16 +1177,26 @@ end -- @param Core.Set#SET_UNIT TargetSet -- @return #PLAYERRECCE self function PLAYERRECCE:onafterTargetsFlared(From, Event, To, Client, Playername, TargetSet) - self:I({From, Event, To}) - local callsign = Client:GetGroup():GetCustomCallSign(true,true) + self:T({From, Event, To}) + local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) - local text = string.format("All stations, FACA %s flared\ntargets at %s!",callsign, coordtext) - MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + if self.debug then + local text = string.format("All stations, FACA %s flared\ntargets at %s!",callsign, coordtext) + MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + end + local text = "Fireworks!" + local ttstext = "Fire works!" + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end return self end ---- [Internal] +--- [Internal] Target lasing -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -944,18 +1207,28 @@ end -- @param #number Lasingtime -- @return #PLAYERRECCE self function PLAYERRECCE:onafterTargetLasing(From, Event, To, Client, Target, Lasercode, Lasingtime) - self:I({From, Event, To}) - local callsign = Client:GetGroup():GetCustomCallSign(true,true) + self:T({From, Event, To}) + local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition,Settings) local targettype = Target:GetTypeName() - local text = string.format("All stations, FACA %s lasing %s\nat %s!\nCode %d, Duration %d seconds!",callsign, targettype, coordtext, Lasercode, Lasingtime) - MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + if self.debug then + local text = string.format("All stations, FACA %s lasing %s\nat %s!\nCode %d, Duration %d seconds!",callsign, targettype, coordtext, Lasercode, Lasingtime) + MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + end + local text = "Lasing!" + local ttstext = "Laser on!" + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end return self end ---- [Internal] +--- [Internal] Laser lost LOS -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -964,18 +1237,28 @@ end -- @param Wrapper.Unit#UNIT Target -- @return #PLAYERRECCE self function PLAYERRECCE:onafterTargetLOSLost(From, Event, To, Client, Target) - self:I({From, Event, To}) - local callsign = Client:GetGroup():GetCustomCallSign(true,true) + self:T({From, Event, To}) + local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition,Settings) local targettype = Target:GetTypeName() - local text = string.format("All stations, FACA %s lost sight of %s\nat %s!",callsign, targettype, coordtext) - MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + if self.debug then + local text = string.format("All stations, FACA %s lost sight of %s\nat %s!",callsign, targettype, coordtext) + MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) + end + local text = "Lost LOS!" + local ttstext = "Lost L O S!" + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end return self end ---- [Internal] +--- [Internal] Target report -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -986,7 +1269,7 @@ end -- @param #string Text -- @return #PLAYERRECCE self function PLAYERRECCE:onafterTargetReport(From, Event, To, Client, TargetSet, Target, Text) - self:I({From, Event, To}) + self:T({From, Event, To}) MESSAGE:New(Text,45,self.Name or "FACA"):ToClient(Client) if self.AttackSet then -- send message to AttackSet @@ -997,11 +1280,11 @@ function PLAYERRECCE:onafterTargetReport(From, Event, To, Client, TargetSet, Tar end end end - self:__TargetReportSent(-2,Client, TargetSet, Target, Text) + --self:__TargetReportSent(-2,Client, TargetSet, Target, Text) return self end ---- [Internal] +--- [Internal] Target data upload -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -1011,13 +1294,20 @@ end -- @param Wrapper.Unit#UNIT Target -- @param #string Text -- @return #PLAYERRECCE self -function PLAYERRECCE:onafterTargetReportSent(From, Event, To, Client, TargetSet, Target, Text) - self:I({From, Event, To}) +function PLAYERRECCE:onafterTargetReportSent(From, Event, To, Client, TargetSet) + self:T({From, Event, To}) + local text = "Upload completed!" + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(text,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end return self end ---- [Internal] +--- [Internal] Stop -- @param #PLAYERRECCE self -- @param #string From -- @param #string Event @@ -1034,9 +1324,6 @@ function PLAYERRECCE:onafterStop(From, Event, To) return self end ---[[ test script -local PlayerSet = SET_CLIENT:New():FilterCoalitions("blue"):FilterActive(true):FilterCategories("helicopter"):FilterStart() -local Attackers = SET_CLIENT:New():FilterCoalitions("blue"):FilterActive(true):FilterStart() -local myrecce = PLAYERRECCE:New("1st Forward FACA",coalition.side.BLUE,PlayerSet) -myrecce:SetAttackSet(Attackers) ---]] \ No newline at end of file +------------------------------------------------------------------------------------------ +-- TODO: END PLAYERRECCE +------------------------------------------------------------------------------------------ From 405e66ea72f65c44425194b8f9205cf85aebdd72 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 1 Oct 2022 16:36:29 +0200 Subject: [PATCH 2/9] #PLAYERTASK * SRS transmit option only when players are on --- Moose Development/Moose/Ops/PlayerTask.lua | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index 18ed99d5e..63edec3aa 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -761,6 +761,7 @@ do -- @field #table PlayerJoinMenu -- @field #table PlayerInfoMenu -- @field #boolean noflaresmokemenu +-- @field #boolean TransmitOnlyWithPlayers -- @extends Core.Fsm#FSM --- @@ -1063,6 +1064,7 @@ PLAYERTASKCONTROLLER = { PlayerJoinMenu = {}, PlayerInfoMenu = {}, noflaresmokemenu = false, + TransmitOnlyWithPlayers = true, } --- @@ -1221,7 +1223,7 @@ PLAYERTASKCONTROLLER.Messages = { --- PLAYERTASK class version. -- @field #string version -PLAYERTASKCONTROLLER.version="0.1.37" +PLAYERTASKCONTROLLER.version="0.1.38" --- Constructor -- @param #PLAYERTASKCONTROLLER self @@ -1407,6 +1409,18 @@ function PLAYERTASKCONTROLLER:SetDisableSmokeFlareTask() return self end +--- [User] For SRS - Switch to only transmit if there are players on the server. +-- @param #PLAYERTASKCONTROLLER self +-- @param #boolean Switch If true, only send SRS if there are alive Players. +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:SetTransmitOnlyWithPlayers(Switch) + self.TransmitOnlyWithPlayers = Switch + if self.SRSQueue then + self.SRSQueue:SetTransmitOnlyWithPlayers(Switch) + end + return self +end + --- [User] Show menu entries to smoke or flare targets (on by default!) -- @param #PLAYERTASKCONTROLLER self -- @return #PLAYERTASKCONTROLLER self @@ -3034,6 +3048,7 @@ function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Cultu self.SRS:SetGoogle(self.PathToGoogleKey) end self.SRSQueue = MSRSQUEUE:New(self.MenuName or self.Name) + self.SRSQueue:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers) return self end From 165a5d7364dd253fd5bedb96a33ae5d1edb516c5 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 2 Oct 2022 13:16:00 +0200 Subject: [PATCH 3/9] #PLAYERRECCE * Message improvements * Laser Distance 8km * Option to set RP Reference Point --- Moose Development/Moose/Ops/PlayerRecce.lua | 128 ++++++++++++++++---- 1 file changed, 104 insertions(+), 24 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index 64ad35b8f..c2fabce1a 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -28,7 +28,11 @@ ------------------------------------------------------------------------------------------------------------------- -- PLAYERRECCE -- TODO: PLAYERRECCE --- TODO: A lot... +-- DONE: No messages when no targets to flare or smoke +-- TODO: Flare smoke group, not all targets +-- DONE: Messages to Attack Group, use client settings +-- DONE: Lasing dist 8km +-- DONE: Reference Point RP ------------------------------------------------------------------------------------------------------------------- --- PLAYERRECCE class. @@ -61,6 +65,9 @@ -- @field #boolean ShortCallsign -- @field #boolean Keepnumber -- @field #table CallsignTranslations +-- @field Core.Point#COORDINATE ReferencePoint +-- @field #string RPName +-- @field Wrapper.Marker#MARKER RPMarker -- @extends Core.Fsm#FSM --- @@ -83,11 +90,11 @@ PLAYERRECCE = { ClassName = "PLAYERRECCE", verbose = true, lid = nil, - version = "0.0.5", + version = "0.0.6", ViewZone = {}, ViewZoneVisual = {}, PlayerSet = nil, - debug = true, + debug = false, LaserSpots = {}, UnitLaserCodes = {}, LaserCodes = {}, @@ -103,6 +110,7 @@ PLAYERRECCE = { ShortCallsign = true, Keepnumber = true, CallsignTranslations = nil, + ReferencePoint = nil, } --- @@ -119,10 +127,10 @@ PLAYERRECCE.LaserRelativePos = { -- @type MaxViewDistance -- @field #string typename Unit type name PLAYERRECCE.MaxViewDistance = { - ["SA342M"] = 5000, - ["SA342Mistral"] = 5000, - ["SA342Minigun"] = 5000, - ["SA342L"] = 5000, + ["SA342M"] = 8000, + ["SA342Mistral"] = 8000, + ["SA342Minigun"] = 8000, + ["SA342L"] = 8000, } --- @@ -141,7 +149,7 @@ PLAYERRECCE.Cameraheight = { PLAYERRECCE.CanLase = { ["SA342M"] = true, ["SA342Mistral"] = true, - ["SA342Minigun"] = false, + ["SA342Minigun"] = false, -- no optics ["SA342L"] = true, } @@ -274,6 +282,24 @@ function PLAYERRECCE:SetLaserCodes( LaserCodes ) return self end +--- [User] Set a reference point coordinate for A2G Operations. Will be used in coordinate references. +-- @param #PLAYERRECCE self +-- @param Core.Point#COORDINATE Coordinate Coordinate of the RP +-- @param #string Name Name of the RP +-- @return #PLAYERRECCE +function PLAYERRECCE:SetReferencePoint(Coordinate,Name) + self.ReferencePoint = Coordinate + self.RPName = 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()) + self.RPMarker = MARKER:New(Coordinate,text) + self.RPMarker:ReadOnly() + self.RPMarker:ToCoalition(self.Coalition) + return self +end + --- [User] Set PlayerTaskController. Allows to upload target reports to the controller, in turn creating tasks for other players. -- @param #PLAYERRECCE self -- @param Ops.PlayerTask#PLAYERTASKCONTROLLER Controller @@ -343,7 +369,7 @@ function PLAYERRECCE:_GetActualMaxLOSight(unit,vheading, vnod, vivoff) local maxview = 0 if unit and unit:IsAlive() then local typename = unit:GetTypeName() - maxview = self.MaxViewDistance[typename] or 5000 + maxview = self.MaxViewDistance[typename] or 8000 local CamHeight = self.Cameraheight[typename] or 0 if vnod > 0 then -- Looking down @@ -426,7 +452,7 @@ function PLAYERRECCE:_GetTargetSet(unit,camera) self:T(self.lid.."_GetTargetSet") local finaltargets = SET_UNIT:New() local finalcount = 0 - local heading,nod,maxview,angle = 0,30,5000,10 + local heading,nod,maxview,angle = 0,30,8000,10 local camon = true local typename = unit:GetTypeName() local name = unit:GetName() @@ -633,7 +659,9 @@ function PLAYERRECCE:_SmokeTargets(client,group,playername) local cameraset = self:_GetTargetSet(client,true) -- Core.Set#SET_UNIT local visualset = self:_GetTargetSet(client,false) -- Core.Set#SET_UNIT cameraset:AddSet(visualset) - self:__TargetsSmoked(-1,client,playername,cameraset) + if cameraset:CountAlive() > 0 then + self:__TargetsSmoked(-1,client,playername,cameraset) + end local highsmoke = SMOKECOLOR.Orange local medsmoke = SMOKECOLOR.White local lowsmoke = SMOKECOLOR.Green @@ -677,7 +705,9 @@ function PLAYERRECCE:_FlareTargets(client,group,playername) local cameraset = self:_GetTargetSet(client,true) -- Core.Set#SET_UNIT local visualset = self:_GetTargetSet(client,false) -- Core.Set#SET_UNIT cameraset:AddSet(visualset) - self:__TargetsFlared(-1,client,playername,cameraset) + if cameraset:CountAlive() > 0 then + self:__TargetsFlared(-1,client,playername,cameraset) + end local highsmoke = FLARECOLOR.Yellow local medsmoke = FLARECOLOR.White local lowsmoke = FLARECOLOR.Green @@ -754,8 +784,11 @@ self:T(self.lid.."_ReportLaserTargets") report:Add(string.rep("-",15)) report:Add("Target type: "..target:GetTypeName()) report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")") - report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings)) - --report:Add("Location: "..target:GetCoordinate():ToStringA2G(client,Settings)) + if not self.ReferencePoint then + report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings)) + else + report:Add("Location: "..client:GetCoordinate():ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings)) + end report:Add("Laser Code: "..self.UnitLaserCodes[playername] or 1688) report:Add(string.rep("-",15)) local text = report:Text() @@ -794,8 +827,11 @@ function PLAYERRECCE:_ReportVisualTargets(client,group,playername) report:Add(string.rep("-",15)) report:Add("Target count: "..number) report:Add("Threat Level: "..ThreatGraph.." ("..ThreatLevelText..")") - report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings)) - --report:Add("Location: "..client:GetCoordinate():ToStringA2G(client,Settings)) + if not self.ReferencePoint then + report:Add("Location: "..client:GetCoordinate():ToStringBULLS(self.Coalition,Settings)) + else + report:Add("Location: "..client:GetCoordinate():ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings)) + end report:Add(string.rep("-",15)) local text = report:Text() self:__TargetReport(-1,client,targetset,nil,text) @@ -1050,6 +1086,10 @@ function PLAYERRECCE:onafterRecceOnStation(From, Event, To, Client, Playername) local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) + if self.ReferencePoint then + local Settings = Client and _DATABASE:GetPlayerSettings(Playername) or _SETTINGS -- Core.Settings#SETTINGS + coordtext = coord:ToStringFromRPShort(self.ReferencePoint,self.RPName,Client,Settings) + end if self.debug then local text = string.format("All stations, FACA %s on station\nat %s!",callsign, coordtext) MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) @@ -1060,8 +1100,9 @@ function PLAYERRECCE:onafterRecceOnStation(From, Event, To, Client, Playername) text2tts = self:_GetTextForSpeech(text2tts) if self.UseSRS then local grp = Client:GetGroup() - self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2,{grp},text1,10) - self.SRSQueue:NewTransmission(text2tts,nil,self.SRS,nil,1,{grp},text2,10) + self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2) + self.SRSQueue:NewTransmission(text2tts,nil,self.SRS,nil,2) + MESSAGE:New(text2,10,self.Name or "FACA"):ToCoalition(self.Coalition) else MESSAGE:New(text1,10,self.Name or "FACA"):ToClient(Client) MESSAGE:New(text2,10,self.Name or "FACA"):ToClient(Client) @@ -1082,6 +1123,10 @@ function PLAYERRECCE:onafterRecceOffStation(From, Event, To, Client, Playername) local callsign = Client:GetGroup():GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations) local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) + if self.ReferencePoint then + local Settings = Client and _DATABASE:GetPlayerSettings(Playername) or _SETTINGS -- Core.Settings#SETTINGS + coordtext = coord:ToStringFromRPShort(self.ReferencePoint,self.RPName,Client,Settings) + end local text = string.format("All stations, FACA %s leaving station\nat %s, good bye!",callsign, coordtext) local texttts = string.format("All stations, FACA %s leaving station at %s, good bye!",callsign, coordtext) texttts = self:_GetTextForSpeech(texttts) @@ -1091,8 +1136,9 @@ function PLAYERRECCE:onafterRecceOffStation(From, Event, To, Client, Playername) local text1 = "Going home!" if self.UseSRS then local grp = Client:GetGroup() - self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2,{grp},text1,10) - self.SRSQueue:NewTransmission(texttts,nil,self.SRS,nil,2,{grp},text,10) + self.SRSQueue:NewTransmission(text1,nil,self.SRS,nil,2) + self.SRSQueue:NewTransmission(texttts,nil,self.SRS,nil,2) + MESSAGE:New(text,10,self.Name or "FACA"):ToCoalition(self.Coalition) else MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) end @@ -1153,9 +1199,23 @@ function PLAYERRECCE:onafterTargetsSmoked(From, Event, To, Client, Playername, T local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) if self.debug then - local text = string.format("All stations, FACA %s smoked targets\nat %s!",callsign, coordtext) + local text = string.format("All stations, %s smoked targets\nat %s!",callsign, coordtext) MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) end + if self.AttackSet then + for _,_client in pairs(self.AttackSet.Set) do + local client = _client --Wrapper.Client#CLIENT + if client and client:IsAlive() then + local Settings = client and _DATABASE:GetPlayerSettings(client:GetPlayerName()) or _SETTINGS + local coordtext = coord:ToStringA2G(client,Settings) + if self.ReferencePoint then + coordtext = coord:ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings) + end + local text = string.format("All stations, %s smoked targets\nat %s!",callsign, coordtext) + MESSAGE:New(text,15,self.Name or "FACA"):ToClient(client) + end + end + end local text = "Smoke on!" local ttstext = "Smoke and Mirrors!" if self.UseSRS then @@ -1182,9 +1242,23 @@ function PLAYERRECCE:onafterTargetsFlared(From, Event, To, Client, Playername, T local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition) if self.debug then - local text = string.format("All stations, FACA %s flared\ntargets at %s!",callsign, coordtext) + local text = string.format("All stations, %s flared\ntargets at %s!",callsign, coordtext) MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) end + if self.AttackSet then + for _,_client in pairs(self.AttackSet.Set) do + local client = _client --Wrapper.Client#CLIENT + if client and client:IsAlive() then + local Settings = client and _DATABASE:GetPlayerSettings(client:GetPlayerName()) or _SETTINGS + if self.ReferencePoint then + coordtext = coord:ToStringFromRPShort(self.ReferencePoint,self.RPName,client,Settings) + end + local coordtext = coord:ToStringA2G(client,Settings) + local text = string.format("All stations, %s flared targets\nat %s!",callsign, coordtext) + MESSAGE:New(text,15,self.Name or "FACA"):ToClient(client) + end + end + end local text = "Fireworks!" local ttstext = "Fire works!" if self.UseSRS then @@ -1212,9 +1286,12 @@ function PLAYERRECCE:onafterTargetLasing(From, Event, To, Client, Target, Laserc local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition,Settings) + if self.ReferencePoint then + coordtext = coord:ToStringFromRPShort(self.ReferencePoint,self.RPName,Client,Settings) + end local targettype = Target:GetTypeName() if self.debug then - local text = string.format("All stations, FACA %s lasing %s\nat %s!\nCode %d, Duration %d seconds!",callsign, targettype, coordtext, Lasercode, Lasingtime) + local text = string.format("All stations, %s lasing %s\nat %s!\nCode %d, Duration %d seconds!",callsign, targettype, coordtext, Lasercode, Lasingtime) MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) end local text = "Lasing!" @@ -1242,9 +1319,12 @@ function PLAYERRECCE:onafterTargetLOSLost(From, Event, To, Client, Target) local Settings = ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS local coord = Client:GetCoordinate() local coordtext = coord:ToStringBULLS(self.Coalition,Settings) + if self.ReferencePoint then + coordtext = coord:ToStringFromRPShort(self.ReferencePoint,self.RPName,Client,Settings) + end local targettype = Target:GetTypeName() if self.debug then - local text = string.format("All stations, FACA %s lost sight of %s\nat %s!",callsign, targettype, coordtext) + local text = string.format("All stations, %s lost sight of %s\nat %s!",callsign, targettype, coordtext) MESSAGE:New(text,15,self.Name or "FACA"):ToCoalition(self.Coalition) end local text = "Lost LOS!" From 60cf7506f893eccaf89d49254d799ad10ee14e91 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 2 Oct 2022 16:10:11 +0200 Subject: [PATCH 4/9] Update Airboss.lua - Added `landingdist` as carrier parameter and into LSO result - Case III does not check groove time for unicorns --- Moose Development/Moose/Ops/Airboss.lua | 131 +++++++++++++----------- 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index bfa135ab5..805e0cdb4 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -1332,6 +1332,7 @@ AIRBOSS.CarrierType = { -- @field #number wire2 Distance in meters from carrier position to second wire. -- @field #number wire3 Distance in meters from carrier position to third wire. -- @field #number wire4 Distance in meters from carrier position to fourth wire. +-- @field #number landingdist Distance in meeters to the landing position. -- @field #number rwylength Length of the landing runway in meters. -- @field #number rwywidth Width of the landing runway in meters. -- @field #number totlength Total length of carrier. @@ -1978,7 +1979,7 @@ function AIRBOSS:New( carriername, alias ) -- Init carrier parameters. if self.carriertype == AIRBOSS.CarrierType.STENNIS then - --self:_InitStennis() + -- Stennis parameters were updated to match the other Super Carriers. self:_InitNimitz() elseif self.carriertype == AIRBOSS.CarrierType.ROOSEVELT then self:_InitNimitz() @@ -1991,7 +1992,7 @@ function AIRBOSS:New( carriername, alias ) elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then self:_InitForrestal() elseif self.carriertype == AIRBOSS.CarrierType.VINSON then - -- TODO: Carl Vinson parameters. + -- Carl Vinson is legacy now. self:_InitStennis() elseif self.carriertype == AIRBOSS.CarrierType.HERMES then -- Hermes parameters. @@ -2006,8 +2007,8 @@ function AIRBOSS:New( carriername, alias ) -- Use Juan Carlos parameters. self:_InitJcarlos() elseif self.carriertype == AIRBOSS.CarrierType.CANBERRA then - -- Use Juan Carlos parameters at this stage --TODO Check primary Landing spot. - self:_InitJcarlos() + -- Use Juan Carlos parameters at this stage. + self:_InitCanberra() elseif self.carriertype == AIRBOSS.CarrierType.KUZNETSOV then -- Kusnetsov parameters - maybe... self:_InitStennis() @@ -4286,6 +4287,9 @@ function AIRBOSS:_InitStennis() self.carrierparam.wire3 = 46 + 24 self.carrierparam.wire4 = 46 + 35 -- Last wire is strangely one meter closer. + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3 + -- Platform at 5k. Reduce descent rate to 2000 ft/min to 1200 dirty up level flight. self.Platform.name = "Platform 5k" self.Platform.Xmin = -UTILS.NMToMeters( 22 ) -- Not more than 22 NM behind the boat. Last check was at 21 NM. @@ -4436,6 +4440,9 @@ function AIRBOSS:_InitNimitz() self.carrierparam.wire3 = 79 self.carrierparam.wire4 = 92 + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3 + end --- Init parameters for Forrestal class super carriers. @@ -4465,6 +4472,9 @@ function AIRBOSS:_InitForrestal() self.carrierparam.wire3 = 64 -- 62 self.carrierparam.wire4 = 74 -- 72.5 + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3 + end --- Init parameters for R12 HMS Hermes carrier. @@ -4494,6 +4504,12 @@ function AIRBOSS:_InitHermes() self.carrierparam.wire3 = nil self.carrierparam.wire4 = nil + -- Distance to landing spot. + self.carrierparam.landingspot=69 + + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot + -- Late break. self.BreakLate.name = "Late Break" self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. @@ -4534,6 +4550,12 @@ function AIRBOSS:_InitTarawa() self.carrierparam.wire3 = nil self.carrierparam.wire4 = nil + -- Distance to landing spot. + self.carrierparam.landingspot=57 + + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot + -- Late break. self.BreakLate.name = "Late Break" self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. @@ -4574,6 +4596,12 @@ function AIRBOSS:_InitAmerica() self.carrierparam.wire3 = nil self.carrierparam.wire4 = nil + -- Distance to landing spot. + self.carrierparam.landingspot=59 + + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot + -- Late break. self.BreakLate.name = "Late Break" self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. @@ -4614,6 +4642,12 @@ function AIRBOSS:_InitJcarlos() self.carrierparam.wire3 = nil self.carrierparam.wire4 = nil + -- Distance to landing spot. + self.carrierparam.landingspot=89 + + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot + -- Late break. self.BreakLate.name = "Late Break" self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. @@ -4626,6 +4660,16 @@ function AIRBOSS:_InitJcarlos() self.BreakLate.LimitZmax = nil end + +--- Init parameters for L02 Canberra carrier. +-- @param #AIRBOSS self +function AIRBOSS:_InitCanberra() + + -- Init Juan Carlos as default. + self:_InitJcarlos() + +end + --- Init parameters for Marshal Voice overs *Gabriella* by HighwaymanEd. -- @param #AIRBOSS self -- @param #string mizfolder (Optional) Folder within miz file where the sound files are located. @@ -5396,7 +5440,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 300 ) -- ? elseif harrier then alt=UTILS.FeetToMeters(312)-- 300-325 ft - end aoa = aoaac.OnSpeed @@ -11134,28 +11177,31 @@ function AIRBOSS:_GetOptLandingCoordinate() -- Start with stern coordiante. self.landingcoord:UpdateFromCoordinate( self:_GetSternCoord() ) - -- Stern coordinate. - -- local stern=self:_GetSternCoord() -- Final bearing. - local FB=self:GetFinalBearing(false) + + -- Cse local case=self.case + -- set Case III V/STOL abeam landing spot over deck -- Pene Testing if self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then if case==3 then - self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()) - -- Altitude 120ft -- is this corect for Case III? - self.landingcoord:SetAltitude(UTILS.FeetToMeters(120)) + + -- Landing coordinate. + self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()) + + -- Altitude 120ft -- is this corect for Case III? + self.landingcoord:SetAltitude(UTILS.FeetToMeters(120)) elseif case==2 or case==1 then - -- Landing 100 ft abeam, 120 ft alt. - self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()):Translate(35, FB-90, true, true) - --stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90) + -- Landing 100 ft abeam, 120 ft alt. + self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()):Translate(35, FB-90, true, true) + + -- Alitude 120 ft. + self.landingcoord:SetAltitude(UTILS.FeetToMeters(120)) - -- Alitude 120 ft. - self.landingcoord:SetAltitude(UTILS.FeetToMeters(120)) end else @@ -11163,8 +11209,7 @@ function AIRBOSS:_GetOptLandingCoordinate() -- Ideally we want to land between 2nd and 3rd wire. if self.carrierparam.wire3 then -- We take the position of the 3rd wire to approximately account for the length of the aircraft. - local w3 = self.carrierparam.wire3 - self.landingcoord:Translate( w3, FB, true, true ) + self.landingcoord:Translate( self.carrierparam.wire3, FB, true, true ) end -- Add 2 meters to account for aircraft height. @@ -11175,54 +11220,19 @@ function AIRBOSS:_GetOptLandingCoordinate() return self.landingcoord end ---- Get landing spot on Tarawa. +--- Get landing spot on Tarawa and others. -- @param #AIRBOSS self -- @return Core.Point#COORDINATE Primary landing spot coordinate. function AIRBOSS:_GetLandingSpotCoordinate() + -- Start at stern coordinate. self.landingspotcoord:UpdateFromCoordinate( self:_GetSternCoord() ) - -- Stern coordinate. - -- local stern=self:_GetSternCoord() + -- Landing 100 ft abeam, 100 alt. + local hdg = self:GetHeading() - if self.carriertype==AIRBOSS.CarrierType.HERMES then - - -- Landing 100 ft abeam, 100 alt. - local hdg = self:GetHeading() - - -- Primary landing spot 5 - self.landingspotcoord:Translate( 69, hdg, true, true ):SetAltitude( self.carrierparam.deckheight ) - elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then - - -- Landing 100 ft abeam, 120 alt. - local hdg = self:GetHeading() - - -- Primary landing spot 7.5 - self.landingspotcoord:Translate( 57, hdg, true, true ):SetAltitude( self.carrierparam.deckheight ) - elseif self.carriertype == AIRBOSS.CarrierType.AMERICA then - - -- Landing 100 ft abeam, 120 alt. - local hdg = self:GetHeading() - - -- Primary landing spot 7.5 a little further forwad on the America - self.landingspotcoord:Translate( 59, hdg, true, true ):SetAltitude( self.carrierparam.deckheight ) - - elseif self.carriertype == AIRBOSS.CarrierType.JCARLOS then - - -- Landing 100 ft abeam, 120 alt. - local hdg = self:GetHeading() - - -- Primary landing spot 5.0 -- Done voice for different landing Spots. - self.landingspotcoord:Translate( 89, hdg, true, true ):SetAltitude( self.carrierparam.deckheight ) - - elseif self.carriertype == AIRBOSS.CarrierType.CANBERRA then - - -- Landing 100 ft abeam, 120 alt. - local hdg = self:GetHeading() - - -- Primary landing spot 5.0 -- Done voice for different landing Spots. - self.landingspotcoord:Translate( 89, hdg, true, true ):SetAltitude( self.carrierparam.deckheight ) - end + -- Primary landing spot. Different carriers handled via carrier parameter landingspot now. + self.landingspotcoord:Translate( self.carrierparam.landingspot, hdg, true, true ):SetAltitude( self.carrierparam.deckheight ) return self.landingspotcoord end @@ -11796,7 +11806,7 @@ function AIRBOSS:_LSOgrade( playerData ) local grade local points - if N == 0 and (TgrooveUnicorn or TgrooveVstolUnicorn) then + if N == 0 and (TgrooveUnicorn or TgrooveVstolUnicorn or playerData.case==3) then -- No deviations, should be REALLY RARE! grade = "_OK_" points = 5.0 @@ -17961,6 +17971,7 @@ function AIRBOSS:onafterLSOGrade(From, Event, To, playerData, grade) result.carriertype=grade.carriertype result.carriername=grade.carriername result.carrierrwy=grade.carrierrwy + result.landingdist=self.carrierparam.landingdist result.theatre=grade.theatre result.case=playerData.case result.Tgroove=grade.Tgroove From 42baf6c8d224ccc0750509fc8318128d9efb03da Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 2 Oct 2022 19:13:51 +0200 Subject: [PATCH 5/9] AIRBOSS v1.3.0 - Added Invincible parameters from master branch - Increased version number --- Moose Development/Moose/Ops/Airboss.lua | 106 +++++++++++++++++------- 1 file changed, 77 insertions(+), 29 deletions(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 805e0cdb4..118b9e642 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -33,6 +33,7 @@ -- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module] -- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_(CV-59)) (CV-59) [Heatblur Carrier Module] -- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_(R12)) (R12) [**WIP**] +-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05) (R05) [**WIP**] -- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1)) (LHA-1) [**WIP**] -- * [USS America](https://en.wikipedia.org/wiki/USS_America_(LHA-6)) (LHA-6) [**WIP**] -- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61) [**WIP**] @@ -115,6 +116,7 @@ -- * [Harrier Ship Landing Mission with Auto LSO!](https://www.youtube.com/watch?v=lqmVvpunk2c) -- * [Updated Airboss V/STOL Features USS Tarawa](https://youtu.be/K7I4pU6j718) -- * [Harrier Practice pattern USS America](https://youtu.be/99NigITYmcI) +-- * [Harrier CASE III TACAN Approach USS Tarawa](https://www.youtube.com/watch?v=bTgJXZ9Mhdc&t=1s) -- * [Harrier CASE III TACAN Approach USS Tarawa](https://www.youtube.com/watch?v=wWHag5WpNZ0) -- -- === @@ -1265,7 +1267,7 @@ AIRBOSS = { --- Aircraft types capable of landing on carrier (human+AI). -- @type AIRBOSS.AircraftCarrier --- @field #string AV8B AV-8B Night Harrier. Works only with the HMS Hermes, USS Tarawa, USS America, and Juan Carlos I. +-- @field #string AV8B AV-8B Night Harrier. Works only with the HMS Hermes, HMS Invincible, USS Tarawa, USS America, and Juan Carlos I. -- @field #string A4EC A-4E Community mod. -- @field #string HORNET F/A-18C Lot 20 Hornet by Eagle Dynamics. -- @field #string F14A F-14A by Heatblur. @@ -1302,6 +1304,7 @@ AIRBOSS.AircraftCarrier={ -- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module] -- @field #string VINSON USS Carl Vinson (CVN-70) [Obsolete] -- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier] +-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier] -- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier] -- @field #string AMERICA USS America (LHA-6) [V/STOL Carrier] -- @field #string JCARLOS Juan Carlos I (L61) [V/STOL Carrier] @@ -1316,6 +1319,7 @@ AIRBOSS.CarrierType = { FORRESTAL = "Forrestal", VINSON = "VINSON", HERMES = "HERMES81", + INVINCIBLE = "hms_invincible", TARAWA = "LHA_Tarawa", AMERICA = "USS America LHA-6", JCARLOS = "L61", @@ -1732,7 +1736,7 @@ AIRBOSS.MenuF10Root = nil --- Airboss class version. -- @field #string version -AIRBOSS.version = "1.2.1" +AIRBOSS.version = "1.3.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -1997,6 +2001,9 @@ function AIRBOSS:New( carriername, alias ) elseif self.carriertype == AIRBOSS.CarrierType.HERMES then -- Hermes parameters. self:_InitHermes() + elseif self.carriertype == AIRBOSS.CarrierType.INVINCIBLE then + -- Invincible parameters. + self:_InitInvincible() elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then -- Tarawa parameters. self:_InitTarawa() @@ -2099,7 +2106,7 @@ function AIRBOSS:New( carriername, alias ) -- cL:FlareYellow() -- Carrier specific. - if self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.HERMES or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.TARAWA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.AMERICA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.JCARLOS or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.CANBERRA then + if self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.INVINCIBLE or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.HERMES or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.TARAWA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.AMERICA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.JCARLOS or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.CANBERRA then -- Flare wires. local w1 = stern:Translate( self.carrierparam.wire1, FB, true ) @@ -2832,7 +2839,7 @@ end function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW) --Check if V/STOL Carrier - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then -- allow a larger GSE for V/STOL operations --Pene Testing self.gle._max=_max or 0.7 @@ -2869,7 +2876,7 @@ end function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LeftMed, LEFT, Right, RightMed, RIGHT) --Check if V/STOL Carrier -- Pene testing - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then -- V/STOL Values -- allow a larger LUE for V/STOL operations self.lue._max=_max or 1.8 @@ -3024,7 +3031,6 @@ end -- @param #AIRBOSS self -- @param #number TimeInterval (Optional) Time interval in seconds. Default 1200 sec = 20 min. -- @return #AIRBOSS self - function AIRBOSS:SetBeaconRefresh( TimeInterval ) self.dTbeacon = TimeInterval or (20 * 60) return self @@ -4514,8 +4520,54 @@ function AIRBOSS:_InitHermes() self.BreakLate.name = "Late Break" self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. self.BreakLate.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks? - self.BreakLate.Zmin = -UTILS.NMToMeters( 0.25 ) -- Not more than 0.25 NM port. - self.BreakLate.Zmax = UTILS.NMToMeters( 0.5 ) -- Not more than 0.5 NM starboard. + self.BreakLate.Zmin = -UTILS.NMToMeters( 1.6 ) -- Not more than 1.6 NM port. + self.BreakLate.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard. + self.BreakLate.LimitXmin = 0 -- Check and next step 0.8 NM port and in front of boat. + self.BreakLate.LimitXmax = nil + self.BreakLate.LimitZmin = -UTILS.NMToMeters( 0.5 ) -- 926 m port, closer than the stennis as abeam is 0.8-1.0 rather than 1.2 + self.BreakLate.LimitZmax = nil + +end + +--- Init parameters for R05 HMS Invincible carrier. +-- @param #AIRBOSS self +function AIRBOSS:_InitInvincible() + + -- Init Stennis as default. + self:_InitStennis() + + -- Carrier Parameters. + self.carrierparam.sterndist = -105 + self.carrierparam.deckheight = 12 -- From model viewer WL0. + + -- Total size of the carrier (approx as rectangle). + self.carrierparam.totlength = 228.19 + self.carrierparam.totwidthport = 20.5 + self.carrierparam.totwidthstarboard = 24.5 + + -- Landing runway. + self.carrierparam.rwyangle = 0 + self.carrierparam.rwylength = 215 + self.carrierparam.rwywidth = 13 + + -- Wires. + self.carrierparam.wire1 = nil + self.carrierparam.wire2 = nil + self.carrierparam.wire3 = nil + self.carrierparam.wire4 = nil + + -- Distance to landing spot. + self.carrierparam.landingspot=69 + + -- Landing distance. + self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.landingspot + + -- Late break. + self.BreakLate.name = "Late Break" + self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0. + self.BreakLate.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks? + self.BreakLate.Zmin = -UTILS.NMToMeters( 1.6 ) -- Not more than 1.6 NM port. + self.BreakLate.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard. self.BreakLate.LimitXmin = 0 -- Check and next step 0.8 NM port and in front of boat. self.BreakLate.LimitXmax = nil self.BreakLate.LimitZmin = -UTILS.NMToMeters( 0.5 ) -- 926 m port, closer than the stennis as abeam is 0.8-1.0 rather than 1.2 @@ -5346,7 +5398,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step ) alt = UTILS.FeetToMeters( 800 ) speed = UTILS.KnotsToMps( 350 ) elseif skyhawk then - alt = UTILS.FeetToMeters( 600 ) speed = UTILS.KnotsToMps( 250 ) elseif goshawk then @@ -6384,7 +6435,7 @@ function AIRBOSS:_GetMarshalAltitude( stack, case ) p2 = Carrier:Translate( UTILS.NMToMeters( 1.5 ), hdg ) -- Tarawa,LHA,LHD Delta patterns. - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then -- Pattern is directly overhead the carrier. p1 = Carrier:Translate( UTILS.NMToMeters( 1.0 ), hdg + 90 ) @@ -8223,7 +8274,7 @@ function AIRBOSS:OnEventLand( EventData ) self:T( self.lid .. text ) -- Check carrier type. - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then -- Power "Idle". self:RadioTransmission( self.LSORadio, self.LSOCall.IDLE, false, 1, nil, true ) @@ -8258,8 +8309,7 @@ function AIRBOSS:OnEventLand( EventData ) -- AI unit landed -- -------------------- - if self.carriertype ~= AIRBOSS.CarrierType.HERMES or self.carriertype ~= AIRBOSS.CarrierType.TARAWA or self.carriertype ~= AIRBOSS.CarrierType.AMERICA or self.carriertype ~= AIRBOSS.CarrierType.JCARLOS or self.carriertype ~= AIRBOSS.CarrierType.CANBERRA then - + if self.carriertype ~= AIRBOSS.CarrierType.INVINCIBLE or self.carriertype ~= AIRBOSS.CarrierType.HERMES or self.carriertype ~= AIRBOSS.CarrierType.TARAWA or self.carriertype ~= AIRBOSS.CarrierType.AMERICA or self.carriertype ~= AIRBOSS.CarrierType.JCARLOS or self.carriertype ~= AIRBOSS.CarrierType.CANBERRA then -- Coordinate at landing event local coord = EventData.IniUnit:GetCoordinate() @@ -9297,7 +9347,7 @@ function AIRBOSS:_CheckForLongDownwind( playerData ) local limit = UTILS.NMToMeters( -1.6 ) -- For the tarawa, other LHA and LHD we give a bit more space. - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then limit = UTILS.NMToMeters( -2.0 ) end @@ -9384,8 +9434,7 @@ function AIRBOSS:_Ninety( playerData ) self:_PlayerHint( playerData ) -- Next step: wake. - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then - + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then -- Harrier has no wake stop. It stays port of the boat. self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.FINAL ) else @@ -10080,7 +10129,7 @@ function AIRBOSS:_GetSternCoord() -- local stern=self:GetCoordinate() -- Stern coordinate (sterndist<0). --Pene testing Case III - if self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then + if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then if case==3 then -- CASE III V/STOL translation Due over deck approach if needed. self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true) @@ -10130,7 +10179,6 @@ function AIRBOSS:_GetWire( Lcoord, dc ) -- Multiplayer wire correction. if self.mpWireCorrection then d = d - self.mpWireCorrection - end -- Shift wires from stern to their correct position. @@ -10722,7 +10770,7 @@ function AIRBOSS:_GetZoneRunwayBox() return self.zoneRunwaybox end ---- Get zone of primary abeam landing position of HMS Hermes, USS Tarawa, USS America and Juan Carlos. Box length 50 meters and width 30 meters. +--- Get zone of primary abeam landing position of HMS Hermes, HMS Invincible, USS Tarawa, USS America and Juan Carlos. Box length 50 meters and width 30 meters. --- Allow for Clear to land call from LSO approaching abeam the landing spot if stable as per NATOPS 00-80T -- @param #AIRBOSS self @@ -10827,7 +10875,7 @@ function AIRBOSS:_GetZoneHolding( case, stack ) self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", Post:GetVec2(), self.marshalradius ) -- Delta pattern. - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", self.carrier:GetVec2(), UTILS.NMToMeters( 5 ) ) end @@ -10879,7 +10927,7 @@ function AIRBOSS:_GetZoneCommence( case, stack ) -- Three position local Three = self:GetCoordinate():Translate( D, hdg + 275 ) - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then local Dx = UTILS.NMToMeters( 2.25 ) local Dz = UTILS.NMToMeters( 2.25 ) @@ -11169,7 +11217,7 @@ function AIRBOSS:_GetAltCarrier( unit ) return h end ---- Get optimal landing position of the aircraft. Usually between second and third wire. In case of Tarawa, Canberrra, Juan Carlos and America we take the abeam landing spot 120 ft above and 21 ft abeam the 7.5 position, for the Juan Carlos I and HMS Hermes it is 120 ft above and 21 ft abeam the 5 position. For CASE III it is 120ft directly above the landing spot. +--- Get optimal landing position of the aircraft. Usually between second and third wire. In case of Tarawa, Canberrra, Juan Carlos and America we take the abeam landing spot 120 ft above and 21 ft abeam the 7.5 position, for the Juan Carlos I, HMS Invincible, and HMS Hermes and Invincible it is 120 ft above and 21 ft abeam the 5 position. For CASE III it is 120ft directly above the landing spot. -- @param #AIRBOSS self -- @return Core.Point#COORDINATE Optimal landing coordinate. function AIRBOSS:_GetOptLandingCoordinate() @@ -11184,7 +11232,7 @@ function AIRBOSS:_GetOptLandingCoordinate() local case=self.case -- set Case III V/STOL abeam landing spot over deck -- Pene Testing - if self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then + if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then if case==3 then @@ -11280,8 +11328,8 @@ function AIRBOSS:GetWind( alt, magnetic, coord ) -- Current position of the carrier or input. local cv = coord or self:GetCoordinate() - -- Wind direction and speed. By default at 50 meters ASL. - local Wdir, Wspeed = cv:GetWind( alt or 15 ) + -- Wind direction and speed. By default at 18 meters ASL. + local Wdir, Wspeed = cv:GetWind( alt or 18 ) -- Include magnetic declination. if magnetic then @@ -12143,7 +12191,7 @@ function AIRBOSS:_GS( step, n ) if n == -1 then gp = AIRBOSS.GroovePos.IC elseif n == 1 then - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then gp = AIRBOSS.GroovePos.AL else gp = AIRBOSS.GroovePos.IW @@ -14026,7 +14074,7 @@ function AIRBOSS:_IsCarrierAircraft( unit ) -- Special case for Harrier which can only land on Tarawa, LHA and LHD. if aircrafttype == AIRBOSS.AircraftCarrier.AV8B then - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then return true else return false @@ -14034,7 +14082,7 @@ function AIRBOSS:_IsCarrierAircraft( unit ) end -- Also only Harriers can land on the Tarawa, LHA and LHD. - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then if aircrafttype ~= AIRBOSS.AircraftCarrier.AV8B then return false end @@ -17482,7 +17530,7 @@ function AIRBOSS:_MarkCaseZones( _unitName, flare ) end -- Tarawa, LHA and LHD landing spots. - if self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then + if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then text = text .. "\n* abeam landing stop with RED flares" -- Abeam landing spot zone. local ALSPT = self:_GetZoneAbeamLandingSpot() From 39bb95f12718c1ea55c0226ebd1e885fd3e2b5ac Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 2 Oct 2022 19:34:04 +0200 Subject: [PATCH 6/9] #PLAYERRECCE -- DONE: Sort for multiple targets in one direction -- DONE: Targets with forget timeout, also report --- Moose Development/Moose/Ops/PlayerRecce.lua | 257 ++++++++++++++++---- 1 file changed, 212 insertions(+), 45 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerRecce.lua b/Moose Development/Moose/Ops/PlayerRecce.lua index c2fabce1a..fcef0bcb9 100644 --- a/Moose Development/Moose/Ops/PlayerRecce.lua +++ b/Moose Development/Moose/Ops/PlayerRecce.lua @@ -33,6 +33,8 @@ -- DONE: Messages to Attack Group, use client settings -- DONE: Lasing dist 8km -- DONE: Reference Point RP +-- DONE: Sort for multiple targets in one direction +-- DONE: Targets with forget timeout, also report ------------------------------------------------------------------------------------------------------------------- --- PLAYERRECCE class. @@ -68,6 +70,8 @@ -- @field Core.Point#COORDINATE ReferencePoint -- @field #string RPName -- @field Wrapper.Marker#MARKER RPMarker +-- @field #number TForget +-- @field Utilities.FiFo#FIFO TargetCache -- @extends Core.Fsm#FSM --- @@ -90,11 +94,11 @@ PLAYERRECCE = { ClassName = "PLAYERRECCE", verbose = true, lid = nil, - version = "0.0.6", + version = "0.0.8", ViewZone = {}, ViewZoneVisual = {}, PlayerSet = nil, - debug = false, + debug = true, LaserSpots = {}, UnitLaserCodes = {}, LaserCodes = {}, @@ -111,8 +115,17 @@ PLAYERRECCE = { Keepnumber = true, CallsignTranslations = nil, ReferencePoint = nil, + TForget = 600, + TargetCache = nil, } +--- +-- @type PlayerRecceDetected +-- @field #boolean detected +-- @field Wrapper.Client#CLIENT recce +-- @field #string playername +-- @field #number timestamp + --- -- @type LaserRelativePos -- @field #string typename Unit type name @@ -153,6 +166,28 @@ PLAYERRECCE.CanLase = { ["SA342L"] = true, } +--- +-- @type SmokeColor +-- @field #string color +PLAYERRECCE.SmokeColor = { + ["highsmoke"] = SMOKECOLOR.Orange, + ["medsmoke"] = SMOKECOLOR.White, + ["lowsmoke"] = SMOKECOLOR.Green, + ["lasersmoke"] = SMOKECOLOR.Red, + ["ownsmoke"] = SMOKECOLOR.Blue, +} + +--- +-- @type FlareColor +-- @field #string color +PLAYERRECCE.FlareColor = { + ["highflare"] =FLARECOLOR.Yellow, + ["medflare"] = FLARECOLOR.White, + ["lowflare"] = FLARECOLOR.Green, + ["laserflare"] = FLARECOLOR.Red, + ["ownflare"] = FLARECOLOR.Green, +} + --- Create and rund a new PlayerRecce instance. -- @param #PLAYERRECCE self -- @param #string Name The name of this instance @@ -176,6 +211,9 @@ function PLAYERRECCE:New(Name, Coalition, PlayerSet) self.minthreatlevel = 0 + self.TForget = 600 + self.TargetCache = FIFO:New() + -- FSM start state is STOPPED. self:SetStartState("Stopped") @@ -442,6 +480,60 @@ function PLAYERRECCE:_GetViewZone(unit, vheading, vnod, maxview, angle, camon, d return viewzone end +--- [Internal] +--@param #PLAYERRECCE self +--@param Wrapper.Client#CLIENT client +--@return Core.Set#SET_UNIT Set of targets, can be empty! +--@return #number count Count of targets +function PLAYERRECCE:_GetKnownTargets(client) + self:T(self.lid.."_GetKnownTargets") + local finaltargets = SET_UNIT:New() + local targets = self.TargetCache:GetDataTable() + local playername = client:GetPlayerName() + for _,_target in pairs(targets) do + local targetdata = _target.PlayerRecceDetected -- Ops.PlayerRecce#PLAYERRECCE.PlayerRecceDetected + if targetdata.playername == playername then + finaltargets:Add(_target:GetName(),_target) + end + end + return finaltargets,finaltargets:CountAlive() +end + +--- [Internal] +--@param #PLAYERRECCE self +--@return #PLAYERRECCE self +function PLAYERRECCE:_CleanupTargetCache() + self:T(self.lid.."_CleanupTargetCache") + local cleancache = FIFO:New() + self.TargetCache:ForEach( + function(unit) + local pull = false + if unit and unit:IsAlive() then + if unit.PlayerRecceDetected and unit.PlayerRecceDetected.timestamp then + local TNow = timer.getTime() + if TNow-unit.PlayerRecceDetected.timestamp > self.TForget then + -- Forget this unit + pull = true + unit.PlayerRecceDetected=nil + end + else + -- no timestamp + pull = true + end + else + -- dead + pull = true + end + if not pull then + cleancache:Push(unit,unit:GetName()) + end + end + ) + self.TargetCache = nil + self.TargetCache = cleancache + return self +end + --- [Internal] --@param #PLAYERRECCE self --@param Wrapper.Unit#UNIT unit The FACA unit @@ -547,9 +639,6 @@ function PLAYERRECCE:_LaseTarget(client,targetset) self.UnitLaserCodes[playername] = 1688 end laser.LaserCode = self.UnitLaserCodes[playername] or 1688 - --function laser:OnAfterLaseOff(From,Event,To) - --MESSAGE:New("Finished lasing",15,"Info"):ToClient(client) - --end self.LaserSpots[playername] = laser else laser = self.LaserSpots[playername] @@ -561,7 +650,6 @@ function PLAYERRECCE:_LaseTarget(client,targetset) local lasingtime = self.lasingtime or 60 local targettype = target:GetTypeName() laser:LaseOn(target,lasercode,lasingtime) - --MESSAGE:New(string.format("Lasing Target %s with Code %d",targettype,lasercode),15,"Info"):ToClient(client) self:__TargetLasing(-1,client,target,lasercode,lasingtime) else -- still looking at target? @@ -571,7 +659,6 @@ function PLAYERRECCE:_LaseTarget(client,targetset) local targettype = oldtarget:GetTypeName() laser:LaseOff() self:__TargetLOSLost(-1,client,oldtarget) - --MESSAGE:New(string.format("Lost LOS on target %s!",targettype),15,"Info"):ToClient(client) end end return self @@ -662,10 +749,10 @@ function PLAYERRECCE:_SmokeTargets(client,group,playername) if cameraset:CountAlive() > 0 then self:__TargetsSmoked(-1,client,playername,cameraset) end - local highsmoke = SMOKECOLOR.Orange - local medsmoke = SMOKECOLOR.White - local lowsmoke = SMOKECOLOR.Green - local lasersmoke = SMOKECOLOR.Red + local highsmoke = self.SmokeColor.highsmoke + local medsmoke = self.SmokeColor.medsmoke + local lowsmoke = self.SmokeColor.lowsmoke + local lasersmoke = self.SmokeColor.lasersmoke local laser = self.LaserSpots[playername] -- Core.Spot#SPOT -- laser targer gets extra smoke if laser and laser.Target and laser.Target:IsAlive() then @@ -708,10 +795,10 @@ function PLAYERRECCE:_FlareTargets(client,group,playername) if cameraset:CountAlive() > 0 then self:__TargetsFlared(-1,client,playername,cameraset) end - local highsmoke = FLARECOLOR.Yellow - local medsmoke = FLARECOLOR.White - local lowsmoke = FLARECOLOR.Green - local lasersmoke = FLARECOLOR.Red + local highsmoke = self.FlareColor.highflare + local medsmoke = self.FlareColor.medflare + local lowsmoke = self.FlareColor.lowflare + local lasersmoke = self.FlareColor.laserflare local laser = self.LaserSpots[playername] -- Core.Spot#SPOT -- laser targer gets extra smoke if laser and laser.Target and laser.Target:IsAlive() then @@ -812,7 +899,7 @@ end -- @return #PLAYERRECCE self function PLAYERRECCE:_ReportVisualTargets(client,group,playername) self:T(self.lid.."_ReportVisualTargets") - local targetset, number = self:_GetTargetSet(client,false) + local targetset, number = self:_GetKnownTargets(client) if number > 0 then local Settings = ( client and _DATABASE:GetPlayerSettings( playername ) ) or _SETTINGS local ThreatLevel = targetset:CalculateThreatLevelA2G() @@ -910,6 +997,7 @@ end -- @return #PLAYERRECCE self function PLAYERRECCE:_CheckNewTargets(targetset,client,playername) self:T(self.lid.."_CheckNewTargets") + local tempset = SET_UNIT:New() targetset:ForEach( function(unit) if unit and unit:IsAlive() then @@ -922,11 +1010,45 @@ function PLAYERRECCE:_CheckNewTargets(targetset,client,playername) playername = playername, timestamp = timer.getTime() } - self:TargetDetected(unit,client,playername) + --self:TargetDetected(unit,client,playername) + tempset:Add(unit:GetName(),unit) + if not self.TargetCache:HasUniqueID(unit:GetName()) then + self.TargetCache:Push(unit,unit:GetName()) + end + end + if unit.PlayerRecceDetected and unit.PlayerRecceDetected.timestamp then + local TNow = timer.getTime() + if TNow-unit.PlayerRecceDetected.timestamp > self.TForget then + unit.PlayerRecceDetected = { + detected = true, + recce = client, + playername = playername, + timestamp = timer.getTime() + } + if not self.TargetCache:HasUniqueID(unit:GetName()) then + self.TargetCache:Push(unit,unit:GetName()) + end + tempset:Add(unit:GetName(),unit) + end end end end ) + local targetsbyclock = {} + for i=1,12 do + targetsbyclock[i] = {} + end + tempset:ForEach( + function (object) + local obj=object -- Wrapper.Unit#UNIT + local clock = self:_GetClockDirection(client,obj) + table.insert(targetsbyclock[clock],obj) + end + ) + self:I("Known target Count: "..self.TargetCache:Count()) + if tempset:CountAlive() > 0 then + self:TargetDetected(targetsbyclock,client,playername) + end return self end @@ -1024,6 +1146,16 @@ end function PLAYERRECCE:onafterStatus(From, Event, To) self:I({From, Event, To}) + if not self.timestamp then + self.timestamp = timer.getTime() + else + local tNow = timer.getTime() + if tNow - self.timestamp >= 60 then + self:_CleanupTargetCache() + self.timestamp = timer.getTime() + end + end + self:_BuildMenus() self.PlayerSet:ForEachClient( @@ -1050,9 +1182,7 @@ function PLAYERRECCE:onafterStatus(From, Event, To) self:_LaseTarget(client,targetset) end end - -- Report new targets - self:_CheckNewTargets(targetset,client,playername) - + -- visual targets local vistargetset, vistargetcount, viszone = self:_GetTargetSet(client,false) if vistargetset then @@ -1064,7 +1194,8 @@ function PLAYERRECCE:onafterStatus(From, Event, To) end end self:T({visualtargetcount=vistargetcount}) - self:_CheckNewTargets(vistargetset,client,playername) + targetset:AddSet(vistargetset) + self:_CheckNewTargets(targetset,client,playername) end end ) @@ -1150,36 +1281,72 @@ end -- @param #string From -- @param #string Event -- @param #string To --- @param Wrapper.Unit#UNIT Target +-- @param #table Targetsbyclock -- @param Wrapper.Client#CLIENT Client -- @param #string Playername -- @return #PLAYERRECCE self -function PLAYERRECCE:onafterTargetDetected(From, Event, To, Target, Client, Playername) +function PLAYERRECCE:onafterTargetDetected(From, Event, To, Targetsbyclock, Client, Playername) self:T({From, Event, To}) + local dunits = "meters" - local targetdirection = self:_GetClockDirection(Client,Target) - local targetdistance = Client:GetCoordinate():Get2DDistance(Target:GetCoordinate()) or 100 local Settings = Client and _DATABASE:GetPlayerSettings(Playername) or _SETTINGS -- Core.Settings#SETTINGS - local Threatlvl = Target:GetThreatLevel() - local ThreatTxt = "Low" - if Threatlvl >=7 then - ThreatTxt = "Medium" - elseif Threatlvl >=3 then - ThreatTxt = "High" - end - if Settings:IsMetric() then - targetdistance = UTILS.Round(targetdistance,-2) - else - targetdistance = UTILS.Round(UTILS.MetersToFeet(targetdistance),-2) - dunits = "feet" - end - local text = string.format("Target! %s! %s o\'clock, %d %s!", ThreatTxt,targetdirection, targetdistance, dunits) - local ttstext = string.format("Target! %s! %s oh clock, %d %s!", ThreatTxt, targetdirection, targetdistance, dunits) - if self.UseSRS then - local grp = Client:GetGroup() - self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) - else - MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + local clientcoord = Client:GetCoordinate() + + for i=1,12 do + local targets = Targetsbyclock[i] --#table + local targetno = #targets + if targetno == 1 then + -- only one + local targetdistance = clientcoord:Get2DDistance(targets[1]:GetCoordinate()) or 100 + local Threatlvl = targets[1]:GetThreatLevel() + local ThreatTxt = "Low" + if Threatlvl >=7 then + ThreatTxt = "Medium" + elseif Threatlvl >=3 then + ThreatTxt = "High" + end + if Settings:IsMetric() then + targetdistance = UTILS.Round(targetdistance,-2) + else + targetdistance = UTILS.Round(UTILS.MetersToFeet(targetdistance),-2) + dunits = "feet" + end + local text = string.format("Target! %s! %s o\'clock, %d %s!", ThreatTxt,i, targetdistance, dunits) + local ttstext = string.format("Target! %s! %s oh clock, %d %s!", ThreatTxt, i, targetdistance, dunits) + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end + elseif targetno > 1 then + -- multiple + local function GetNearest(TTable) + local distance = 10000000 + for _,_unit in pairs(TTable) do + local dist = clientcoord:Get2DDistance(_unit:GetCoordinate()) or 100 + if dist < distance then + distance = dist + end + end + return distance + end + local targetdistance = GetNearest(targets) + if Settings:IsMetric() then + targetdistance = UTILS.Round(targetdistance,-2) + else + targetdistance = UTILS.Round(UTILS.MetersToFeet(targetdistance),-2) + dunits = "feet" + end + local text = string.format(" %d targets! %s o\'clock, %d %s!", targetno, i, targetdistance, dunits) + local ttstext = string.format("%d targets! %s oh clock, %d %s!", targetno, i, targetdistance, dunits) + if self.UseSRS then + local grp = Client:GetGroup() + self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,1,{grp},text,10) + else + MESSAGE:New(text,10,self.Name or "FACA"):ToClient(Client) + end + end end return self end From 1e04aaa77dcd22fb36a0cf6754c911c101bc63f2 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 2 Oct 2022 19:45:48 +0200 Subject: [PATCH 7/9] Update Airboss.lua - reenabled ai handling --- Moose Development/Moose/Ops/Airboss.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 313b8b154..118b9e642 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -5813,7 +5813,7 @@ function AIRBOSS:_ScanCarrierZone() if knownflight then -- Check if flight is AI and if we want to handle it at all. - if knownflight.ai and knownflight.flag == -100 and self.handleai and false then --Disabled AI handling because of incorrect OPSGROUP reference! + if knownflight.ai and knownflight.flag == -100 and self.handleai then local putintomarshal = false From 10eec8a47baa361d8c86e63cba73d68b4542b5b4 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 3 Oct 2022 16:32:55 +0200 Subject: [PATCH 8/9] Update FlightGroup.lua - Added `GetSquadronName` and `GetAirwingName` functions --- Moose Development/Moose/Ops/FlightGroup.lua | 30 ++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 6c5d0bf2f..1b63c2bbb 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -210,7 +210,7 @@ FLIGHTGROUP.Players={} --- FLIGHTGROUP class version. -- @field #string version -FLIGHTGROUP.version="0.8.0" +FLIGHTGROUP.version="0.8.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -372,11 +372,34 @@ end --- Get airwing the flight group belongs to. -- @param #FLIGHTGROUP self --- @return Ops.AirWing#AIRWING The AIRWING object. -function FLIGHTGROUP:GetAirWing() +-- @return Ops.AirWing#AIRWING The AIRWING object (if any). +function FLIGHTGROUP:GetAirwing() return self.legion end +--- Get name of airwing the flight group belongs to. +-- @param #FLIGHTGROUP self +-- @return #string Name of the airwing or "None" if the flightgroup does not belong to any airwing. +function FLIGHTGROUP:GetAirwing() + local name=self.legion and self.legion.alias or "None" + return name +end + +--- Get squadron the flight group belongs to. +-- @param #FLIGHTGROUP self +-- @return Ops.Squadron#SQUADRON The SQUADRON of this flightgroup or #nil if the flightgroup does not belong to any squadron. +function FLIGHTGROUP:GetSquadron() + return self.cohort +end + +--- Get squadron name the flight group belongs to. +-- @param #FLIGHTGROUP self +-- @return #string The squadron name or "None" if the flightgroup does not belon to any squadron. +function FLIGHTGROUP:GetSquadronName() + local name=self.cohort and self.cohort:GetName() or "None" + return name +end + --- Set if aircraft is VTOL capable. Unfortunately, there is no DCS way to determine this via scripting. -- @param #FLIGHTGROUP self -- @return #FLIGHTGROUP self @@ -836,6 +859,7 @@ end function FLIGHTGROUP:GetKills() return self.Nkills end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Status ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 064e082a1221cbc5ae275bc3a33ec254b120d238 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 3 Oct 2022 19:12:19 +0200 Subject: [PATCH 9/9] Airwing - Added `:IncreasePayloadAmount` function --- Moose Development/Moose/Ops/AirWing.lua | 38 +++++++++++++++++++++++++ Moose Development/Moose/Ops/Legion.lua | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Ops/AirWing.lua b/Moose Development/Moose/Ops/AirWing.lua index c8fbb1524..0dae8cb06 100644 --- a/Moose Development/Moose/Ops/AirWing.lua +++ b/Moose Development/Moose/Ops/AirWing.lua @@ -422,6 +422,44 @@ function AIRWING:SetPayloadAmount(Payload, Navailable) return self end +--- Increase or decrease the amount of available payloads. Unlimited playloads first need to be set to a limited number with the `SetPayloadAmount` function. +-- @param #AIRWING self +-- @param #AIRWING.Payload Payload The payload table created by the `:NewPayload` function. +-- @param #number N Number of payloads to be added. Use negative number to decrease amount. Default 1. +-- @return #AIRWING self +function AIRWING:IncreasePayloadAmount(Payload, N) + + N=N or 1 + + if Payload and Payload.navail>=0 then + + -- Increase/decrease amount. + Payload.navail=Payload.navail+N + + -- Ensure playload does not drop below 0. + Payload.navail=math.max(Payload.navail, 0) + + end + + return self +end + +--- Get amount of payloads available for a given playload. +-- @param #AIRWING self +-- @param #AIRWING.Payload Payload The payload table created by the `:NewPayload` function. +-- @return #number Number of payloads available. Unlimited payloads will return -1. +function AIRWING:GetPayloadAmount(Payload) + return Payload.navail +end + +--- Get capabilities of a given playload. +-- @param #AIRWING self +-- @param #AIRWING.Payload Payload The payload data table. +-- @return #table Capabilities. +function AIRWING:GetPayloadCapabilities(Payload) + return Payload.capabilities +end + --- Add a mission capability to an existing payload. -- @param #AIRWING self -- @param #AIRWING.Payload Payload The payload table to which the capability should be added. diff --git a/Moose Development/Moose/Ops/Legion.lua b/Moose Development/Moose/Ops/Legion.lua index 366d6a7d5..d2e0574e9 100644 --- a/Moose Development/Moose/Ops/Legion.lua +++ b/Moose Development/Moose/Ops/Legion.lua @@ -1854,7 +1854,7 @@ end --- Count total number of assets of the legion. -- @param #LEGION self --- @param #boolean InStock If true, only assets that are in the warehouse stock/inventory are counted. +-- @param #boolean InStock If `true`, only assets that are in the warehouse stock/inventory are counted. -- @param #table MissionTypes (Optional) Count only assest that can perform certain mission type(s). Default is all types. -- @param #table Attributes (Optional) Count only assest that have a certain attribute(s), e.g. `WAREHOUSE.Attribute.AIR_BOMBER`. -- @return #number Amount of asset groups in stock.