mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge branch 'develop' into Functional-ATC_Ground_AlertFreqCustom_PersianGulf
This commit is contained in:
@@ -216,7 +216,7 @@
|
||||
-- One way to determin which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}().
|
||||
-- In debug mode, the all ammo types of the group are printed to the monitor as message and can be found in the DCS.log file.
|
||||
--
|
||||
-- ## Empoying Selected Weapons
|
||||
-- ## Employing Selected Weapons
|
||||
--
|
||||
-- If an ARTY group carries multiple weapons, which can be used for artillery task, a certain weapon type can be selected to attack the target.
|
||||
-- This is done via the *weapontype* parameter of the @{#ARTY.AssignTargetCoord}(..., *weapontype*, ...) function.
|
||||
@@ -674,11 +674,13 @@ ARTY.id="ARTY | "
|
||||
|
||||
--- Arty script version.
|
||||
-- @field #string version
|
||||
ARTY.version="1.0.6"
|
||||
ARTY.version="1.0.7"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO list:
|
||||
-- TODO: Add hit event and make the arty group relocate.
|
||||
-- TODO: Handle rearming for ships. How?
|
||||
-- DONE: Delete targets from queue user function.
|
||||
-- DONE: Delete entire target queue user function.
|
||||
-- DONE: Add weapon types. Done but needs improvements.
|
||||
@@ -697,11 +699,9 @@ ARTY.version="1.0.6"
|
||||
-- DONE: Add command move to make arty group move.
|
||||
-- DONE: remove schedulers for status event.
|
||||
-- DONE: Improve handling of special weapons. When winchester if using selected weapons?
|
||||
-- TODO: Handle rearming for ships. How?
|
||||
-- DONE: Make coordinate after rearming general, i.e. also work after the group has moved to anonther location.
|
||||
-- DONE: Add set commands via markers. E.g. set rearming place.
|
||||
-- DONE: Test stationary types like mortas ==> rearming etc.
|
||||
-- TODO: Add hit event and make the arty group relocate.
|
||||
-- DONE: Add illumination and smoke.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -2878,7 +2878,7 @@ function ARTY:onafterCeaseFire(Controllable, From, Event, To, target)
|
||||
self.Controllable:ClearTasks()
|
||||
|
||||
else
|
||||
self:E(ARTY.id.."ERROR: No target in cease fire for group %s.", self.groupname)
|
||||
self:E(ARTY.id..string.format("ERROR: No target in cease fire for group %s.", self.groupname))
|
||||
end
|
||||
|
||||
-- Set number of shots to zero.
|
||||
@@ -4253,101 +4253,116 @@ end
|
||||
-- @param #ARTY self
|
||||
function ARTY:_CheckTargetsInRange()
|
||||
|
||||
local targets2delete={}
|
||||
|
||||
for i=1,#self.targets do
|
||||
local _target=self.targets[i]
|
||||
|
||||
self:T3(ARTY.id..string.format("Before: Target %s - in range = %s", _target.name, tostring(_target.inrange)))
|
||||
|
||||
-- Check if target is in range.
|
||||
local _inrange,_toofar,_tooclose=self:_TargetInRange(_target)
|
||||
local _inrange,_toofar,_tooclose,_remove=self:_TargetInRange(_target)
|
||||
self:T3(ARTY.id..string.format("Inbetw: Target %s - in range = %s, toofar = %s, tooclose = %s", _target.name, tostring(_target.inrange), tostring(_toofar), tostring(_tooclose)))
|
||||
|
||||
-- Init default for assigning moves into range.
|
||||
local _movetowards=false
|
||||
local _moveaway=false
|
||||
if _remove then
|
||||
|
||||
if _target.inrange==nil then
|
||||
|
||||
-- First time the check is performed. We call the function again and send a message.
|
||||
_target.inrange,_toofar,_tooclose=self:_TargetInRange(_target, self.report or self.Debug)
|
||||
-- The ARTY group is immobile and not cargo but the target is not in range!
|
||||
table.insert(targets2delete, _target.name)
|
||||
|
||||
-- Send group towards/away from target.
|
||||
if _toofar then
|
||||
_movetowards=true
|
||||
elseif _tooclose then
|
||||
_moveaway=true
|
||||
end
|
||||
else
|
||||
|
||||
elseif _target.inrange==true then
|
||||
|
||||
-- Target was in range at previous check...
|
||||
|
||||
if _toofar then --...but is now too far away.
|
||||
_movetowards=true
|
||||
elseif _tooclose then --...but is now too close.
|
||||
_moveaway=true
|
||||
end
|
||||
|
||||
elseif _target.inrange==false then
|
||||
|
||||
-- Target was out of range at previous check.
|
||||
-- Init default for assigning moves into range.
|
||||
local _movetowards=false
|
||||
local _moveaway=false
|
||||
|
||||
if _inrange then
|
||||
-- Inform coalition that target is now in range.
|
||||
local text=string.format("%s, target %s is now in range.", self.alias, _target.name)
|
||||
self:T(ARTY.id..text)
|
||||
MESSAGE:New(text,10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Assign a relocation command so that the unit will be in range of the requested target.
|
||||
if self.autorelocate and (_movetowards or _moveaway) then
|
||||
|
||||
-- Get current position.
|
||||
local _from=self.Controllable:GetCoordinate()
|
||||
local _dist=_from:Get2DDistance(_target.coord)
|
||||
if _target.inrange==nil then
|
||||
|
||||
if _dist<=self.autorelocatemaxdist then
|
||||
|
||||
local _tocoord --Core.Point#COORDINATE
|
||||
local _name=""
|
||||
local _safetymargin=500
|
||||
|
||||
if _movetowards then
|
||||
-- First time the check is performed. We call the function again and send a message.
|
||||
_target.inrange,_toofar,_tooclose=self:_TargetInRange(_target, self.report or self.Debug)
|
||||
|
||||
-- Target was in range on previous check but now we are too far away.
|
||||
local _waytogo=_dist-self.maxrange+_safetymargin
|
||||
local _heading=self:_GetHeading(_from,_target.coord)
|
||||
_tocoord=_from:Translate(_waytogo, _heading)
|
||||
_name=string.format("%s, relocation to within max firing range of target %s", self.alias, _target.name)
|
||||
|
||||
elseif _moveaway then
|
||||
|
||||
-- Target was in range on previous check but now we are too far away.
|
||||
local _waytogo=_dist-self.minrange+_safetymargin
|
||||
local _heading=self:_GetHeading(_target.coord,_from)
|
||||
_tocoord=_from:Translate(_waytogo, _heading)
|
||||
_name=string.format("%s, relocation to within min firing range of target %s", self.alias, _target.name)
|
||||
|
||||
-- Send group towards/away from target.
|
||||
if _toofar then
|
||||
_movetowards=true
|
||||
elseif _tooclose then
|
||||
_moveaway=true
|
||||
end
|
||||
|
||||
-- Send info message.
|
||||
MESSAGE:New(_name.." assigned.", 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug)
|
||||
|
||||
-- Assign relocation move.
|
||||
self:AssignMoveCoord(_tocoord, nil, nil, self.autorelocateonroad, false, _name, true)
|
||||
|
||||
elseif _target.inrange==true then
|
||||
|
||||
-- Target was in range at previous check...
|
||||
|
||||
if _toofar then --...but is now too far away.
|
||||
_movetowards=true
|
||||
elseif _tooclose then --...but is now too close.
|
||||
_moveaway=true
|
||||
end
|
||||
|
||||
elseif _target.inrange==false then
|
||||
|
||||
-- Target was out of range at previous check.
|
||||
|
||||
if _inrange then
|
||||
-- Inform coalition that target is now in range.
|
||||
local text=string.format("%s, target %s is now in range.", self.alias, _target.name)
|
||||
self:T(ARTY.id..text)
|
||||
MESSAGE:New(text,10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Assign a relocation command so that the unit will be in range of the requested target.
|
||||
if self.autorelocate and (_movetowards or _moveaway) then
|
||||
|
||||
-- Get current position.
|
||||
local _from=self.Controllable:GetCoordinate()
|
||||
local _dist=_from:Get2DDistance(_target.coord)
|
||||
|
||||
if _dist<=self.autorelocatemaxdist then
|
||||
|
||||
local _tocoord --Core.Point#COORDINATE
|
||||
local _name=""
|
||||
local _safetymargin=500
|
||||
|
||||
if _movetowards then
|
||||
|
||||
-- Target was in range on previous check but now we are too far away.
|
||||
local _waytogo=_dist-self.maxrange+_safetymargin
|
||||
local _heading=self:_GetHeading(_from,_target.coord)
|
||||
_tocoord=_from:Translate(_waytogo, _heading)
|
||||
_name=string.format("%s, relocation to within max firing range of target %s", self.alias, _target.name)
|
||||
|
||||
elseif _moveaway then
|
||||
|
||||
-- Target was in range on previous check but now we are too far away.
|
||||
local _waytogo=_dist-self.minrange+_safetymargin
|
||||
local _heading=self:_GetHeading(_target.coord,_from)
|
||||
_tocoord=_from:Translate(_waytogo, _heading)
|
||||
_name=string.format("%s, relocation to within min firing range of target %s", self.alias, _target.name)
|
||||
|
||||
end
|
||||
|
||||
-- Send info message.
|
||||
MESSAGE:New(_name.." assigned.", 10):ToCoalitionIf(self.Controllable:GetCoalition(), self.report or self.Debug)
|
||||
|
||||
-- Assign relocation move.
|
||||
self:AssignMoveCoord(_tocoord, nil, nil, self.autorelocateonroad, false, _name, true)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Update value.
|
||||
_target.inrange=_inrange
|
||||
|
||||
self:T3(ARTY.id..string.format("After: Target %s - in range = %s", _target.name, tostring(_target.inrange)))
|
||||
end
|
||||
|
||||
-- Update value.
|
||||
_target.inrange=_inrange
|
||||
|
||||
self:T3(ARTY.id..string.format("After: Target %s - in range = %s", _target.name, tostring(_target.inrange)))
|
||||
|
||||
end
|
||||
|
||||
-- Remove targets not in range.
|
||||
for _,targetname in pairs(targets2delete) do
|
||||
self:RemoveTarget(targetname)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Check all normal (untimed) targets and return the target with the highest priority which has been engaged the fewest times.
|
||||
@@ -4728,6 +4743,7 @@ end
|
||||
-- @return #boolean True if target is in range, false otherwise.
|
||||
-- @return #boolean True if ARTY group is too far away from the target, i.e. distance > max firing range.
|
||||
-- @return #boolean True if ARTY group is too close to the target, i.e. distance < min finring range.
|
||||
-- @return #boolean True if target should be removed since ARTY group is immobile and not cargo.
|
||||
function ARTY:_TargetInRange(target, message)
|
||||
self:F3(target)
|
||||
|
||||
@@ -4763,11 +4779,13 @@ function ARTY:_TargetInRange(target, message)
|
||||
end
|
||||
|
||||
-- Remove target if ARTY group cannot move, e.g. Mortas. No chance to be ever in range - unless they are cargo.
|
||||
local _remove=false
|
||||
if not (self.ismobile or self.iscargo) and _inrange==false then
|
||||
self:RemoveTarget(target.name)
|
||||
--self:RemoveTarget(target.name)
|
||||
_remove=true
|
||||
end
|
||||
|
||||
return _inrange,_toofar,_tooclose
|
||||
return _inrange,_toofar,_tooclose,_remove
|
||||
end
|
||||
|
||||
--- Get the weapon type name, which should be used to attack the target.
|
||||
|
||||
@@ -1012,7 +1012,7 @@ do -- DETECTION_BASE
|
||||
--- Set the parameters to calculate to optimal intercept point.
|
||||
-- @param #DETECTION_BASE self
|
||||
-- @param #boolean Intercept Intercept is true if an intercept point is calculated. Intercept is false if it is disabled. The default Intercept is false.
|
||||
-- @param #number IntereptDelay If Intercept is true, then InterceptDelay is the average time it takes to get airplanes airborne.
|
||||
-- @param #number InterceptDelay If Intercept is true, then InterceptDelay is the average time it takes to get airplanes airborne.
|
||||
-- @return #DETECTION_BASE self
|
||||
function DETECTION_BASE:SetIntercept( Intercept, InterceptDelay )
|
||||
self:F2()
|
||||
@@ -1233,7 +1233,7 @@ do -- DETECTION_BASE
|
||||
-- @param DCS#Unit.Category Category The category of the unit.
|
||||
-- @return #boolean true if there are friendlies nearby
|
||||
function DETECTION_BASE:IsFriendliesNearBy( DetectedItem, Category )
|
||||
--self:F( { "FriendliesNearBy Test", DetectedItem.FriendliesNearBy } )
|
||||
-- self:F( { "FriendliesNearBy Test", DetectedItem.FriendliesNearBy } )
|
||||
return ( DetectedItem.FriendliesNearBy and DetectedItem.FriendliesNearBy[Category] ~= nil ) or false
|
||||
end
|
||||
|
||||
|
||||
@@ -546,7 +546,7 @@ RAT.id="RAT | "
|
||||
--- RAT version.
|
||||
-- @list version
|
||||
RAT.version={
|
||||
version = "2.3.4",
|
||||
version = "2.3.5",
|
||||
print = true,
|
||||
}
|
||||
|
||||
@@ -717,6 +717,11 @@ function RAT:Spawn(naircraft)
|
||||
self.FLcruise=005*RAT.unit.FL2m
|
||||
end
|
||||
end
|
||||
|
||||
-- Enable helos to go to destinations 100 meters away.
|
||||
if self.category==RAT.cat.heli then
|
||||
self.mindist=50
|
||||
end
|
||||
|
||||
-- Run consistency checks.
|
||||
self:_CheckConsistency()
|
||||
@@ -1812,14 +1817,14 @@ function RAT:ATC_Delay(time)
|
||||
end
|
||||
|
||||
--- Set minimum distance between departure and destination. Default is 5 km.
|
||||
-- Minimum distance should not be smaller than maybe ~500 meters to ensure that departure and destination are different.
|
||||
-- Minimum distance should not be smaller than maybe ~100 meters to ensure that departure and destination are different.
|
||||
-- @param #RAT self
|
||||
-- @param #number dist Distance in km.
|
||||
-- @return #RAT RAT self object.
|
||||
function RAT:SetMinDistance(dist)
|
||||
self:F2(dist)
|
||||
-- Distance in meters. Absolute minimum is 500 m.
|
||||
self.mindist=math.max(500, dist*1000)
|
||||
self.mindist=math.max(100, dist*1000)
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -2446,7 +2451,7 @@ function RAT:_SetRoute(takeoff, landing, _departure, _destination, _waypoint)
|
||||
local VxCruiseMax
|
||||
if self.Vcruisemax then
|
||||
-- User input.
|
||||
VxCruiseMax = min(self.Vcruisemax, self.aircraft.Vmax)
|
||||
VxCruiseMax = math.min(self.Vcruisemax, self.aircraft.Vmax)
|
||||
else
|
||||
-- Max cruise speed 90% of Vmax or 900 km/h whichever is lower.
|
||||
VxCruiseMax = math.min(self.aircraft.Vmax*0.90, 250)
|
||||
@@ -5435,7 +5440,7 @@ function RAT:_ATCInit(airports_map)
|
||||
if not RAT.ATC.init then
|
||||
local text
|
||||
text="Starting RAT ATC.\nSimultanious = "..RAT.ATC.Nclearance.."\n".."Delay = "..RAT.ATC.delay
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
RAT.ATC.init=true
|
||||
for _,ap in pairs(airports_map) do
|
||||
local name=ap:GetName()
|
||||
@@ -5458,7 +5463,7 @@ end
|
||||
-- @param #string name Group name of the flight.
|
||||
-- @param #string dest Name of the destination airport.
|
||||
function RAT:_ATCAddFlight(name, dest)
|
||||
self:T(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest))
|
||||
BASE:T(string.format("%sATC %s: Adding flight %s with destination %s.", RAT.id, dest, name, dest))
|
||||
RAT.ATC.flight[name]={}
|
||||
RAT.ATC.flight[name].destination=dest
|
||||
RAT.ATC.flight[name].Tarrive=-1
|
||||
@@ -5483,7 +5488,7 @@ end
|
||||
-- @param #string name Group name of the flight.
|
||||
-- @param #number time Time the fight first registered.
|
||||
function RAT:_ATCRegisterFlight(name, time)
|
||||
self:T(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.")
|
||||
BASE:T(RAT.id.."Flight ".. name.." registered at ATC for landing clearance.")
|
||||
RAT.ATC.flight[name].Tarrive=time
|
||||
RAT.ATC.flight[name].holding=0
|
||||
end
|
||||
@@ -5514,7 +5519,7 @@ function RAT:_ATCStatus()
|
||||
|
||||
-- Aircraft is holding.
|
||||
local text=string.format("ATC %s: Flight %s is holding for %i:%02d. %s.", dest, name, hold/60, hold%60, busy)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
elseif hold==RAT.ATC.onfinal then
|
||||
|
||||
@@ -5522,7 +5527,7 @@ function RAT:_ATCStatus()
|
||||
local Tfinal=Tnow-RAT.ATC.flight[name].Tonfinal
|
||||
|
||||
local text=string.format("ATC %s: Flight %s is on final. Waiting %i:%02d for landing event.", dest, name, Tfinal/60, Tfinal%60)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
elseif hold==RAT.ATC.unregistered then
|
||||
|
||||
@@ -5530,7 +5535,7 @@ function RAT:_ATCStatus()
|
||||
--self:T(string.format("ATC %s: Flight %s is not registered yet (hold %d).", dest, name, hold))
|
||||
|
||||
else
|
||||
self:E(RAT.id.."ERROR: Unknown holding time in RAT:_ATCStatus().")
|
||||
BASE:E(RAT.id.."ERROR: Unknown holding time in RAT:_ATCStatus().")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5572,12 +5577,12 @@ function RAT:_ATCCheck()
|
||||
|
||||
-- Debug message.
|
||||
local text=string.format("ATC %s: Flight %s runway is busy. You are #%d of %d in landing queue. Your holding time is %i:%02d.", name, flight,qID, nqueue, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
else
|
||||
|
||||
local text=string.format("ATC %s: Flight %s was cleared for landing. Your holding time was %i:%02d.", name, flight, RAT.ATC.flight[flight].holding/60, RAT.ATC.flight[flight].holding%60)
|
||||
self:T(RAT.id..text)
|
||||
BASE:T(RAT.id..text)
|
||||
|
||||
-- Clear flight for landing.
|
||||
RAT:_ATCClearForLanding(name, flight)
|
||||
@@ -5705,12 +5710,7 @@ function RAT:_ATCQueue()
|
||||
for k,v in ipairs(_queue) do
|
||||
table.insert(RAT.ATC.airport[airport].queue, v[1])
|
||||
end
|
||||
|
||||
--fvh
|
||||
--for k,v in ipairs(RAT.ATC.airport[airport].queue) do
|
||||
--print(string.format("queue #%02i flight \"%s\" holding %d seconds",k, v, RAT.ATC.flight[v].holding))
|
||||
--end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
--
|
||||
-- ## Features:
|
||||
--
|
||||
-- * Impact points of bombs, rockets and missils are recorded and distance to closest range target is measured and reported to the player.
|
||||
-- * Impact points of bombs, rockets and missiles are recorded and distance to closest range target is measured and reported to the player.
|
||||
-- * Number of hits on strafing passes are counted and reported. Also the percentage of hits w.r.t fired shots is evaluated.
|
||||
-- * Results of all bombing and strafing runs are stored and top 10 results can be displayed.
|
||||
-- * Range targets can be marked by smoke.
|
||||
@@ -56,9 +56,9 @@
|
||||
-- @field #table strafeStatus Table containing the current strafing target a player as assigned to.
|
||||
-- @field #table strafePlayerResults Table containing the strafing results of each player.
|
||||
-- @field #table bombPlayerResults Table containing the bombing results of each player.
|
||||
-- @field #table PlayerSettings Indiviual player settings.
|
||||
-- @field #table PlayerSettings Individual player settings.
|
||||
-- @field #number dtBombtrack Time step [sec] used for tracking released bomb/rocket positions. Default 0.005 seconds.
|
||||
-- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threashold [m]. Default 25000 m.
|
||||
-- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threshold [m]. Default 25000 m.
|
||||
-- @field #number Tmsg Time [sec] messages to players are displayed. Default 30 sec.
|
||||
-- @field #string examinergroupname Name of the examiner group which should get all messages.
|
||||
-- @field #boolean examinerexclusive If true, only the examiner gets messages. If false, clients and examiner get messages.
|
||||
@@ -75,10 +75,11 @@
|
||||
-- @field #boolean trackbombs If true (default), all bomb types are tracked and impact point to closest bombing target is evaluated.
|
||||
-- @field #boolean trackrockets If true (default), all rocket types are tracked and impact point to closest bombing target is evaluated.
|
||||
-- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated.
|
||||
-- @field #boolean defaultsmokebomb If true, initialize player settings to smoke bomb.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Enables a mission designer to easily set up practice ranges in DCS. A new RANGE object can be created with the @{#RANGE.New}(rangename) contructor.
|
||||
-- The parameter "rangename" defindes the name of the range. It has to be unique since this is also the name displayed in the radio menu.
|
||||
-- The parameter "rangename" defines the name of the range. It has to be unique since this is also the name displayed in the radio menu.
|
||||
--
|
||||
-- Generally, a range consists of strafe pits and bombing targets. For strafe pits the number of hits for each pass is counted and tabulated.
|
||||
-- For bombing targets, the distance from the impact point of the bomb, rocket or missile to the closest range target is measured and tabulated.
|
||||
@@ -89,12 +90,12 @@
|
||||
-- **IMPORTANT**
|
||||
--
|
||||
-- Due to a DCS bug, it is not possible to directly monitor when a player enters a plane. So in a mission with client slots, it is vital that
|
||||
-- a player first enters as spector and **after that** jumps into the slot of his aircraft!
|
||||
-- a player first enters as spectator or hits ESC twice and **after that** jumps into the slot of his aircraft!
|
||||
-- If that is not done, the script is not started correctly. This can be checked by looking at the radio menues. If the mission was entered correctly,
|
||||
-- there should be an "On the Range" menu items in the "F10. Other..." menu.
|
||||
--
|
||||
-- ## Strafe Pits
|
||||
-- Each strafe pit can consist of multiple targets. Often one findes two or three strafe targets next to each other.
|
||||
-- Each strafe pit can consist of multiple targets. Often one finds two or three strafe targets next to each other.
|
||||
--
|
||||
-- A strafe pit can be added to the range by the @{#RANGE.AddStrafePit}(*targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*) function.
|
||||
--
|
||||
@@ -104,7 +105,7 @@
|
||||
-- If the parameter *heading* is passed as **nil**, the heading is automatically taken from the heading of the first target unit as defined in the ME.
|
||||
-- The parameter *inverseheading* turns the heading around by 180 degrees. This is sometimes useful, since the default heading of strafe target units point in the
|
||||
-- wrong/opposite direction.
|
||||
-- * The parameter *goodpass* defines the number of hits a pilot has to achive during a run to be judged as a "good" pass.
|
||||
-- * The parameter *goodpass* defines the number of hits a pilot has to achieve during a run to be judged as a "good" pass.
|
||||
-- * The last parameter *foulline* sets the distance from the pit targets to the foul line. Hit from closer than this line are not counted!
|
||||
--
|
||||
-- Another function to add a strafe pit is @{#RANGE.AddStrafePitGroup}(*group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline*). Here,
|
||||
@@ -151,7 +152,7 @@
|
||||
-- * "F2. My Settings": Player specific settings.
|
||||
-- * "F3. Stats" Player: statistics and scores.
|
||||
-- * "Range Information": Information about the range, such as bearing and range. Also range and player specific settings are displayed.
|
||||
-- * "Weather Report": Temperatur, wind and QFE pressure information is provided.
|
||||
-- * "Weather Report": Temperature, wind and QFE pressure information is provided.
|
||||
--
|
||||
-- ## Examples
|
||||
--
|
||||
@@ -243,6 +244,7 @@ RANGE={
|
||||
trackbombs=true,
|
||||
trackrockets=true,
|
||||
trackmissiles=true,
|
||||
defaultsmokebomb=true,
|
||||
}
|
||||
|
||||
--- Default range parameters.
|
||||
@@ -266,19 +268,25 @@ RANGE.Defaults={
|
||||
-- @field #table Names
|
||||
RANGE.Names={}
|
||||
|
||||
--- Main radio menu.
|
||||
-- @field #table MenuF10
|
||||
--- Main radio menu on group level.
|
||||
-- @field #table MenuF10 Root menu table on group level.
|
||||
RANGE.MenuF10={}
|
||||
|
||||
--- Main radio menu on mission level.
|
||||
-- @field #table MenuF10Root Root menu on mission level.
|
||||
RANGE.MenuF10Root=nil
|
||||
|
||||
--- Some ID to identify who we are in output of the DCS.log file.
|
||||
-- @field #string id
|
||||
RANGE.id="RANGE | "
|
||||
|
||||
--- Range script version.
|
||||
-- @field #string version
|
||||
RANGE.version="1.2.1"
|
||||
RANGE.version="1.2.4"
|
||||
|
||||
--TODO list:
|
||||
--TODO: Verbosity level for messages.
|
||||
--TODO: Add option for default settings such as smoke off.
|
||||
--TODO: Add custom weapons, which can be specified by the user.
|
||||
--TODO: Check if units are still alive.
|
||||
--DONE: Add statics for strafe pits.
|
||||
@@ -310,6 +318,9 @@ function RANGE:New(rangename)
|
||||
local text=string.format("RANGE script version %s - creating new RANGE object of name: %s.", RANGE.version, self.rangename)
|
||||
self:E(RANGE.id..text)
|
||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
||||
|
||||
-- Defaults
|
||||
self:SetDefaultPlayerSmokeBomb()
|
||||
|
||||
-- Return object.
|
||||
return self
|
||||
@@ -317,93 +328,102 @@ end
|
||||
|
||||
--- Initializes number of targets and location of the range. Starts the event handlers.
|
||||
-- @param #RANGE self
|
||||
function RANGE:Start()
|
||||
-- @param #number delay Delay in seconds, before the RANGE is started. Default immediately.
|
||||
-- @return self
|
||||
function RANGE:Start(delay)
|
||||
self:F()
|
||||
|
||||
-- Location/coordinate of range.
|
||||
local _location=nil
|
||||
if delay and delay>0 then
|
||||
SCHEDULER:New(nil, self.Start, {self}, delay)
|
||||
else
|
||||
|
||||
-- Count bomb targets.
|
||||
local _count=0
|
||||
for _,_target in pairs(self.bombingTargets) do
|
||||
_count=_count+1
|
||||
-- Location/coordinate of range.
|
||||
local _location=nil
|
||||
|
||||
-- Get range location.
|
||||
if _location==nil then
|
||||
_location=_target.target:GetCoordinate() --Core.Point#COORDINATE
|
||||
end
|
||||
end
|
||||
self.nbombtargets=_count
|
||||
|
||||
-- Count strafing targets.
|
||||
_count=0
|
||||
for _,_target in pairs(self.strafeTargets) do
|
||||
_count=_count+1
|
||||
|
||||
for _,_unit in pairs(_target.targets) do
|
||||
-- Count bomb targets.
|
||||
local _count=0
|
||||
for _,_target in pairs(self.bombingTargets) do
|
||||
_count=_count+1
|
||||
|
||||
-- Get range location.
|
||||
if _location==nil then
|
||||
_location=_unit:GetCoordinate()
|
||||
_location=_target.target:GetCoordinate() --Core.Point#COORDINATE
|
||||
end
|
||||
end
|
||||
end
|
||||
self.nstrafetargets=_count
|
||||
|
||||
-- Location of the range. We simply take the first unit/target we find if it was not explicitly specified by the user.
|
||||
if self.location==nil then
|
||||
self.location=_location
|
||||
end
|
||||
|
||||
if self.location==nil then
|
||||
local text=string.format("ERROR! No range location found. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
||||
self:E(RANGE.id..text)
|
||||
return
|
||||
end
|
||||
|
||||
-- Define a MOOSE zone of the range.
|
||||
if self.rangezone==nil then
|
||||
self.rangezone=ZONE_RADIUS:New(self.rangename, {x=self.location.x, y=self.location.z}, self.rangeradius)
|
||||
end
|
||||
|
||||
-- Starting range.
|
||||
local text=string.format("Starting RANGE %s. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
||||
self:E(RANGE.id..text)
|
||||
MESSAGE:New(text,10):ToAllIf(self.Debug)
|
||||
|
||||
-- Event handling.
|
||||
if self.eventmoose then
|
||||
-- Events are handled my MOOSE.
|
||||
self:T(RANGE.id.."Events are handled by MOOSE.")
|
||||
self:HandleEvent(EVENTS.Birth)
|
||||
self:HandleEvent(EVENTS.Hit)
|
||||
self:HandleEvent(EVENTS.Shot)
|
||||
else
|
||||
-- Events are handled directly by DCS.
|
||||
self:T(RANGE.id.."Events are handled directly by DCS.")
|
||||
world.addEventHandler(self)
|
||||
end
|
||||
|
||||
-- Make bomb target move randomly within the range zone.
|
||||
for _,_target in pairs(self.bombingTargets) do
|
||||
|
||||
-- Check if it is a static object.
|
||||
local _static=self:_CheckStatic(_target.target:GetName())
|
||||
self.nbombtargets=_count
|
||||
|
||||
if _target.move and _static==false and _target.speed>1 then
|
||||
local unit=_target.target --Wrapper.Unit#UNIT
|
||||
_target.target:PatrolZones({self.rangezone}, _target.speed*0.75, "Off road")
|
||||
-- Count strafing targets.
|
||||
_count=0
|
||||
for _,_target in pairs(self.strafeTargets) do
|
||||
_count=_count+1
|
||||
|
||||
for _,_unit in pairs(_target.targets) do
|
||||
if _location==nil then
|
||||
_location=_unit:GetCoordinate()
|
||||
end
|
||||
end
|
||||
end
|
||||
self.nstrafetargets=_count
|
||||
|
||||
-- Location of the range. We simply take the first unit/target we find if it was not explicitly specified by the user.
|
||||
if self.location==nil then
|
||||
self.location=_location
|
||||
end
|
||||
|
||||
if self.location==nil then
|
||||
local text=string.format("ERROR! No range location found. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
||||
self:E(RANGE.id..text)
|
||||
return
|
||||
end
|
||||
|
||||
-- Define a MOOSE zone of the range.
|
||||
if self.rangezone==nil then
|
||||
self.rangezone=ZONE_RADIUS:New(self.rangename, {x=self.location.x, y=self.location.z}, self.rangeradius)
|
||||
end
|
||||
|
||||
-- Starting range.
|
||||
local text=string.format("Starting RANGE %s. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
||||
self:I(RANGE.id..text)
|
||||
MESSAGE:New(text,10):ToAllIf(self.Debug)
|
||||
|
||||
-- Event handling.
|
||||
if self.eventmoose then
|
||||
-- Events are handled my MOOSE.
|
||||
self:T(RANGE.id.."Events are handled by MOOSE.")
|
||||
self:HandleEvent(EVENTS.Birth)
|
||||
self:HandleEvent(EVENTS.Hit)
|
||||
self:HandleEvent(EVENTS.Shot)
|
||||
else
|
||||
-- Events are handled directly by DCS.
|
||||
self:T(RANGE.id.."Events are handled directly by DCS.")
|
||||
world.addEventHandler(self)
|
||||
end
|
||||
|
||||
-- Make bomb target move randomly within the range zone.
|
||||
for _,_target in pairs(self.bombingTargets) do
|
||||
|
||||
-- Check if it is a static object.
|
||||
local _static=self:_CheckStatic(_target.target:GetName())
|
||||
|
||||
if _target.move and _static==false and _target.speed>1 then
|
||||
local unit=_target.target --Wrapper.Unit#UNIT
|
||||
_target.target:PatrolZones({self.rangezone}, _target.speed*0.75, "Off road")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Debug mode: smoke all targets and range zone.
|
||||
if self.Debug then
|
||||
self:_MarkTargetsOnMap()
|
||||
self:_SmokeBombTargets()
|
||||
self:_SmokeStrafeTargets()
|
||||
self:_SmokeStrafeTargetBoxes()
|
||||
self.rangezone:SmokeZone(SMOKECOLOR.White)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Debug mode: smoke all targets and range zone.
|
||||
if self.Debug then
|
||||
self:_MarkTargetsOnMap()
|
||||
self:_SmokeBombTargets()
|
||||
self:_SmokeStrafeTargets()
|
||||
self:_SmokeStrafeTargetBoxes()
|
||||
self.rangezone:SmokeZone(SMOKECOLOR.White)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -412,143 +432,199 @@ end
|
||||
--- Set maximal strafing altitude. Player entering a strafe pit above that altitude are not registered for a valid pass.
|
||||
-- @param #RANGE self
|
||||
-- @param #number maxalt Maximum altitude AGL in meters. Default is 914 m= 3000 ft.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetMaxStrafeAlt(maxalt)
|
||||
self.strafemaxalt=maxalt or RANGE.Defaults.strafemaxalt
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set time interval for tracking bombs. A smaller time step increases accuracy but needs more CPU time.
|
||||
-- @param #RANGE self
|
||||
-- @param #number dt Time interval in seconds. Default is 0.005 s.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetBombtrackTimestep(dt)
|
||||
self.dtBombtrack=dt or RANGE.Defaults.dtBombtrack
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set time how long (most) messages are displayed.
|
||||
-- @param #RANGE self
|
||||
-- @param #number time Time in seconds. Default is 30 s.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetMessageTimeDuration(time)
|
||||
self.Tmsg=time or RANGE.Defaults.Tmsg
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set messages to examiner. The examiner will receive messages from all clients.
|
||||
-- @param #RANGE self
|
||||
-- @param #string examinergroupname Name of the group of the examiner.
|
||||
-- @param #boolean exclusively If true, messages are send exclusively to the examiner, i.e. not to the clients.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetMessageToExaminer(examinergroupname, exclusively)
|
||||
self.examinergroupname=examinergroupname
|
||||
self.examinerexclusive=exclusively
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set max number of player results that are displayed.
|
||||
-- @param #RANGE self
|
||||
-- @param #number nmax Number of results. Default is 10.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetDisplayedMaxPlayerResults(nmax)
|
||||
self.ndisplayresult=nmax or RANGE.Defaults.ndisplayresult
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set range radius. Defines the area in which e.g. bomb impacts are smoked.
|
||||
-- @param #RANGE self
|
||||
-- @param #number radius Radius in km. Default 5 km.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetRangeRadius(radius)
|
||||
self.rangeradius=radius*1000 or RANGE.Defaults.rangeradius
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set player setting whether bomb impact points are smoked or not
|
||||
-- @param #RANGE self
|
||||
-- @param #boolean If true nor nil default is to smoke impact points of bombs.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetDefaultPlayerSmokeBomb(switch)
|
||||
if switch==true or switch==nil then
|
||||
self.defaultsmokebomb=true
|
||||
else
|
||||
self.defaultsmokebomb=false
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set bomb track threshold distance. Bombs/rockets/missiles are only tracked if player-range distance is less than this distance. Default 25 km.
|
||||
-- @param #RANGE self
|
||||
-- @param #number distance Threshold distance in km. Default 25 km.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetBombtrackThreshold(distance)
|
||||
self.BombtrackThreshold=distance*1000 or 25*1000
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set range location. If this is not done, one (random) unit position of the range is used to determine the center of the range.
|
||||
--- Set range location. If this is not done, one (random) unit position of the range is used to determine the location of the range.
|
||||
-- The range location determines the position at which the weather data is evaluated.
|
||||
-- @param #RANGE self
|
||||
-- @param Core.Point#COORDINATE coordinate Coordinate of the center of the range.
|
||||
-- @param Core.Point#COORDINATE coordinate Coordinate of the range.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetRangeLocation(coordinate)
|
||||
self.location=coordinate
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set range zone. For example, no bomb impact points are smoked if a bomb falls outside of this zone.
|
||||
-- If a zone is not explicitly specified, the range zone is determined by its location and radius.
|
||||
-- @param #RANGE self
|
||||
-- @param Core.Zone#ZONE zone MOOSE zone defining the range perimeters.
|
||||
function RANGE:SetRangeLocation(zone)
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetRangeZone(zone)
|
||||
self.rangezone=zone
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set smoke color for marking bomb targets. By default bomb targets are marked by red smoke.
|
||||
-- @param #RANGE self
|
||||
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Red.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetBombTargetSmokeColor(colorid)
|
||||
self.BombSmokeColor=colorid or SMOKECOLOR.Red
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set smoke color for marking strafe targets. By default strafe targets are marked by green smoke.
|
||||
-- @param #RANGE self
|
||||
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.Green.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetStrafeTargetSmokeColor(colorid)
|
||||
self.StrafeSmokeColor=colorid or SMOKECOLOR.Green
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set smoke color for marking strafe pit approach boxes. By default strafe pit boxes are marked by white smoke.
|
||||
-- @param #RANGE self
|
||||
-- @param Utilities.Utils#SMOKECOLOR colorid Color id. Default SMOKECOLOR.White.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetStrafePitSmokeColor(colorid)
|
||||
self.StrafePitSmokeColor=colorid or SMOKECOLOR.White
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set time delay between bomb impact and starting to smoke the impact point.
|
||||
-- @param #RANGE self
|
||||
-- @param #number delay Time delay in seconds. Default is 3 seconds.
|
||||
-- @return #RANGE self
|
||||
function RANGE:SetSmokeTimeDelay(delay)
|
||||
self.TdelaySmoke=delay or RANGE.Defaults.TdelaySmoke
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enable debug modus.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:DebugON()
|
||||
self.Debug=true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Disable debug modus.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:DebugOFF()
|
||||
self.Debug=false
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enables tracking of all bomb types. Note that this is the default setting.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:TrackBombsON()
|
||||
self.trackbombs=true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Disables tracking of all bomb types.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:TrackBombsOFF()
|
||||
self.trackbombs=false
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enables tracking of all rocket types. Note that this is the default setting.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:TrackRocketsON()
|
||||
self.trackrockets=true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Disables tracking of all rocket types.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:TrackRocketsOFF()
|
||||
self.trackrockets=false
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enables tracking of all missile types. Note that this is the default setting.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:TrackMissilesON()
|
||||
self.trackmissiles=true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Disables tracking of all missile types.
|
||||
-- @param #RANGE self
|
||||
-- @return #RANGE self
|
||||
function RANGE:TrackMissilesOFF()
|
||||
self.trackmissiles=false
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -563,6 +639,7 @@ end
|
||||
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false.
|
||||
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
||||
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
||||
-- @return #RANGE self
|
||||
function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
||||
self:F({targetnames=targetnames, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline})
|
||||
|
||||
@@ -680,6 +757,8 @@ function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inversehe
|
||||
local text=string.format("Adding new strafe target %s with %d targets: heading = %03d, box_L = %.1f, box_W = %.1f, goodpass = %d, foul line = %.1f", _name, ntargets, heading, l, w, goodpass, foulline)
|
||||
self:T(RANGE.id..text)
|
||||
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@@ -695,6 +774,7 @@ end
|
||||
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false.
|
||||
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
||||
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
||||
-- @return #RANGE self
|
||||
function RANGE:AddStrafePitGroup(group, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
||||
self:F({group=group, boxlength=boxlength, boxwidth=boxwidth, heading=heading, inverseheading=inverseheading, goodpass=goodpass, foulline=foulline})
|
||||
|
||||
@@ -720,6 +800,7 @@ function RANGE:AddStrafePitGroup(group, boxlength, boxwidth, heading, inversehea
|
||||
self:AddStrafePit(_names, boxlength, boxwidth, heading, inverseheading, goodpass, foulline)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add bombing target(s) to range.
|
||||
@@ -727,6 +808,7 @@ end
|
||||
-- @param #table targetnames Table containing names of unit or static objects serving as bomb targets.
|
||||
-- @param #number goodhitrange (Optional) Max distance from target unit (in meters) which is considered as a good hit. Default is 25 m.
|
||||
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||
-- @return #RANGE self
|
||||
function RANGE:AddBombingTargets(targetnames, goodhitrange, randommove)
|
||||
self:F({targetnames=targetnames, goodhitrange=goodhitrange, randommove=randommove})
|
||||
|
||||
@@ -756,6 +838,8 @@ function RANGE:AddBombingTargets(targetnames, goodhitrange, randommove)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a unit or static object as bombing target.
|
||||
@@ -763,6 +847,7 @@ end
|
||||
-- @param Wrapper.Positionable#POSITIONABLE unit Positionable (unit or static) of the strafe target.
|
||||
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
||||
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||
-- @return #RANGE self
|
||||
function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove)
|
||||
self:F({unit=unit, goodhitrange=goodhitrange, randommove=randommove})
|
||||
|
||||
@@ -797,6 +882,8 @@ function RANGE:AddBombingTargetUnit(unit, goodhitrange, randommove)
|
||||
|
||||
-- Insert target to table.
|
||||
table.insert(self.bombingTargets, {name=name, target=unit, goodhitrange=goodhitrange, move=randommove, speed=speed})
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add all units of a group as bombing targets.
|
||||
@@ -804,6 +891,7 @@ end
|
||||
-- @param Wrapper.Group#GROUP group Group of bombing targets.
|
||||
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
||||
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||
-- @return #RANGE self
|
||||
function RANGE:AddBombingTargetGroup(group, goodhitrange, randommove)
|
||||
self:F({group=group, goodhitrange=goodhitrange, randommove=randommove})
|
||||
|
||||
@@ -818,6 +906,7 @@ function RANGE:AddBombingTargetGroup(group, goodhitrange, randommove)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Measures the foule line distance between two unit or static objects.
|
||||
@@ -970,11 +1059,12 @@ function RANGE:OnEventBirth(EventData)
|
||||
|
||||
-- By default, some bomb impact points and do not flare each hit on target.
|
||||
self.PlayerSettings[_playername]={}
|
||||
self.PlayerSettings[_playername].smokebombimpact=true
|
||||
self.PlayerSettings[_playername].smokebombimpact=self.defaultsmokebomb
|
||||
self.PlayerSettings[_playername].flaredirecthits=false
|
||||
self.PlayerSettings[_playername].smokecolor=SMOKECOLOR.Blue
|
||||
self.PlayerSettings[_playername].flarecolor=FLARECOLOR.Red
|
||||
self.PlayerSettings[_playername].delaysmoke=true
|
||||
self.PlayerSettings[_playername].messages=true
|
||||
|
||||
-- Start check in zone timer.
|
||||
if self.planes[_uid] ~= true then
|
||||
@@ -1041,7 +1131,7 @@ function RANGE:OnEventHit(EventData)
|
||||
if _currentTarget.pastfoulline==false and _unit and _playername then
|
||||
local _d=_currentTarget.zone.foulline
|
||||
local text=string.format("%s, Invalid hit!\nYou already passed foul line distance of %d m for target %s.", self:_myname(_unitName), _d, targetname)
|
||||
self:_DisplayMessageToGroup(_unit, text, 10)
|
||||
self:_DisplayMessageToGroup(_unit, text)
|
||||
self:T2(RANGE.id..text)
|
||||
_currentTarget.pastfoulline=true
|
||||
end
|
||||
@@ -1163,11 +1253,19 @@ function RANGE:OnEventShot(EventData)
|
||||
-- Coordinate of impact point.
|
||||
local impactcoord=COORDINATE:NewFromVec3(_lastBombPos)
|
||||
|
||||
-- Check if impact happend in range zone.
|
||||
local insidezone=self.rangezone:IsCoordinateInZone(impactcoord)
|
||||
|
||||
-- Distance from range. We dont want to smoke targets outside of the range.
|
||||
local impactdist=impactcoord:Get2DDistance(self.location)
|
||||
|
||||
-- Impact point of bomb.
|
||||
if self.Debug then
|
||||
impactcoord:MarkToAll("Bomb impact point")
|
||||
end
|
||||
|
||||
-- Smoke impact point of bomb.
|
||||
if self.PlayerSettings[_playername].smokebombimpact and impactdist<self.rangeradius then
|
||||
if self.PlayerSettings[_playername].smokebombimpact and insidezone then
|
||||
if self.PlayerSettings[_playername].delaysmoke then
|
||||
timer.scheduleFunction(self._DelayedSmoke, {coord=impactcoord, color=self.PlayerSettings[_playername].smokecolor}, timer.getTime() + self.TdelaySmoke)
|
||||
else
|
||||
@@ -1184,6 +1282,8 @@ function RANGE:OnEventShot(EventData)
|
||||
|
||||
-- Distance between bomb and target.
|
||||
local _temp = impactcoord:Get2DDistance(_target:GetCoordinate())
|
||||
|
||||
--env.info(string.format("FF target = %s dist = %d m", _target:GetName(), _temp))
|
||||
|
||||
-- Find closest target to last known position of the bomb.
|
||||
if _distance == nil or _temp < _distance then
|
||||
@@ -1203,7 +1303,7 @@ function RANGE:OnEventShot(EventData)
|
||||
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 <= self.scorebombdistance then
|
||||
|
||||
-- Init bomb player results.
|
||||
@@ -1222,10 +1322,10 @@ function RANGE:OnEventShot(EventData)
|
||||
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
||||
elseif _distance <= self.rangeradius then
|
||||
elseif insidezone then
|
||||
-- Send message
|
||||
local _message=string.format("%s, weapon fell more than %.1f km away from nearest range target. No score!", _callsign, self.scorebombdistance/1000)
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, false)
|
||||
end
|
||||
|
||||
--Terminate the timer
|
||||
@@ -1309,7 +1409,7 @@ function RANGE:_DisplayMyStrafePitResults(_unitName)
|
||||
end
|
||||
|
||||
-- Send message to group.
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1365,7 +1465,7 @@ function RANGE:_DisplayStrafePitResults(_unitName)
|
||||
end
|
||||
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1422,7 +1522,7 @@ function RANGE:_DisplayMyBombingResults(_unitName)
|
||||
end
|
||||
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1478,7 +1578,7 @@ function RANGE:_DisplayBombingResults(_unitName)
|
||||
end
|
||||
|
||||
-- Send message.
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true)
|
||||
self:_DisplayMessageToGroup(_unit, _message, nil, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1555,7 +1655,7 @@ function RANGE:_DisplayRangeInfo(_unitname)
|
||||
text=text..textdelay
|
||||
|
||||
-- Send message to player group.
|
||||
self:_DisplayMessageToGroup(unit, text, nil, true)
|
||||
self:_DisplayMessageToGroup(unit, text, nil, true, true)
|
||||
|
||||
-- Debug output.
|
||||
self:T2(RANGE.id..text)
|
||||
@@ -1592,7 +1692,7 @@ function RANGE:_DisplayBombTargets(_unitname)
|
||||
end
|
||||
end
|
||||
|
||||
self:_DisplayMessageToGroup(_unit,_text, nil, true)
|
||||
self:_DisplayMessageToGroup(_unit,_text, nil, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1632,7 +1732,7 @@ function RANGE:_DisplayStrafePits(_unitname)
|
||||
_text=_text..string.format("\n- %s: %s - heading %03d",_strafepit.name, mycoord, heading)
|
||||
end
|
||||
|
||||
self:_DisplayMessageToGroup(_unit,_text, nil, true)
|
||||
self:_DisplayMessageToGroup(_unit,_text, nil, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1694,7 +1794,7 @@ function RANGE:_DisplayRangeWeather(_unitname)
|
||||
end
|
||||
|
||||
-- Send message to player group.
|
||||
self:_DisplayMessageToGroup(unit, text, nil, true)
|
||||
self:_DisplayMessageToGroup(unit, text, nil, true, true)
|
||||
|
||||
-- Debug output.
|
||||
self:T2(RANGE.id..text)
|
||||
@@ -1738,7 +1838,7 @@ function RANGE:_CheckInZone(_unitName)
|
||||
local unitinzone=_unit:IsInZone(zone) and unitalt <= self.strafemaxalt and towardspit
|
||||
|
||||
-- Debug output
|
||||
local text=string.format("Checking stil in zone. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _unitName, _playername, tostring(unitinzone), unitalt, deltaheading)
|
||||
local text=string.format("Checking still in zone. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _unitName, _playername, tostring(unitinzone), unitalt, deltaheading)
|
||||
self:T2(RANGE.id..text)
|
||||
|
||||
-- Check if player is in strafe zone and below max alt.
|
||||
@@ -1883,12 +1983,33 @@ function RANGE:_AddF10Commands(_unitName)
|
||||
|
||||
-- Enable switch so we don't do this twice.
|
||||
self.MenuAddedTo[_gid] = true
|
||||
|
||||
-- Main F10 menu: F10/On the Range/<Range Name>/
|
||||
if RANGE.MenuF10[_gid] == nil then
|
||||
RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range")
|
||||
end
|
||||
local _rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10[_gid])
|
||||
|
||||
-- Range root menu path.
|
||||
local _rangePath=nil
|
||||
|
||||
if RANGE.MenuF10Root then
|
||||
|
||||
-------------------
|
||||
-- MISSION LEVEL --
|
||||
-------------------
|
||||
|
||||
_rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10Root)
|
||||
|
||||
else
|
||||
|
||||
-----------------
|
||||
-- GROUP LEVEL --
|
||||
-----------------
|
||||
|
||||
-- Main F10 menu: F10/On the Range/<Range Name>/
|
||||
if RANGE.MenuF10[_gid] == nil then
|
||||
RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range")
|
||||
end
|
||||
_rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10[_gid])
|
||||
|
||||
end
|
||||
|
||||
|
||||
local _statsPath = missionCommands.addSubMenuForGroup(_gid, "Statistics", _rangePath)
|
||||
local _markPath = missionCommands.addSubMenuForGroup(_gid, "Mark Targets", _rangePath)
|
||||
local _settingsPath = missionCommands.addSubMenuForGroup(_gid, "My Settings", _rangePath)
|
||||
@@ -1921,9 +2042,11 @@ function RANGE:_AddF10Commands(_unitName)
|
||||
missionCommands.addCommandForGroup(_gid, "White Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.White)
|
||||
missionCommands.addCommandForGroup(_gid, "Yellow Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Yellow)
|
||||
-- F10/On the Range/<Range Name>/My Settings/
|
||||
missionCommands.addCommandForGroup(_gid, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName)
|
||||
missionCommands.addCommandForGroup(_gid, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName)
|
||||
missionCommands.addCommandForGroup(_gid, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName)
|
||||
missionCommands.addCommandForGroup(_gid, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName)
|
||||
missionCommands.addCommandForGroup(_gid, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName)
|
||||
missionCommands.addCommandForGroup(_gid, "All Messages On/Off", _settingsPath, self._MessagesToPlayerOnOff, self, _unitName)
|
||||
|
||||
-- F10/On the Range/<Range Name>/Range Information
|
||||
missionCommands.addCommandForGroup(_gid, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName)
|
||||
missionCommands.addCommandForGroup(_gid, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName)
|
||||
@@ -2103,7 +2226,7 @@ function RANGE:_ResetRangeStats(_unitName)
|
||||
self.strafePlayerResults[_playername] = nil
|
||||
self.bombPlayerResults[_playername] = nil
|
||||
local text=string.format("%s, %s, your range stats were cleared.", self.rangename, _playername)
|
||||
self:DisplayMessageToGroup(_unit, text, 5)
|
||||
self:DisplayMessageToGroup(_unit, text, 5, false, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2113,33 +2236,35 @@ end
|
||||
-- @param #string _text Message text.
|
||||
-- @param #number _time Duration how long the message is displayed.
|
||||
-- @param #boolean _clear Clear up old messages.
|
||||
function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear)
|
||||
-- @param #boolean display If true, display message regardless of player setting "Messages Off".
|
||||
function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear, display)
|
||||
self:F({unit=_unit, text=_text, time=_time, clear=_clear})
|
||||
|
||||
-- Defaults
|
||||
_time=_time or self.Tmsg
|
||||
if _clear==nil then
|
||||
if _clear==nil or _clear==false then
|
||||
_clear=false
|
||||
else
|
||||
_clear=true
|
||||
end
|
||||
|
||||
-- Group ID.
|
||||
local _gid=_unit:GetGroup():GetID()
|
||||
|
||||
if _gid and not self.examinerexclusive then
|
||||
if _clear == true then
|
||||
trigger.action.outTextForGroup(_gid, _text, _time, _clear)
|
||||
else
|
||||
trigger.action.outTextForGroup(_gid, _text, _time)
|
||||
end
|
||||
-- Get playername and player settings
|
||||
local _, playername=self:_GetPlayerUnitAndName(_unit:GetName())
|
||||
local playermessage=self.PlayerSettings[playername].messages
|
||||
|
||||
-- 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
|
||||
trigger.action.outTextForGroup(_gid, _text, _time, _clear)
|
||||
end
|
||||
|
||||
-- Send message to examiner.
|
||||
if self.examinergroupname~=nil then
|
||||
local _examinerid=GROUP:FindByName(self.examinergroupname):GetID()
|
||||
if _examinerid then
|
||||
if _clear == true then
|
||||
trigger.action.outTextForGroup(_examinerid, _text, _time, _clear)
|
||||
else
|
||||
trigger.action.outTextForGroup(_examinerid, _text, _time)
|
||||
end
|
||||
trigger.action.outTextForGroup(_examinerid, _text, _time, _clear)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2161,7 +2286,7 @@ function RANGE:_SmokeBombImpactOnOff(unitname)
|
||||
self.PlayerSettigs[playername].smokebombimpact=true
|
||||
text=string.format("%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername)
|
||||
end
|
||||
self:_DisplayMessageToGroup(unit, text, 5)
|
||||
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -2182,7 +2307,27 @@ function RANGE:_SmokeBombDelayOnOff(unitname)
|
||||
self.PlayerSettigs[playername].delaysmoke=true
|
||||
text=string.format("%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername)
|
||||
end
|
||||
self:_DisplayMessageToGroup(unit, text, 5)
|
||||
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Toggle display messages to player.
|
||||
-- @param #RANGE self
|
||||
-- @param #string unitname Name of the player unit.
|
||||
function RANGE:_MessagesToPlayerOnOff(unitname)
|
||||
self:F(unitname)
|
||||
|
||||
local unit, playername = self:_GetPlayerUnitAndName(unitname)
|
||||
if unit and playername then
|
||||
local text
|
||||
if self.PlayerSettings[playername].messages==true then
|
||||
text=string.format("%s, %s, display of ALL messages is now OFF.", self.rangename, playername)
|
||||
else
|
||||
text=string.format("%s, %s, display of ALL messages is now ON.", self.rangename, playername)
|
||||
end
|
||||
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||
self.PlayerSettings[playername].messages=not self.PlayerSettings[playername].messages
|
||||
end
|
||||
|
||||
end
|
||||
@@ -2203,7 +2348,7 @@ function RANGE:_FlareDirectHitsOnOff(unitname)
|
||||
self.PlayerSettings[playername].flaredirecthits=true
|
||||
text=string.format("%s, %s, flaring direct hits is now ON.", self.rangename, playername)
|
||||
end
|
||||
self:_DisplayMessageToGroup(unit, text, 5)
|
||||
self:_DisplayMessageToGroup(unit, text, 5, false, true)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -2321,7 +2466,7 @@ function RANGE:_smokecolor2text(color)
|
||||
elseif color==SMOKECOLOR.White then
|
||||
txt="white"
|
||||
else
|
||||
txt=string.format("unkown color (%s)", tostring(color))
|
||||
txt=string.format("unknown color (%s)", tostring(color))
|
||||
end
|
||||
|
||||
return txt
|
||||
@@ -2344,7 +2489,7 @@ function RANGE:_flarecolor2text(color)
|
||||
elseif color==FLARECOLOR.Yellow then
|
||||
txt="yellow"
|
||||
else
|
||||
txt=string.format("unkown color (%s)", tostring(color))
|
||||
txt=string.format("unknown color (%s)", tostring(color))
|
||||
end
|
||||
|
||||
return txt
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user