Fixed link in Func.Range to "476 vFG - Air Weapons Range Objects"

# Conflicts:
#	Moose Development/Moose/Functional/Range.lua
This commit is contained in:
kaltokri 2024-05-21 19:48:01 +02:00
parent 42d8a9f59d
commit 59ceb01d19

View File

@ -7,7 +7,7 @@
-- Implementation is based on the [Simple Range Script](https://forums.eagle.ru/showthread.php?t=157991) by Ciribob, which itself was motivated -- Implementation is based on the [Simple Range Script](https://forums.eagle.ru/showthread.php?t=157991) by Ciribob, which itself was motivated
-- by a script by SNAFU [see here](https://forums.eagle.ru/showthread.php?t=109174). -- by a script by SNAFU [see here](https://forums.eagle.ru/showthread.php?t=109174).
-- --
-- [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is highly recommended for this class. -- [476th - Air Weapons Range Objects mod](https://www.476vfightergroup.com/downloads.php?do=download&downloadid=482) is highly recommended for this class.
-- --
-- **Main Features:** -- **Main Features:**
-- --
@ -46,7 +46,7 @@
-- --
-- ### Contributions: FlightControl, Ciribob -- ### Contributions: FlightControl, Ciribob
-- ### SRS Additions: Applevangelist -- ### SRS Additions: Applevangelist
-- --
-- === -- ===
-- @module Functional.Range -- @module Functional.Range
-- @image Range.JPG -- @image Range.JPG
@ -102,7 +102,7 @@
-- @field #string targetpath Path where to save the target sheets. -- @field #string targetpath Path where to save the target sheets.
-- @field #string targetprefix File prefix for target sheet files. -- @field #string targetprefix File prefix for target sheet files.
-- @field Sound.SRS#MSRS controlmsrs SRS wrapper for range controller. -- @field Sound.SRS#MSRS controlmsrs SRS wrapper for range controller.
-- @field Sound.SRS#MSRSQUEUE controlsrsQ SRS queue for range controller. -- @field Sound.SRS#MSRSQUEUE controlsrsQ SRS queue for range controller.
-- @field Sound.SRS#MSRS instructmsrs SRS wrapper for range instructor. -- @field Sound.SRS#MSRS instructmsrs SRS wrapper for range instructor.
-- @field Sound.SRS#MSRSQUEUE instructsrsQ SRS queue for range instructor. -- @field Sound.SRS#MSRSQUEUE instructsrsQ SRS queue for range instructor.
-- @field #number Coalition Coalition side for the menu, if any. -- @field #number Coalition Coalition side for the menu, if any.
@ -169,7 +169,7 @@
-- --
-- ## Specifying Coordinates -- ## Specifying Coordinates
-- --
-- It is also possible to specify coordinates rather than unit or static objects as bombing target locations. This has the advantage, that even when the unit/static object is dead, the specified -- It is also possible to specify coordinates rather than unit or static objects as bombing target locations. This has the advantage, that even when the unit/static object is dead, the specified
-- coordinate will still be a valid impact point. This can be done via the @{#RANGE.AddBombingTargetCoordinate}(*coord*, *name*, *goodhitrange*) function. -- coordinate will still be a valid impact point. This can be done via the @{#RANGE.AddBombingTargetCoordinate}(*coord*, *name*, *goodhitrange*) function.
-- --
-- # Fine Tuning -- # Fine Tuning
@ -231,8 +231,8 @@
-- By default, the sound files are placed in the "Range Soundfiles/" folder inside the mission (.miz) file. Another folder can be specified via the @{#RANGE.SetSoundfilesPath}(*path*) function. -- By default, the sound files are placed in the "Range Soundfiles/" folder inside the mission (.miz) file. Another folder can be specified via the @{#RANGE.SetSoundfilesPath}(*path*) function.
-- --
-- ## Voice output via SRS -- ## Voice output via SRS
-- --
-- Alternatively, the voice output can be fully done via SRS, **no sound file additions needed**. Set up SRS with @{#RANGE.SetSRS}(). -- Alternatively, the voice output can be fully done via SRS, **no sound file additions needed**. Set up SRS with @{#RANGE.SetSRS}().
-- Range control and instructor frequencies and voices can then be set via @{#RANGE.SetSRSRangeControl}() and @{#RANGE.SetSRSRangeInstructor}(). -- Range control and instructor frequencies and voices can then be set via @{#RANGE.SetSRSRangeControl}() and @{#RANGE.SetSRSRangeInstructor}().
-- --
-- # Persistence -- # Persistence
@ -243,11 +243,11 @@
-- The next time you start the mission, these results are also automatically loaded. -- The next time you start the mission, these results are also automatically loaded.
-- --
-- Strafing results are currently **not** saved. -- Strafing results are currently **not** saved.
-- --
-- # FSM Events -- # FSM Events
-- --
-- This class creates additional events that can be used by mission designers for custom reactions -- This class creates additional events that can be used by mission designers for custom reactions
-- --
-- * `EnterRange` when a player enters a range zone. See @{#RANGE.OnAfterEnterRange} -- * `EnterRange` when a player enters a range zone. See @{#RANGE.OnAfterEnterRange}
-- * `ExitRange` when a player leaves a range zone. See @{#RANGE.OnAfterExitRange} -- * `ExitRange` when a player leaves a range zone. See @{#RANGE.OnAfterExitRange}
-- * `Impact` on impact of a player's weapon on a bombing target. See @{#RANGE.OnAfterImpact} -- * `Impact` on impact of a player's weapon on a bombing target. See @{#RANGE.OnAfterImpact}
@ -371,7 +371,7 @@ RANGE = {
-- @param #number boxlength Length of strafe pit box in meters. -- @param #number boxlength Length of strafe pit box in meters.
-- @param #number boxwidth Width of strafe pit box in meters. -- @param #number boxwidth Width of strafe pit box in meters.
-- @param #number goodpass Number of hits for a good strafing pit pass. -- @param #number goodpass Number of hits for a good strafing pit pass.
-- @param #number foulline Distance of foul line in meters. -- @param #number foulline Distance of foul line in meters.
RANGE.Defaults = { RANGE.Defaults = {
goodhitrange = 25, goodhitrange = 25,
strafemaxalt = 914, strafemaxalt = 914,
@ -625,9 +625,9 @@ function RANGE:New( RangeName, Coalition )
-- Get range name. -- Get range name.
-- TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu. -- TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu.
self.rangename = RangeName or "Practice Range" self.rangename = RangeName or "Practice Range"
self.Coalition = Coalition self.Coalition = Coalition
-- Log id. -- Log id.
self.lid = string.format( "RANGE %s | ", self.rangename ) self.lid = string.format( "RANGE %s | ", self.rangename )
@ -993,9 +993,9 @@ end
-- @param #string Host Host. Default "127.0.0.1". -- @param #string Host Host. Default "127.0.0.1".
-- @return #RANGE self -- @return #RANGE self
function RANGE:SetFunkManOn(Port, Host) function RANGE:SetFunkManOn(Port, Host)
self.funkmanSocket=SOCKET:New(Port, Host) self.funkmanSocket=SOCKET:New(Port, Host)
return self return self
end end
@ -1200,7 +1200,7 @@ end
-- @param #string PathToSRS Path to SRS directory. -- @param #string PathToSRS Path to SRS directory.
-- @param #number Port SRS port. Default 5002. -- @param #number Port SRS port. Default 5002.
-- @param #number Coalition Coalition side, e.g. `coalition.side.BLUE` or `coalition.side.RED`. Default `coalition.side.BLUE`. -- @param #number Coalition Coalition side, e.g. `coalition.side.BLUE` or `coalition.side.RED`. Default `coalition.side.BLUE`.
-- @param #number Frequency Frequency to use. Default is 256 MHz for range control and 305 MHz for instructor. If given, both control and instructor get this frequency. -- @param #number Frequency Frequency to use. Default is 256 MHz for range control and 305 MHz for instructor. If given, both control and instructor get this frequency.
-- @param #number Modulation Modulation to use, defaults to radio.modulation.AM -- @param #number Modulation Modulation to use, defaults to radio.modulation.AM
-- @param #number Volume Volume, between 0.0 and 1.0. Defaults to 1.0 -- @param #number Volume Volume, between 0.0 and 1.0. Defaults to 1.0
-- @param #string PathToGoogleKey Path to Google TTS credentials. -- @param #string PathToGoogleKey Path to Google TTS credentials.
@ -1208,9 +1208,9 @@ end
function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume, PathToGoogleKey) function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume, PathToGoogleKey)
if PathToSRS or MSRS.path then if PathToSRS or MSRS.path then
self.useSRS=true self.useSRS=true
self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM) self.controlmsrs=MSRS:New(PathToSRS or MSRS.path, Frequency or 256, Modulation or radio.modulation.AM)
self.controlmsrs:SetPort(Port or MSRS.port) self.controlmsrs:SetPort(Port or MSRS.port)
self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE) self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE)
@ -1224,14 +1224,14 @@ function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume,
self.instructmsrs:SetLabel("RANGEI") self.instructmsrs:SetLabel("RANGEI")
self.instructmsrs:SetVolume(Volume or 1.0) self.instructmsrs:SetVolume(Volume or 1.0)
self.instructsrsQ = MSRSQUEUE:New("INSTRUCT") self.instructsrsQ = MSRSQUEUE:New("INSTRUCT")
if PathToGoogleKey then if PathToGoogleKey then
self.controlmsrs:SetProviderOptionsGoogle(PathToGoogleKey,PathToGoogleKey) self.controlmsrs:SetProviderOptionsGoogle(PathToGoogleKey,PathToGoogleKey)
self.controlmsrs:SetProvider(MSRS.Provider.GOOGLE) self.controlmsrs:SetProvider(MSRS.Provider.GOOGLE)
self.instructmsrs:SetProviderOptionsGoogle(PathToGoogleKey,PathToGoogleKey) self.instructmsrs:SetProviderOptionsGoogle(PathToGoogleKey,PathToGoogleKey)
self.instructmsrs:SetProvider(MSRS.Provider.GOOGLE) self.instructmsrs:SetProvider(MSRS.Provider.GOOGLE)
end end
else else
self:E(self.lid..string.format("ERROR: No SRS path specified!")) self:E(self.lid..string.format("ERROR: No SRS path specified!"))
end end
@ -1741,9 +1741,9 @@ end
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function RANGE:OnEventBirth( EventData ) function RANGE:OnEventBirth( EventData )
self:F( { eventbirth = EventData } ) self:F( { eventbirth = EventData } )
if not EventData.IniPlayerName then return end if not EventData.IniPlayerName then return end
local _unitName = EventData.IniUnitName local _unitName = EventData.IniUnitName
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
@ -1764,7 +1764,7 @@ function RANGE:OnEventBirth( EventData )
-- Reset current strafe status. -- Reset current strafe status.
self.strafeStatus[_uid] = nil self.strafeStatus[_uid] = nil
if self.Coalition then if self.Coalition then
if EventData.IniCoalition == self.Coalition then if EventData.IniCoalition == self.Coalition then
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName ) self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
@ -1773,7 +1773,7 @@ function RANGE:OnEventBirth( EventData )
-- Add Menu commands after a delay of 0.1 seconds. -- Add Menu commands after a delay of 0.1 seconds.
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName ) self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
end end
-- By default, some bomb impact points and do not flare each hit on target. -- By default, some bomb impact points and do not flare each hit on target.
self.PlayerSettings[_playername] = {} -- #RANGE.PlayerData self.PlayerSettings[_playername] = {} -- #RANGE.PlayerData
self.PlayerSettings[_playername].smokebombimpact = self.defaultsmokebomb self.PlayerSettings[_playername].smokebombimpact = self.defaultsmokebomb
@ -1907,21 +1907,21 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
local _distance = nil local _distance = nil
local _closeCoord = nil --Core.Point#COORDINATE local _closeCoord = nil --Core.Point#COORDINATE
local _hitquality = "POOR" local _hitquality = "POOR"
-- Get callsign. -- Get callsign.
local _callsign = self:_myname( playerData.unitname ) local _callsign = self:_myname( playerData.unitname )
local _playername=playerData.playername local _playername=playerData.playername
local _unit=playerData.unit local _unit=playerData.unit
-- Coordinate of impact point. -- Coordinate of impact point.
local impactcoord = weapon:GetImpactCoordinate() local impactcoord = weapon:GetImpactCoordinate()
-- Check if impact happened in range zone. -- Check if impact happened in range zone.
local insidezone = self.rangezone:IsCoordinateInZone( impactcoord ) local insidezone = self.rangezone:IsCoordinateInZone( impactcoord )
-- Smoke impact point of bomb. -- Smoke impact point of bomb.
if playerData.smokebombimpact and insidezone then if playerData.smokebombimpact and insidezone then
if playerData.delaysmoke then if playerData.delaysmoke then
@ -1930,19 +1930,19 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
impactcoord:Smoke( playerData.smokecolor ) impactcoord:Smoke( playerData.smokecolor )
end end
end end
-- Loop over defined bombing targets. -- Loop over defined bombing targets.
for _, _bombtarget in pairs( self.bombingTargets ) do for _, _bombtarget in pairs( self.bombingTargets ) do
local bombtarget=_bombtarget --#RANGE.BombTarget local bombtarget=_bombtarget --#RANGE.BombTarget
-- Get target coordinate. -- Get target coordinate.
local targetcoord = self:_GetBombTargetCoordinate( _bombtarget ) local targetcoord = self:_GetBombTargetCoordinate( _bombtarget )
if targetcoord then if targetcoord then
-- Distance between bomb and target. -- Distance between bomb and target.
local _temp = impactcoord:Get2DDistance( targetcoord ) local _temp = impactcoord:Get2DDistance( targetcoord )
-- Find closest target to last known position of the bomb. -- Find closest target to last known position of the bomb.
if _distance == nil or _temp < _distance then if _distance == nil or _temp < _distance then
_distance = _temp _distance = _temp
@ -1959,21 +1959,21 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
else else
_hitquality = "POOR" _hitquality = "POOR"
end end
end end
end end
end end
-- Count if bomb fell less than ~1 km away from the target. -- Count if bomb fell less than ~1 km away from the target.
if _distance and _distance <= self.scorebombdistance then if _distance and _distance <= self.scorebombdistance then
-- Init bomb player results. -- Init bomb player results.
if not self.bombPlayerResults[_playername] then if not self.bombPlayerResults[_playername] then
self.bombPlayerResults[_playername] = {} self.bombPlayerResults[_playername] = {}
end end
-- Local results. -- Local results.
local _results = self.bombPlayerResults[_playername] local _results = self.bombPlayerResults[_playername]
local result = {} -- #RANGE.BombResult local result = {} -- #RANGE.BombResult
result.command=SOCKET.DataType.BOMBRESULT result.command=SOCKET.DataType.BOMBRESULT
result.name = _closetTarget.name or "unknown" result.name = _closetTarget.name or "unknown"
@ -1995,24 +1995,24 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
result.attackVel = attackVel result.attackVel = attackVel
result.attackAlt = attackAlt result.attackAlt = attackAlt
result.date=os and os.date() or "n/a" result.date=os and os.date() or "n/a"
-- Add to table. -- Add to table.
table.insert( _results, result ) table.insert( _results, result )
-- Call impact. -- Call impact.
self:Impact( result, playerData ) self:Impact( result, playerData )
elseif insidezone then elseif insidezone then
-- Send message. -- Send message.
-- DONE SRS message -- DONE SRS message
local _message = string.format( "%s, weapon impacted too far from nearest range target (>%.1f km). No score!", _callsign, self.scorebombdistance / 1000 ) local _message = string.format( "%s, weapon impacted too far from nearest range target (>%.1f km). No score!", _callsign, self.scorebombdistance / 1000 )
if self.useSRS then if self.useSRS then
local ttstext = string.format( "%s, weapon impacted too far from nearest range target, mor than %.1f kilometer. No score!", _callsign, self.scorebombdistance / 1000 ) local ttstext = string.format( "%s, weapon impacted too far from nearest range target, mor than %.1f kilometer. No score!", _callsign, self.scorebombdistance / 1000 )
self.controlsrsQ:NewTransmission(ttstext,nil,self.controlmsrs,nil,2) self.controlsrsQ:NewTransmission(ttstext,nil,self.controlmsrs,nil,2)
end end
self:_DisplayMessageToGroup( _unit, _message, nil, false ) self:_DisplayMessageToGroup( _unit, _message, nil, false )
if self.rangecontrol then if self.rangecontrol then
-- weapon impacted too far from the nearest target! No Score! -- weapon impacted too far from the nearest target! No Score!
if self.useSRS then if self.useSRS then
@ -2021,11 +2021,11 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
self.rangecontrol:NewTransmission( RANGE.Sound.RCWeaponImpactedTooFar.filename, RANGE.Sound.RCWeaponImpactedTooFar.duration, self.soundpath, nil, nil, _message, self.subduration ) self.rangecontrol:NewTransmission( RANGE.Sound.RCWeaponImpactedTooFar.filename, RANGE.Sound.RCWeaponImpactedTooFar.duration, self.soundpath, nil, nil, _message, self.subduration )
end end
end end
else else
self:T( self.lid .. "Weapon impacted outside range zone." ) self:T( self.lid .. "Weapon impacted outside range zone." )
end end
end end
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun). --- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
@ -2038,7 +2038,7 @@ function RANGE:OnEventShot( EventData )
if EventData.Weapon == nil or EventData.IniDCSUnit == nil or EventData.IniPlayerName == nil then if EventData.Weapon == nil or EventData.IniDCSUnit == nil or EventData.IniPlayerName == nil then
return return
end end
-- Create weapon object. -- Create weapon object.
local weapon=WEAPON:New(EventData.weapon) local weapon=WEAPON:New(EventData.weapon)
@ -2050,7 +2050,7 @@ function RANGE:OnEventShot( EventData )
-- Get player unit and name. -- Get player unit and name.
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
-- Distance Player-to-Range. Set this to larger value than the threshold. -- Distance Player-to-Range. Set this to larger value than the threshold.
local dPR = self.BombtrackThreshold * 2 local dPR = self.BombtrackThreshold * 2
@ -2065,16 +2065,16 @@ function RANGE:OnEventShot( EventData )
-- Player data. -- Player data.
local playerData = self.PlayerSettings[_playername] -- #RANGE.PlayerData local playerData = self.PlayerSettings[_playername] -- #RANGE.PlayerData
-- Attack parameters. -- Attack parameters.
local attackHdg=_unit:GetHeading() local attackHdg=_unit:GetHeading()
local attackAlt=_unit:GetHeight() local attackAlt=_unit:GetHeight()
attackAlt = UTILS.MetersToFeet(attackAlt) attackAlt = UTILS.MetersToFeet(attackAlt)
local attackVel=_unit:GetVelocityKNOTS() local attackVel=_unit:GetVelocityKNOTS()
-- Tracking info and init of last bomb position. -- Tracking info and init of last bomb position.
self:T( self.lid .. string.format( "RANGE %s: Tracking %s - %s.", self.rangename, weapon:GetTypeName(), weapon:GetName())) self:T( self.lid .. string.format( "RANGE %s: Tracking %s - %s.", self.rangename, weapon:GetTypeName(), weapon:GetName()))
-- Set callback function on impact. -- Set callback function on impact.
weapon:SetFuncImpact(RANGE._OnImpact, self, playerData, attackHdg, attackAlt, attackVel) weapon:SetFuncImpact(RANGE._OnImpact, self, playerData, attackHdg, attackAlt, attackVel)
@ -2146,33 +2146,33 @@ end
function RANGE:onafterEnterRange( From, Event, To, player ) function RANGE:onafterEnterRange( From, Event, To, player )
if self.instructor and self.rangecontrol then if self.instructor and self.rangecontrol then
if self.useSRS then if self.useSRS then
local text = string.format("You entered the bombing range. For hit assessment, contact the range controller at %.3f MHz", self.rangecontrolfreq) local text = string.format("You entered the bombing range. For hit assessment, contact the range controller at %.3f MHz", self.rangecontrolfreq)
local ttstext = string.format("You entered the bombing range. For hit assessment, contact the range controller at %.3f mega hertz.", self.rangecontrolfreq) local ttstext = string.format("You entered the bombing range. For hit assessment, contact the range controller at %.3f mega hertz.", self.rangecontrolfreq)
local group = player.client:GetGroup() local group = player.client:GetGroup()
self.instructsrsQ:NewTransmission(ttstext, nil, self.instructmsrs, nil, 1, {group}, text, 10) self.instructsrsQ:NewTransmission(ttstext, nil, self.instructmsrs, nil, 1, {group}, text, 10)
else else
-- Range control radio frequency split. -- Range control radio frequency split.
local RF = UTILS.Split( string.format( "%.3f", self.rangecontrolfreq ), "." ) local RF = UTILS.Split( string.format( "%.3f", self.rangecontrolfreq ), "." )
-- Radio message that player entered the range -- Radio message that player entered the range
-- You entered the bombing range. For hit assessment, contact the range controller at xy MHz -- You entered the bombing range. For hit assessment, contact the range controller at xy MHz
self.instructor:NewTransmission( RANGE.Sound.IREnterRange.filename, RANGE.Sound.IREnterRange.duration, self.soundpath ) self.instructor:NewTransmission( RANGE.Sound.IREnterRange.filename, RANGE.Sound.IREnterRange.duration, self.soundpath )
self.instructor:Number2Transmission( RF[1] ) self.instructor:Number2Transmission( RF[1] )
if tonumber( RF[2] ) > 0 then if tonumber( RF[2] ) > 0 then
self.instructor:NewTransmission( RANGE.Sound.IRDecimal.filename, RANGE.Sound.IRDecimal.duration, self.soundpath ) self.instructor:NewTransmission( RANGE.Sound.IRDecimal.filename, RANGE.Sound.IRDecimal.duration, self.soundpath )
self.instructor:Number2Transmission( RF[2] ) self.instructor:Number2Transmission( RF[2] )
end end
self.instructor:NewTransmission( RANGE.Sound.IRMegaHertz.filename, RANGE.Sound.IRMegaHertz.duration, self.soundpath ) self.instructor:NewTransmission( RANGE.Sound.IRMegaHertz.filename, RANGE.Sound.IRMegaHertz.duration, self.soundpath )
end end
end end
@ -2190,11 +2190,11 @@ function RANGE:onafterExitRange( From, Event, To, player )
if self.instructor then if self.instructor then
-- You left the bombing range zone. Have a nice day! -- You left the bombing range zone. Have a nice day!
if self.useSRS then if self.useSRS then
local text = "You left the bombing range zone. " local text = "You left the bombing range zone. "
local r=math.random(5) local r=math.random(5)
if r==1 then if r==1 then
text=text.."Have a nice day!" text=text.."Have a nice day!"
elseif r==2 then elseif r==2 then
@ -2204,9 +2204,9 @@ function RANGE:onafterExitRange( From, Event, To, player )
elseif r==4 then elseif r==4 then
text=text.."See you in two weeks!" text=text.."See you in two weeks!"
elseif r==5 then elseif r==5 then
text=text.."!" text=text.."!"
end end
self.instructsrsQ:NewTransmission(text, nil, self.instructmsrs, nil, 1, {player.client:GetGroup()}, text, 10) self.instructsrsQ:NewTransmission(text, nil, self.instructmsrs, nil, 1, {player.client:GetGroup()}, text, 10)
else else
self.instructor:NewTransmission( RANGE.Sound.IRExitRange.filename, RANGE.Sound.IRExitRange.duration, self.soundpath ) self.instructor:NewTransmission( RANGE.Sound.IRExitRange.filename, RANGE.Sound.IRExitRange.duration, self.soundpath )
@ -2240,7 +2240,7 @@ function RANGE:onafterImpact( From, Event, To, result, player )
text = text .. string.format( " %s hit.", result.quality ) text = text .. string.format( " %s hit.", result.quality )
if self.rangecontrol then if self.rangecontrol then
if self.useSRS then if self.useSRS then
local group = player.client:GetGroup() local group = player.client:GetGroup()
self.controlsrsQ:NewTransmission(text,nil,self.controlmsrs,nil,1,{group},text,10) self.controlsrsQ:NewTransmission(text,nil,self.controlmsrs,nil,1,{group},text,10)
@ -2265,10 +2265,10 @@ function RANGE:onafterImpact( From, Event, To, result, player )
-- Unit. -- Unit.
if player.unitname and not self.useSRS then if player.unitname and not self.useSRS then
-- Get unit. -- Get unit.
local unit = UNIT:FindByName( player.unitname ) local unit = UNIT:FindByName( player.unitname )
-- Send message. -- Send message.
self:_DisplayMessageToGroup( unit, text, nil, true ) self:_DisplayMessageToGroup( unit, text, nil, true )
self:T( self.lid .. text ) self:T( self.lid .. text )
@ -2278,7 +2278,7 @@ function RANGE:onafterImpact( From, Event, To, result, player )
if self.autosave then if self.autosave then
self:Save() self:Save()
end end
-- Send result to FunkMan, which creates fancy MatLab figures and sends them to Discord via a bot. -- Send result to FunkMan, which creates fancy MatLab figures and sends them to Discord via a bot.
if self.funkmanSocket then if self.funkmanSocket then
self.funkmanSocket:SendTable(result) self.funkmanSocket:SendTable(result)
@ -2547,7 +2547,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
local _message = string.format( "My Top %d Strafe Pit Results:\n", self.ndisplayresult ) local _message = string.format( "My Top %d Strafe Pit Results:\n", self.ndisplayresult )
-- Get player results. -- Get player results.
local _results = self.strafePlayerResults[_playername] local _results = self.strafePlayerResults[_playername]
-- Create message. -- Create message.
if _results == nil then if _results == nil then
@ -2853,7 +2853,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
end end
end end
text = text .. string.format( "Instructor %.3f MHz (Relay=%s)\n", self.instructorfreq, alive ) text = text .. string.format( "Instructor %.3f MHz (Relay=%s)\n", self.instructorfreq, alive )
end end
if self.rangecontrol then if self.rangecontrol then
local alive = "N/A" local alive = "N/A"
if self.rangecontrolrelayname then if self.rangecontrolrelayname then
@ -3081,10 +3081,10 @@ function RANGE:_CheckInZone( _unitName )
local unitheading = 0 -- RangeBoss local unitheading = 0 -- RangeBoss
if _unit and _playername then if _unit and _playername then
-- Player data. -- Player data.
local playerData=self.PlayerSettings[_playername] -- #RANGE.PlayerData local playerData=self.PlayerSettings[_playername] -- #RANGE.PlayerData
--- Function to check if unit is in zone and facing in the right direction and is below the max alt. --- Function to check if unit is in zone and facing in the right direction and is below the max alt.
local function checkme( targetheading, _zone ) local function checkme( targetheading, _zone )
local zone = _zone -- Core.Zone#ZONE local zone = _zone -- Core.Zone#ZONE
@ -3098,7 +3098,7 @@ function RANGE:_CheckInZone( _unitName )
if towardspit then if towardspit then
local vec3 = _unit:GetVec3() local vec3 = _unit:GetVec3()
local vec2 = { x = vec3.x, y = vec3.z } -- DCS#Vec2 local vec2 = { x = vec3.x, y = vec3.z } -- DCS#Vec2
local landheight = land.getHeight( vec2 ) local landheight = land.getHeight( vec2 )
local unitalt = vec3.y - landheight local unitalt = vec3.y - landheight
@ -3145,7 +3145,7 @@ function RANGE:_CheckInZone( _unitName )
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _msg, nil, true ) self:_DisplayMessageToGroup( _unit, _msg, nil, true )
if self.rangecontrol then if self.rangecontrol then
if self.useSRS then if self.useSRS then
local group = _unit:GetGroup() local group = _unit:GetGroup()
@ -3164,9 +3164,9 @@ function RANGE:_CheckInZone( _unitName )
-- Result. -- Result.
local _result = self.strafeStatus[_unitID] --#RANGE.StrafeStatus local _result = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
local _sound = nil -- #RANGE.Soundfile local _sound = nil -- #RANGE.Soundfile
-- Calculate accuracy of run. Number of hits wrt number of rounds fired. -- Calculate accuracy of run. Number of hits wrt number of rounds fired.
local shots = _result.ammo - _ammo local shots = _result.ammo - _ammo
local accur = 0 local accur = 0
@ -3176,7 +3176,7 @@ function RANGE:_CheckInZone( _unitName )
accur = 100 accur = 100
end end
end end
-- Results text and sound message. -- Results text and sound message.
local resulttext="" local resulttext=""
if _result.pastfoulline == true then -- if _result.pastfoulline == true then --
@ -3213,7 +3213,7 @@ function RANGE:_CheckInZone( _unitName )
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _text ) self:_DisplayMessageToGroup( _unit, _text )
-- Strafe result. -- Strafe result.
local result = {} -- #RANGE.StrafeResult local result = {} -- #RANGE.StrafeResult
result.command=SOCKET.DataType.STRAFERESULT result.command=SOCKET.DataType.STRAFERESULT
@ -3230,14 +3230,14 @@ function RANGE:_CheckInZone( _unitName )
result.rangename = self.rangename result.rangename = self.rangename
result.airframe=playerData.airframe result.airframe=playerData.airframe
result.invalid = _result.pastfoulline result.invalid = _result.pastfoulline
-- Griger Results. -- Griger Results.
self:StrafeResult(playerData, result) self:StrafeResult(playerData, result)
-- Save trap sheet. -- Save trap sheet.
if playerData and playerData.targeton and self.targetsheet then if playerData and playerData.targeton and self.targetsheet then
self:_SaveTargetSheet( _playername, result ) self:_SaveTargetSheet( _playername, result )
end end
-- Voice over. -- Voice over.
if self.rangecontrol then if self.rangecontrol then
@ -3302,7 +3302,7 @@ function RANGE:_CheckInZone( _unitName )
-- Send message. -- Send message.
self:_DisplayMessageToGroup( _unit, _msg, 10, true ) self:_DisplayMessageToGroup( _unit, _msg, 10, true )
-- Trigger event that player is rolling in. -- Trigger event that player is rolling in.
self:RollingIn(playerData, target) self:RollingIn(playerData, target)
@ -3438,18 +3438,18 @@ function RANGE:_GetBombTargetCoordinate( target )
local coord = nil -- Core.Point#COORDINATE local coord = nil -- Core.Point#COORDINATE
if target.type == RANGE.TargetType.UNIT then if target.type == RANGE.TargetType.UNIT then
-- Check if alive -- Check if alive
if target.target and target.target:IsAlive() then if target.target and target.target:IsAlive() then
-- Get current position. -- Get current position.
coord = target.target:GetCoordinate() coord = target.target:GetCoordinate()
-- Save as last known position in case target dies. -- Save as last known position in case target dies.
target.coordinate=coord target.coordinate=coord
else else
-- Use stored position. -- Use stored position.
coord = target.coordinate coord = target.coordinate
end end
elseif target.type == RANGE.TargetType.STATIC then elseif target.type == RANGE.TargetType.STATIC then
-- Static targets dont move. -- Static targets dont move.
@ -3459,11 +3459,11 @@ function RANGE:_GetBombTargetCoordinate( target )
-- Coordinates dont move. -- Coordinates dont move.
coord = target.coordinate coord = target.coordinate
elseif target.type == RANGE.TargetType.SCENERY then elseif target.type == RANGE.TargetType.SCENERY then
-- Coordinates dont move. -- Coordinates dont move.
coord = target.coordinate coord = target.coordinate
else else
self:E( self.lid .. "ERROR: Unknown target type." ) self:E( self.lid .. "ERROR: Unknown target type." )
@ -3670,7 +3670,7 @@ function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display, _to
local playermessage = self.PlayerSettings[playername].messages local playermessage = self.PlayerSettings[playername].messages
-- Send message to player if messages enabled and not only for the examiner. -- Send message to player if messages enabled and not only for the examiner.
if _gid and (playermessage == true or display) and (not self.examinerexclusive) then if _gid and (playermessage == true or display) and (not self.examinerexclusive) then
if _togroup and _grp then if _togroup and _grp then
local m = MESSAGE:New(_text,_time,nil,_clear):ToGroup(_grp) local m = MESSAGE:New(_text,_time,nil,_clear):ToGroup(_grp)
@ -4025,9 +4025,9 @@ function RANGE:_GetPlayerUnitAndName( _unitName )
self:F2( _unitName ) self:F2( _unitName )
if _unitName ~= nil then if _unitName ~= nil then
local multiplayer = false local multiplayer = false
-- Get DCS unit from its name. -- Get DCS unit from its name.
local DCSunit = Unit.getByName( _unitName ) local DCSunit = Unit.getByName( _unitName )
@ -4066,7 +4066,7 @@ function RANGE:_myname( unitname )
if grp and grp:IsAlive() then if grp and grp:IsAlive() then
pname = grp:GetCustomCallSign(true,true) pname = grp:GetCustomCallSign(true,true)
end end
end end
return pname return pname
end end