From 595b9132e846525752f96c319b954f2030db31b8 Mon Sep 17 00:00:00 2001 From: kaltokri Date: Wed, 28 Feb 2024 17:34:40 +0100 Subject: [PATCH] Added additional information to FOX:AddProtectedGroup method --- Moose Development/Moose/Functional/Fox.lua | 622 ++++++++++----------- 1 file changed, 311 insertions(+), 311 deletions(-) diff --git a/Moose Development/Moose/Functional/Fox.lua b/Moose Development/Moose/Functional/Fox.lua index 0c9c81b67..ee5854474 100644 --- a/Moose Development/Moose/Functional/Fox.lua +++ b/Moose Development/Moose/Functional/Fox.lua @@ -1,14 +1,14 @@ --- **Functional** - Yet Another Missile Trainer. --- --- +-- +-- -- Practice to evade missiles without being destroyed. --- +-- -- -- ## Main Features: --- +-- -- * Handles air-to-air and surface-to-air missiles. -- * Define your own training zones on the map. Players in this zone will be protected. --- * Define launch zones. Only missiles launched in these zones are tracked. +-- * Define launch zones. Only missiles launched in these zones are tracked. -- * Define protected AI groups. -- * F10 radio menu to adjust settings for each player. -- * Alert on missile launch (optional). @@ -16,7 +16,7 @@ -- * Adaptive update of missile-to-player distance. -- * Finite State Machine (FSM) implementation. -- * Easy to use. See examples below. --- +-- -- === -- -- ### Author: **funkyfranky** @@ -47,7 +47,7 @@ -- @field #number dt10 Time step [sec] for missile position updates if distance to target > 10 km and < 50 km. Default 1 sec. -- @field #number dt05 Time step [sec] for missile position updates if distance to target > 5 km and < 10 km. Default 0.5 sec. -- @field #number dt01 Time step [sec] for missile position updates if distance to target > 1 km and < 5 km. Default 0.1 sec. --- @field #number dt00 Time step [sec] for missile position updates if distance to target < 1 km. Default 0.01 sec. +-- @field #number dt00 Time step [sec] for missile position updates if distance to target < 1 km. Default 0.01 sec. -- @extends Core.Fsm#FSM --- Fox 3! @@ -57,66 +57,66 @@ -- ![Banner Image](..\Presentations\FOX\FOX_Main.png) -- -- # The FOX Concept --- +-- -- As you probably know [Fox](https://en.wikipedia.org/wiki/Fox_\(code_word\)) is a NATO brevity code for launching air-to-air munition. Therefore, the class name is not 100% accurate as this -- script handles air-to-air but also surface-to-air missiles. --- +-- -- # Basic Script --- +-- -- -- Create a new missile trainer object. -- fox=FOX:New() --- +-- -- -- Start missile trainer. -- fox:Start() --- +-- -- # Training Zones --- +-- -- Players are only protected if they are inside one of the training zones. --- +-- -- -- Create a new missile trainer object. -- fox=FOX:New() --- +-- -- -- Add training zones. -- fox:AddSafeZone(ZONE:New("Training Zone Alpha")) -- fox:AddSafeZone(ZONE:New("Training Zone Bravo")) --- +-- -- -- Start missile trainer. -- fox:Start() --- +-- -- # Launch Zones --- +-- -- Missile launches are only monitored if the shooter is inside the defined launch zone. --- +-- -- -- Create a new missile trainer object. -- fox=FOX:New() --- +-- -- -- Add training zones. -- fox:AddLaunchZone(ZONE:New("Launch Zone SA-10 Krim")) -- fox:AddLaunchZone(ZONE:New("Training Zone Bravo")) --- +-- -- -- Start missile trainer. -- fox:Start() --- +-- -- # Protected AI Groups --- +-- -- Define AI protected groups. These groups cannot be harmed by missiles. --- +-- -- ## Add Individual Groups --- +-- -- -- Create a new missile trainer object. -- fox=FOX:New() --- +-- -- -- Add single protected group(s). -- fox:AddProtectedGroup(GROUP:FindByName("A-10 Protected")) -- fox:AddProtectedGroup(GROUP:FindByName("Yak-40")) --- +-- -- -- Start missile trainer. -- fox:Start() --- +-- -- # Notes --- +-- -- The script needs to be running before you enter an airplane slot. If FOX is not available to you, go back to observers and then join a slot again. --- +-- -- @field #FOX FOX = { ClassName = "FOX", @@ -218,17 +218,17 @@ function FOX:New() -- Inherit everthing from FSM class. local self=BASE:Inherit(self, FSM:New()) -- #FOX - + -- Defaults: self:SetDefaultMissileDestruction(true) self:SetDefaultLaunchAlerts(true) self:SetDefaultLaunchMarks(true) - + -- Explosion/destruction defaults. self:SetExplosionDistance() self:SetExplosionDistanceBigMissiles() self:SetExplosionPower() - + -- Start State. self:SetStartState("Stopped") @@ -350,7 +350,7 @@ function FOX:New() -- @param #string To To state. -- @param #FOX.PlayerData player Player data. - + return self end @@ -368,16 +368,16 @@ function FOX:onafterStart(From, Event, To) -- Handle events: self:HandleEvent(EVENTS.Birth) self:HandleEvent(EVENTS.Shot) - + if self.Debug then self:HandleEvent(EVENTS.Hit) end - + if self.Debug then self:TraceClass(self.ClassName) self:TraceLevel(2) end - + self:__Status(-20) end @@ -395,7 +395,7 @@ function FOX:onafterStop(From, Event, To) -- Handle events: self:UnHandleEvent(EVENTS.Birth) self:UnHandleEvent(EVENTS.Shot) - + if self.Debug then self:UnhandleEvent(EVENTS.Hit) end @@ -437,18 +437,18 @@ function FOX:SetProtectedGroupSet(groupset) return self end ---- Add a group to the protected set. +--- Add a group to the protected set. Works only with AI! -- @param #FOX self -- @param Wrapper.Group#GROUP group Protected group. -- @return #FOX self function FOX:AddProtectedGroup(group) - + if not self.protectedset then self.protectedset=SET_GROUP:New() end - + self.protectedset:AddGroup(group) - + return self end @@ -483,7 +483,7 @@ end function FOX:SetExplosionDistanceBigMissiles(distance, explosivemass) self.explosiondist2=distance or 500 - + self.bigmissilemass=explosivemass or 50 return self @@ -609,18 +609,18 @@ function FOX:onafterStatus(From, Event, To) -- Get FSM state. local fsmstate=self:GetState() - + local time=timer.getAbsTime() local clock=UTILS.SecondsToClock(time) - + -- Status. if self.verbose>=1 then self:I(self.lid..string.format("Missile trainer status %s: %s", clock, fsmstate)) end - + -- Check missile status. self:_CheckMissileStatus() - + -- Check player status. self:_CheckPlayers() @@ -635,39 +635,39 @@ function FOX:_CheckPlayers() for playername,_playersettings in pairs(self.players) do local playersettings=_playersettings --#FOX.PlayerData - + local unitname=playersettings.unitname local unit=UNIT:FindByName(unitname) - + if unit and unit:IsAlive() then - + local coord=unit:GetCoordinate() - + local issafe=self:_CheckCoordSafe(coord) - - + + if issafe then - + ----------------------------- -- Player INSIDE Safe Zone -- ----------------------------- - + if not playersettings.inzone then self:EnterSafeZone(playersettings) playersettings.inzone=true end - + else - + ------------------------------ -- Player OUTSIDE Safe Zone -- - ------------------------------ - + ------------------------------ + if playersettings.inzone==true then self:ExitSafeZone(playersettings) playersettings.inzone=false end - + end end end @@ -686,7 +686,7 @@ function FOX:_RemoveMissile(missile) table.remove(self.missiles, i) return end - end + end end end @@ -699,7 +699,7 @@ function FOX:_CheckMissileStatus() local inactive={} for i,_missile in pairs(self.missiles) do local missile=_missile --#FOX.MissileData - + local targetname="unkown" if missile.targetUnit then targetname=missile.targetUnit:GetName() @@ -712,14 +712,14 @@ function FOX:_CheckMissileStatus() local mtype=missile.missileType local dtype=missile.missileType local range=UTILS.MetersToNM(missile.missileRange) - + if not active then table.insert(inactive,i) end local heading=self:_GetWeapongHeading(missile.weapon) - + text=text..string.format("\n[%d] %s: active=%s, range=%.1f NM, heading=%03d, target=%s, player=%s, missilename=%s", i, mtype, active, range, heading, targetname, playername, missile.missileName) - + end if #self.missiles==0 then text=text.." none" @@ -728,7 +728,7 @@ function FOX:_CheckMissileStatus() self:I(self.lid..text) end - -- Remove inactive missiles. + -- Remove inactive missiles. for i=#self.missiles,1,-1 do local missile=self.missiles[i] --#FOX.MissileData if missile and not missile.active then @@ -747,31 +747,31 @@ function FOX:_IsProtected(targetunit) if not self.protectedset then return false end - + if targetunit and targetunit:IsAlive() then -- Get Group. local targetgroup=targetunit:GetGroup() - + if targetgroup then local targetname=targetgroup:GetName() - + for _,_group in pairs(self.protectedset:GetSet()) do local group=_group --Wrapper.Group#GROUP - + if group then local groupname=group:GetName() - + -- Target belongs to a protected set. if targetname==groupname then return true end end - + end end end - + return false end @@ -784,22 +784,22 @@ function FOX._FuncTrack(weapon, self, missile) -- Missile coordinate. local missileCoord= missile.missileCoord:UpdateFromVec3(weapon.vec3) --COORDINATE:NewFromVec3(_lastBombPos) - + -- Missile velocity in m/s. local missileVelocity=weapon:GetSpeed() --UTILS.VecNorm(_ordnance:getVelocity()) - + -- Update missile target if necessary. self:GetMissileTarget(missile) - + -- Target unit of the missile. - local target=nil --Wrapper.Unit#UNIT - + local target=nil --Wrapper.Unit#UNIT + if missile.targetUnit then - + ----------------------------------- -- Missile has a specific target -- ----------------------------------- - + if missile.targetPlayer then -- Target is a player. if missile.targetPlayer.destroy==true then @@ -811,13 +811,13 @@ function FOX._FuncTrack(weapon, self, missile) target=missile.targetUnit end end - + else - + ------------------------------------ -- Missile has NO specific target -- - ------------------------------------ - + ------------------------------------ + -- TODO: This might cause a problem with wingman. Even if the shooter itself is excluded from the check, it's wingmen are not. -- That would trigger the distance check right after missile launch if things to wrong. -- @@ -825,165 +825,165 @@ function FOX._FuncTrack(weapon, self, missile) -- * Time check: enable this check after X seconds after missile was fired. What is X? -- * Coalition check. But would not work in training situations where blue on blue is valid! -- * At least enable it for surface-to-air missiles. - + local function _GetTarget(_unit) local unit=_unit --Wrapper.Unit#UNIT - + -- Player position. local playerCoord=unit:GetCoordinate() - - -- Distance. + + -- Distance. local dist=missileCoord:Get3DDistance(playerCoord) - + -- Update mindist if necessary. Only include players in range of missile + 50% safety margin. if dist<=self.explosiondist then return unit - end + end end - + -- Distance to closest player. local mindist=nil - + -- Loop over players. for _,_player in pairs(self.players) do local player=_player --#FOX.PlayerData - + -- Check that player was not the one who launched the missile. if player.unitname~=missile.shooterName then - + -- Player position. local playerCoord=player.unit:GetCoordinate() - - -- Distance. + + -- Distance. local dist=missileCoord:Get3DDistance(playerCoord) - + -- Distance from shooter to player. local Dshooter2player=playerCoord:Get3DDistance(missile.shotCoord) - + -- Update mindist if necessary. Only include players in range of missile + 50% safety margin. if (mindist==nil or dist=self.bigmissilemass end - + -- If missile is 150 m from target ==> destroy missile if in safe zone. if destroymissile and self:_CheckCoordSafe(targetVec3) then - + -- Destroy missile. - self:I(self.lid..string.format("Destroying missile %s(%s) fired by %s aimed at %s [player=%s] at distance %.1f m", + self:I(self.lid..string.format("Destroying missile %s(%s) fired by %s aimed at %s [player=%s] at distance %.1f m", missile.missileType, missile.missileName, missile.shooterName, target:GetName(), tostring(missile.targetPlayer~=nil), distance)) weapon:Destroy() - + -- Missile is not active any more. missile.active=false - + -- Debug smoke. if self.Debug then - missileCoord:SmokeRed() + missileCoord:SmokeRed() end - + -- Create event. self:MissileDestroyed(missile) - + -- Little explosion for the visual effect. if self.explosionpower>0 and distance>50 and (distShooter==nil or (distShooter and distShooter>50)) then missileCoord:Explosion(self.explosionpower) end - + -- Target was a player. if missile.targetPlayer then - + -- Message to target. local text=string.format("Destroying missile. %s", self:_DeadText()) MESSAGE:New(text, 10):ToGroup(target:GetGroup()) - + -- Increase dead counter. missile.targetPlayer.dead=missile.targetPlayer.dead+1 end -- We could disable the tracking here but then the impact function would not be called. --weapon.tracking=false - + else - + -- Time step. - local dt=1.0 + local dt=1.0 if distance>50000 then -- > 50 km dt=self.dt50 --=5.0 @@ -1000,17 +1000,17 @@ function FOX._FuncTrack(weapon, self, missile) -- < 1 km dt=self.dt00 --0.01 end - + -- Set time step. weapon:SetTimeStepTrack(dt) end - + else - + -- No current target. self:T(self.lid..string.format("Missile %s(%s) fired by %s has no current target. Checking back in 0.1 sec.", missile.missileType, missile.missileName, missile.shooterName)) weapon:SetTimeStepTrack(0.1) - + end end @@ -1021,25 +1021,25 @@ end -- @param #FOX.MissileData missile Fired missile. function FOX._FuncImpact(weapon, self, missile) - if missile.targetPlayer then - + if missile.targetPlayer then + -- Get human player. local player=missile.targetPlayer - + -- Check for player and distance < 10 km. if player and player.unit:IsAlive() then -- and missileCoord and player.unit:GetCoordinate():Get3DDistance(missileCoord)<10*1000 then local text=string.format("Missile defeated. Well done, %s!", player.name) MESSAGE:New(text, 10):ToClient(player.client) - + -- Increase defeated counter. player.defeated=player.defeated+1 end - + end - + -- Missile is not active any more. - missile.active=false - + missile.active=false + --Terminate the timer. self:T(FOX.lid..string.format("Terminating missile track timer.")) weapon.tracking=false @@ -1058,59 +1058,59 @@ function FOX:onafterMissileLaunch(From, Event, To, missile) local text=string.format("FOX: Tracking missile %s(%s) - target %s - shooter %s", missile.missileType, missile.missileName, tostring(missile.targetName), missile.shooterName) self:I(FOX.lid..text) MESSAGE:New(text, 10):ToAllIf(self.Debug) - + -- Loop over players. for _,_player in pairs(self.players) do local player=_player --#FOX.PlayerData - + -- Player position. local playerUnit=player.unit - + -- Check that player is alive and of the opposite coalition. if playerUnit and playerUnit:IsAlive() and player.coalition~=missile.shooterCoalition then - + -- Player missile distance. local distance=playerUnit:GetCoordinate():Get3DDistance(missile.shotCoord) - + -- Player bearing to missile. local bearing=playerUnit:GetCoordinate():HeadingTo(missile.shotCoord) - + -- Alert that missile has been launched. if player.launchalert then - + -- Alert directly targeted players or players that are within missile max range. if (missile.targetPlayer and player.unitname==missile.targetPlayer.unitname) or (distance Target=%s, fuse dist=%s, explosive=%s", tostring(missile.shooterName), tostring(missile.missileType), tostring(missile.missileName), tostring(missile.targetName), tostring(missile.fuseDist), tostring(missile.explosive))) - + -- Only track if target was a player or target is protected. Saw the 9M311 missiles have no target! if missile.targetPlayer or self:_IsProtected(missile.targetUnit) or missile.targetName=="unknown" then - + -- Add missile table. table.insert(self.missiles, missile) - + -- Trigger MissileLaunch event. self:__MissileLaunch(0.1, missile) - + end - + end --if _track - + end --- FOX event handler for event hit. @@ -1340,7 +1340,7 @@ end -- @param Core.Event#EVENTDATA EventData function FOX:OnEventHit(EventData) self:T({eventhit = EventData}) - + -- Nil checks. if EventData.Weapon==nil then return @@ -1351,10 +1351,10 @@ function FOX:OnEventHit(EventData) if EventData.TgtUnit==nil then return end - + local weapon=EventData.Weapon local weaponname=weapon:getName() - + for i,_missile in pairs(self.missiles) do local missile=_missile --#FOX.MissileData if missile.missileName==weaponname then @@ -1375,51 +1375,51 @@ end -- @param #string _unitName Name of player unit. function FOX:_AddF10Commands(_unitName) self:F(_unitName) - + -- Get player unit and name. local _unit, playername = self:_GetPlayerUnitAndName(_unitName) - + -- Check for player unit. if _unit and playername then -- Get group and ID. local group=_unit:GetGroup() local gid=group:GetID() - + if group and gid then - + if not self.menuadded[gid] then - + -- Enable switch so we don't do this twice. self.menuadded[gid]=true - + -- Set menu root path. local _rootPath=nil if FOX.MenuF10Root then ------------------------ -- MISSON LEVEL MENUE -- - ------------------------ - + ------------------------ + -- F10/FOX/... _rootPath=FOX.MenuF10Root - + else ------------------------ -- GROUP LEVEL MENUES -- ------------------------ - + -- Main F10 menu: F10/FOX/ if FOX.MenuF10[gid]==nil then FOX.MenuF10[gid]=missionCommands.addSubMenuForGroup(gid, "FOX") end - + -- F10/FOX/... _rootPath=FOX.MenuF10[gid] - + end - - - -------------------------------- + + + -------------------------------- -- F10/F FOX/F1 Help -------------------------------- --local _helpPath=missionCommands.addSubMenuForGroup(gid, "Help", _rootPath) @@ -1430,12 +1430,12 @@ function FOX:_AddF10Commands(_unitName) ------------------------- -- F10/F FOX/ ------------------------- - + missionCommands.addCommandForGroup(gid, "Destroy Missiles On/Off", _rootPath, self._ToggleDestroyMissiles, self, _unitName) -- F1 missionCommands.addCommandForGroup(gid, "Launch Alerts On/Off", _rootPath, self._ToggleLaunchAlert, self, _unitName) -- F2 missionCommands.addCommandForGroup(gid, "Mark Launch On/Off", _rootPath, self._ToggleLaunchMark, self, _unitName) -- F3 missionCommands.addCommandForGroup(gid, "My Status", _rootPath, self._MyStatus, self, _unitName) -- F4 - + end else self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName or "unknown")) @@ -1452,23 +1452,23 @@ end -- @param #string _unitname Name of the player unit. function FOX:_MyStatus(_unitname) self:F2(_unitname) - + -- Get player unit and player name. local unit, playername = self:_GetPlayerUnitAndName(_unitname) - + -- Check if we have a player. if unit and playername then - - -- Player data. + + -- Player data. local playerData=self.players[playername] --#FOX.PlayerData - + if playerData then - + local m,mtext=self:_GetTargetMissiles(playerData.name) - + local text=string.format("Status of player %s:\n", playerData.name) local safe=self:_CheckCoordSafe(playerData.unit:GetCoordinate()) - + text=text..string.format("Destroy missiles? %s\n", tostring(playerData.destroy)) text=text..string.format("Launch alert? %s\n", tostring(playerData.launchalert)) text=text..string.format("Launch marks? %s\n", tostring(playerData.marklaunch)) @@ -1476,9 +1476,9 @@ function FOX:_MyStatus(_unitname) text=text..string.format("Missiles defeated: %d\n", playerData.defeated) text=text..string.format("Missiles destroyed: %d\n", playerData.dead) text=text..string.format("Me target: %d\n%s", m, mtext) - + MESSAGE:New(text, 10, nil, true):ToClient(playerData.client) - + end end end @@ -1494,12 +1494,12 @@ function FOX:_GetTargetMissiles(playername) local n=0 for _,_missile in pairs(self.missiles) do local missile=_missile --#FOX.MissileData - + if missile.targetPlayer and missile.targetPlayer.name==playername then n=n+1 text=text..string.format("Type %s: active %s\n", missile.missileType, tostring(missile.active)) end - + end return n,text @@ -1510,21 +1510,21 @@ end -- @param #string _unitname Name of the player unit. function FOX:_ToggleLaunchAlert(_unitname) self:F2(_unitname) - + -- Get player unit and player name. local unit, playername = self:_GetPlayerUnitAndName(_unitname) - + -- Check if we have a player. if unit and playername then - - -- Player data. + + -- Player data. local playerData=self.players[playername] --#FOX.PlayerData - + if playerData then - + -- Invert state. playerData.launchalert=not playerData.launchalert - + -- Inform player. local text="" if playerData.launchalert==true then @@ -1533,7 +1533,7 @@ function FOX:_ToggleLaunchAlert(_unitname) text=string.format("%s, missile launch alerts are now DISABLED.", playerData.name) end MESSAGE:New(text, 5):ToClient(playerData.client) - + end end end @@ -1543,21 +1543,21 @@ end -- @param #string _unitname Name of the player unit. function FOX:_ToggleLaunchMark(_unitname) self:F2(_unitname) - + -- Get player unit and player name. local unit, playername = self:_GetPlayerUnitAndName(_unitname) - + -- Check if we have a player. if unit and playername then - - -- Player data. + + -- Player data. local playerData=self.players[playername] --#FOX.PlayerData - + if playerData then - + -- Invert state. playerData.marklaunch=not playerData.marklaunch - + -- Inform player. local text="" if playerData.marklaunch==true then @@ -1566,7 +1566,7 @@ function FOX:_ToggleLaunchMark(_unitname) text=string.format("%s, missile launch marks are now DISABLED.", playerData.name) end MESSAGE:New(text, 5):ToClient(playerData.client) - + end end end @@ -1577,21 +1577,21 @@ end -- @param #string _unitname Name of the player unit. function FOX:_ToggleDestroyMissiles(_unitname) self:F2(_unitname) - + -- Get player unit and player name. local unit, playername = self:_GetPlayerUnitAndName(_unitname) - + -- Check if we have a player. if unit and playername then - - -- Player data. + + -- Player data. local playerData=self.players[playername] --#FOX.PlayerData - + if playerData then - + -- Invert state. playerData.destroy=not playerData.destroy - + -- Inform player. local text="" if playerData.destroy==true then @@ -1600,7 +1600,7 @@ function FOX:_ToggleDestroyMissiles(_unitname) text=string.format("%s, incoming missiles will NOT be DESTROYED.", playerData.name) end MESSAGE:New(text, 5):ToClient(playerData.client) - + end end end @@ -1622,9 +1622,9 @@ function FOX:_DeadText() texts[4]="Well, I guess that was it!" texts[5]="Bye, bye!" texts[6]="Cheers buddy, was nice knowing you!" - + local r=math.random(#texts) - + return texts[r] end @@ -1637,9 +1637,9 @@ function FOX:_CheckCoordSafe(coord) -- No safe zones defined ==> Everything is safe. if #self.safezones==0 then - return true + return true end - + -- Loop over all zones. for _,_zone in pairs(self.safezones) do local zone=_zone --Core.Zone#ZONE @@ -1662,9 +1662,9 @@ function FOX:_CheckCoordLaunch(coord) -- No safe zones defined ==> Everything is safe. if #self.launchzones==0 then - return true + return true end - + -- Loop over all zones. for _,_zone in pairs(self.launchzones) do local zone=_zone --Core.Zone#ZONE @@ -1679,50 +1679,50 @@ function FOX:_CheckCoordLaunch(coord) return false end ---- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. +--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. -- @param #FOX self -- @param DCS#Weapon weapon The weapon. -- @return #number Heading of weapon in degrees or -1. function FOX:_GetWeapongHeading(weapon) if weapon and weapon:isExist() then - + local wp=weapon:getPosition() - + local wph = math.atan2(wp.x.z, wp.x.x) - + if wph < 0 then wph=wph+2*math.pi end - + wph=math.deg(wph) - + return wph end return -1 end ---- Tell player notching headings. +--- Tell player notching headings. -- @param #FOX self -- @param #FOX.PlayerData playerData Player data. -- @param DCS#Weapon weapon The weapon. function FOX:_SayNotchingHeadings(playerData, weapon) if playerData and playerData.unit and playerData.unit:IsAlive() then - + local nr, nl=self:_GetNotchingHeadings(weapon) - + if nr and nl then - local text=string.format("Notching heading %03d° or %03d°", nr, nl) + local text=string.format("Notching heading %03d° or %03d°", nr, nl) MESSAGE:New(text, 5, "FOX"):ToClient(playerData.client) end - + end end ---- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. +--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. -- @param #FOX self -- @param DCS#Weapon weapon The weapon. -- @return #number Notching heading right, i.e. missile heading +90°. @@ -1730,22 +1730,22 @@ end function FOX:_GetNotchingHeadings(weapon) if weapon then - + local hdg=self:_GetWeapongHeading(weapon) - + local hdg1=hdg+90 if hdg1>360 then hdg1=hdg1-360 end - + local hdg2=hdg-90 if hdg2<0 then hdg2=hdg2+360 end - + return hdg1, hdg2 - end - + end + return nil, nil end @@ -1755,14 +1755,14 @@ end -- @return #FOX.PlayerData Player data. function FOX:_GetPlayerFromUnitname(unitName) - for _,_player in pairs(self.players) do + for _,_player in pairs(self.players) do local player=_player --#FOX.PlayerData - + if player.unitname==unitName then return player end end - + return nil end @@ -1777,20 +1777,20 @@ function FOX:_GetPlayerFromUnit(unit) -- Name of the unit local unitname=unit:GetName() - for _,_player in pairs(self.players) do + for _,_player in pairs(self.players) do local player=_player --#FOX.PlayerData - + if player.unitname==unitname then return player end end end - + return nil end ---- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. +--- Returns the unit of a player and the player name. If the unit does not belong to a player, nil is returned. -- @param #FOX self -- @param #string _unitName Name of the player unit. -- @return Wrapper.Unit#UNIT Unit of player or nil. @@ -1799,31 +1799,31 @@ function FOX:_GetPlayerUnitAndName(_unitName) self:F2(_unitName) if _unitName ~= nil then - + -- Get DCS unit from its name. local DCSunit=Unit.getByName(_unitName) - + if DCSunit then - + -- Get player name if any. local playername=DCSunit:getPlayerName() - + -- Unit object. local unit=UNIT:Find(DCSunit) - + -- Debug. self:T2({DCSunit=DCSunit, unit=unit, playername=playername}) - + -- Check if enverything is there. if DCSunit and unit and playername then self:T(self.lid..string.format("Found DCS unit %s with player %s.", tostring(_unitName), tostring(playername))) return unit, playername end - + end - + end - + -- Return nil if we could not find a player. return nil,nil end