From a42ff854063af7cf9fbe8833d4345f66e6d136a2 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sat, 1 Oct 2022 16:03:05 +0200 Subject: [PATCH] #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 +------------------------------------------------------------------------------------------