mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8af3f89c14 | ||
|
|
fe3079caad | ||
|
|
61ac6b4131 | ||
|
|
36cb189512 | ||
|
|
15f9843878 | ||
|
|
67f847dd16 | ||
|
|
8b9143d3f1 | ||
|
|
0388d47f23 | ||
|
|
de9b173d9b | ||
|
|
2cecc526fb | ||
|
|
968d178317 | ||
|
|
3c477b872a | ||
|
|
77e6088114 | ||
|
|
edd6594953 | ||
|
|
f8c05c99d0 | ||
|
|
50f6d98b49 | ||
|
|
147eeb05f6 | ||
|
|
d8cb15a577 | ||
|
|
0daac876ea | ||
|
|
1832125022 | ||
|
|
c311c40b72 | ||
|
|
db516a2077 | ||
|
|
ff8766669c | ||
|
|
06dc9a732e | ||
|
|
50c74d0852 | ||
|
|
1c97eb6f3c | ||
|
|
69449430d1 | ||
|
|
663cd34aa3 | ||
|
|
cfed6f5153 | ||
|
|
2b22d5288c | ||
|
|
a64424ecc8 | ||
|
|
fd1b2ecb86 | ||
|
|
6cae3e62cf | ||
|
|
05ce7e4513 | ||
|
|
136bd19f19 | ||
|
|
8873504daf | ||
|
|
a844a5d697 | ||
|
|
a49f4eaa21 | ||
|
|
e6e2651f8c | ||
|
|
b93ba13644 | ||
|
|
e4a51951b0 | ||
|
|
ad56e39942 | ||
|
|
ea09dc5a6e | ||
|
|
8ecfd913a3 | ||
|
|
53367c786e | ||
|
|
db5797bb4e | ||
|
|
5e8fe97752 | ||
|
|
393fa0bfbb | ||
|
|
4f51884b9d | ||
|
|
4c5c320073 | ||
|
|
9098590568 | ||
|
|
555bb7e68b | ||
|
|
c0a18957f0 | ||
|
|
2cf939560e | ||
|
|
9d3a7aae78 | ||
|
|
f6ed592f92 | ||
|
|
c98757d13c | ||
|
|
17378f509e | ||
|
|
7f18ea0e7a | ||
|
|
5172619cb1 | ||
|
|
3962529698 | ||
|
|
6481d5d41e |
@@ -136,7 +136,7 @@ function DATABASE:New()
|
|||||||
self:_RegisterGroupsAndUnits()
|
self:_RegisterGroupsAndUnits()
|
||||||
self:_RegisterClients()
|
self:_RegisterClients()
|
||||||
self:_RegisterStatics()
|
self:_RegisterStatics()
|
||||||
self:_RegisterAirbases()
|
--self:_RegisterAirbases()
|
||||||
--self:_RegisterPlayers()
|
--self:_RegisterPlayers()
|
||||||
|
|
||||||
self.UNITS_Position = 0
|
self.UNITS_Position = 0
|
||||||
|
|||||||
@@ -3998,7 +3998,25 @@ do -- SET_CLIENT
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Iterate the SET_CLIENT and count alive units.
|
||||||
|
-- @param #SET_CLIENT self
|
||||||
|
-- @return #number count
|
||||||
|
function SET_CLIENT:CountAlive()
|
||||||
|
|
||||||
|
local Set = self:GetSet()
|
||||||
|
|
||||||
|
local CountU = 0
|
||||||
|
for UnitID, UnitData in pairs(Set) do -- For each GROUP in SET_GROUP
|
||||||
|
if UnitData and UnitData:IsAlive() then
|
||||||
|
CountU = CountU + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return CountU
|
||||||
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @param Wrapper.Client#CLIENT MClient
|
-- @param Wrapper.Client#CLIENT MClient
|
||||||
@@ -4746,7 +4764,7 @@ do -- SET_AIRBASE
|
|||||||
|
|
||||||
local airbaseName, airbase=self:FindInDatabase(EventData)
|
local airbaseName, airbase=self:FindInDatabase(EventData)
|
||||||
|
|
||||||
if airbase and airbase:IsShip() or airbase:IsHelipad() then
|
if airbase and (airbase:IsShip() or airbase:IsHelipad()) then
|
||||||
self:RemoveAirbasesByName(airbaseName)
|
self:RemoveAirbasesByName(airbaseName)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -138,24 +138,24 @@ SPAWNSTATIC = {
|
|||||||
-- @return #SPAWNSTATIC self
|
-- @return #SPAWNSTATIC self
|
||||||
function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
|
|
||||||
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate(SpawnTemplateName)
|
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate(SpawnTemplateName)
|
||||||
|
|
||||||
if TemplateStatic then
|
if TemplateStatic then
|
||||||
self.SpawnTemplatePrefix = SpawnTemplateName
|
self.SpawnTemplatePrefix = SpawnTemplateName
|
||||||
self.TemplateStaticUnit = UTILS.DeepCopy(TemplateStatic.units[1])
|
self.TemplateStaticUnit = UTILS.DeepCopy(TemplateStatic.units[1])
|
||||||
self.CountryID = SpawnCountryID or CountryID
|
self.CountryID = SpawnCountryID or CountryID
|
||||||
self.CategoryID = CategoryID
|
self.CategoryID = CategoryID
|
||||||
self.CoalitionID = CoalitionID
|
self.CoalitionID = CoalitionID
|
||||||
self.SpawnIndex = 0
|
self.SpawnIndex = 0
|
||||||
else
|
else
|
||||||
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
||||||
end
|
end
|
||||||
|
|
||||||
self:SetEventPriority( 5 )
|
self:SetEventPriority( 5 )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates the main object to spawn a @{Static} given a template table.
|
--- Creates the main object to spawn a @{Static} given a template table.
|
||||||
@@ -422,7 +422,11 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if self.InitCargo~=nil then
|
if self.InitCargo~=nil then
|
||||||
Template.isCargo=self.InitCargo
|
Template.canCargo=self.InitCargo
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitCargoMass~=nil then
|
||||||
|
Template.mass=self.InitCargoMass
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitLinkUnit then
|
if self.InitLinkUnit then
|
||||||
|
|||||||
@@ -183,12 +183,12 @@ function ZONE_BASE:IsCoordinateInZone( Coordinate )
|
|||||||
return InZone
|
return InZone
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns if a PointVec2 is within the zone.
|
--- Returns if a PointVec2 is within the zone. (Name is misleading, actually takes a #COORDINATE)
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 to test.
|
-- @param Core.Point#COORDINATE PointVec2 The coordinate to test.
|
||||||
-- @return #boolean true if the PointVec2 is within the zone.
|
-- @return #boolean true if the PointVec2 is within the zone.
|
||||||
function ZONE_BASE:IsPointVec2InZone( PointVec2 )
|
function ZONE_BASE:IsPointVec2InZone( Coordinate )
|
||||||
local InZone = self:IsVec2InZone( PointVec2:GetVec2() )
|
local InZone = self:IsVec2InZone( Coordinate:GetVec2() )
|
||||||
return InZone
|
return InZone
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -498,8 +498,8 @@ end
|
|||||||
--
|
--
|
||||||
-- @field #ZONE_RADIUS
|
-- @field #ZONE_RADIUS
|
||||||
ZONE_RADIUS = {
|
ZONE_RADIUS = {
|
||||||
ClassName="ZONE_RADIUS",
|
ClassName="ZONE_RADIUS",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Constructor of @{#ZONE_RADIUS}, taking the zone name, the zone location and a radius.
|
--- Constructor of @{#ZONE_RADIUS}, taking the zone name, the zone location and a radius.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
@@ -510,15 +510,15 @@ ZONE_RADIUS = {
|
|||||||
function ZONE_RADIUS:New( ZoneName, Vec2, Radius )
|
function ZONE_RADIUS:New( ZoneName, Vec2, Radius )
|
||||||
|
|
||||||
-- Inherit ZONE_BASE.
|
-- Inherit ZONE_BASE.
|
||||||
local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) -- #ZONE_RADIUS
|
local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) ) -- #ZONE_RADIUS
|
||||||
self:F( { ZoneName, Vec2, Radius } )
|
self:F( { ZoneName, Vec2, Radius } )
|
||||||
|
|
||||||
self.Radius = Radius
|
self.Radius = Radius
|
||||||
self.Vec2 = Vec2
|
self.Vec2 = Vec2
|
||||||
|
|
||||||
--self.Coordinate=COORDINATE:NewFromVec2(Vec2)
|
--self.Coordinate=COORDINATE:NewFromVec2(Vec2)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Update zone from a 2D vector.
|
--- Update zone from a 2D vector.
|
||||||
@@ -746,11 +746,11 @@ end
|
|||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @return DCS#Vec2 The location of the zone.
|
-- @return DCS#Vec2 The location of the zone.
|
||||||
function ZONE_RADIUS:GetVec2()
|
function ZONE_RADIUS:GetVec2()
|
||||||
self:F2( self.ZoneName )
|
self:F2( self.ZoneName )
|
||||||
|
|
||||||
self:T2( { self.Vec2 } )
|
self:T2( { self.Vec2 } )
|
||||||
|
|
||||||
return self.Vec2
|
return self.Vec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets the @{DCS#Vec2} of the zone.
|
--- Sets the @{DCS#Vec2} of the zone.
|
||||||
@@ -1165,20 +1165,20 @@ end
|
|||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
-- @return DCS#Vec2 The random location within the zone.
|
-- @return DCS#Vec2 The random location within the zone.
|
||||||
function ZONE_RADIUS:GetRandomVec2( inner, outer )
|
function ZONE_RADIUS:GetRandomVec2( inner, outer )
|
||||||
self:F( self.ZoneName, inner, outer )
|
self:F( self.ZoneName, inner, outer )
|
||||||
|
|
||||||
local Point = {}
|
local Point = {}
|
||||||
local Vec2 = self:GetVec2()
|
local Vec2 = self:GetVec2()
|
||||||
local _inner = inner or 0
|
local _inner = inner or 0
|
||||||
local _outer = outer or self:GetRadius()
|
local _outer = outer or self:GetRadius()
|
||||||
|
|
||||||
local angle = math.random() * math.pi * 2;
|
local angle = math.random() * math.pi * 2;
|
||||||
Point.x = Vec2.x + math.cos( angle ) * math.random(_inner, _outer);
|
Point.x = Vec2.x + math.cos( angle ) * math.random(_inner, _outer);
|
||||||
Point.y = Vec2.y + math.sin( angle ) * math.random(_inner, _outer);
|
Point.y = Vec2.y + math.sin( angle ) * math.random(_inner, _outer);
|
||||||
|
|
||||||
self:T( { Point } )
|
self:T( { Point } )
|
||||||
|
|
||||||
return Point
|
return Point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
||||||
|
|||||||
@@ -23,9 +23,9 @@
|
|||||||
-- Date: July 2021
|
-- Date: July 2021
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **MANTIS** class, extends #Core.Base#BASE
|
--- **MANTIS** class, extends Core.Base#BASE
|
||||||
-- @type MANTIS
|
-- @type MANTIS
|
||||||
-- @field #string Classname
|
-- @field #string ClassName
|
||||||
-- @field #string name Name of this Mantis
|
-- @field #string name Name of this Mantis
|
||||||
-- @field #string SAM_Templates_Prefix Prefix to build the #SET_GROUP for SAM sites
|
-- @field #string SAM_Templates_Prefix Prefix to build the #SET_GROUP for SAM sites
|
||||||
-- @field Core.Set#SET_GROUP SAM_Group The SAM #SET_GROUP
|
-- @field Core.Set#SET_GROUP SAM_Group The SAM #SET_GROUP
|
||||||
@@ -195,6 +195,9 @@ MANTIS = {
|
|||||||
TimeStamp = 0,
|
TimeStamp = 0,
|
||||||
state2flag = false,
|
state2flag = false,
|
||||||
SamStateTracker = {},
|
SamStateTracker = {},
|
||||||
|
DLink = false,
|
||||||
|
DLTimeStamp = 0,
|
||||||
|
Padding = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Advanced state enumerator
|
--- Advanced state enumerator
|
||||||
@@ -219,7 +222,8 @@ do
|
|||||||
--@param #string coaltion Coalition side of your setup, e.g. "blue", "red" or "neutral"
|
--@param #string coaltion Coalition side of your setup, e.g. "blue", "red" or "neutral"
|
||||||
--@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional)
|
--@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional)
|
||||||
--@param #string awacs Group name of your Awacs (optional)
|
--@param #string awacs Group name of your Awacs (optional)
|
||||||
--@param #boolean EmOnOff Make MANTIS switch Emissions on and off instead of changing the alarm state between RED and GREEN
|
--@param #boolean EmOnOff Make MANTIS switch Emissions on and off instead of changing the alarm state between RED and GREEN (optional)
|
||||||
|
--@param #number Padding For #SEAD - Extra number of seconds to add to radar switch-back-on time (optional)
|
||||||
--@return #MANTIS self
|
--@return #MANTIS self
|
||||||
--@usage Start up your MANTIS with a basic setting
|
--@usage Start up your MANTIS with a basic setting
|
||||||
--
|
--
|
||||||
@@ -241,7 +245,7 @@ do
|
|||||||
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
||||||
-- `mybluemantis:Start()`
|
-- `mybluemantis:Start()`
|
||||||
--
|
--
|
||||||
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, EmOnOff)
|
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, EmOnOff, Padding)
|
||||||
|
|
||||||
-- DONE: Create some user functions for these
|
-- DONE: Create some user functions for these
|
||||||
-- DONE: Make HQ useful
|
-- DONE: Make HQ useful
|
||||||
@@ -278,7 +282,9 @@ do
|
|||||||
self.relointerval = math.random(1800,3600) -- random between 30 and 60 mins
|
self.relointerval = math.random(1800,3600) -- random between 30 and 60 mins
|
||||||
self.state2flag = false
|
self.state2flag = false
|
||||||
self.SamStateTracker = {} -- table to hold alert states, so we don't trigger state changes twice in adv mode
|
self.SamStateTracker = {} -- table to hold alert states, so we don't trigger state changes twice in adv mode
|
||||||
|
self.DLink = false
|
||||||
|
self.Padding = Padding or 10
|
||||||
|
|
||||||
if EmOnOff then
|
if EmOnOff then
|
||||||
if EmOnOff == false then
|
if EmOnOff == false then
|
||||||
self.UseEmOnOff = false
|
self.UseEmOnOff = false
|
||||||
@@ -325,7 +331,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
self.version="0.5.2"
|
self.version="0.6.2"
|
||||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||||
|
|
||||||
--- FSM Functions ---
|
--- FSM Functions ---
|
||||||
@@ -593,7 +599,7 @@ do
|
|||||||
-- E.g. `mymantis:SetAdvancedMode(true, 90)`
|
-- E.g. `mymantis:SetAdvancedMode(true, 90)`
|
||||||
function MANTIS:SetAdvancedMode(onoff, ratio)
|
function MANTIS:SetAdvancedMode(onoff, ratio)
|
||||||
self:T(self.lid .. "SetAdvancedMode")
|
self:T(self.lid .. "SetAdvancedMode")
|
||||||
self:T({onoff, ratio})
|
--self:T({onoff, ratio})
|
||||||
local onoff = onoff or false
|
local onoff = onoff or false
|
||||||
local ratio = ratio or 100
|
local ratio = ratio or 100
|
||||||
if (type(self.HQ_Template_CC) == "string") and onoff and self.dynamic then
|
if (type(self.HQ_Template_CC) == "string") and onoff and self.dynamic then
|
||||||
@@ -619,6 +625,17 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set using an #INTEL_DLINK object instead of #DETECTION. Requires Develop branch of Moose.lua.
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param Ops.Intelligence#INTEL_DLINK DLink The data link object to be used.
|
||||||
|
function MANTIS:SetUsingDLink(DLink)
|
||||||
|
self:T(self.lid .. "SetUsingDLink")
|
||||||
|
self.DLink = true
|
||||||
|
self.Detection = DLink
|
||||||
|
self.DLTimeStamp = timer.getAbsTime()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- [Internal] Function to check if HQ is alive
|
--- [Internal] Function to check if HQ is alive
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
-- @return #boolean True if HQ is alive, else false
|
-- @return #boolean True if HQ is alive, else false
|
||||||
@@ -633,10 +650,10 @@ do
|
|||||||
local hqgrp = GROUP:FindByName(hq)
|
local hqgrp = GROUP:FindByName(hq)
|
||||||
if hqgrp then
|
if hqgrp then
|
||||||
if hqgrp:IsAlive() then -- ok we're on, hq exists and as alive
|
if hqgrp:IsAlive() then -- ok we're on, hq exists and as alive
|
||||||
self:T(self.lid.." HQ is alive!")
|
--self:T(self.lid.." HQ is alive!")
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
self:T(self.lid.." HQ is dead!")
|
--self:T(self.lid.." HQ is dead!")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -650,7 +667,7 @@ do
|
|||||||
function MANTIS:_CheckEWRState()
|
function MANTIS:_CheckEWRState()
|
||||||
self:T(self.lid .. "CheckEWRState")
|
self:T(self.lid .. "CheckEWRState")
|
||||||
local text = self.lid.." Checking EWR State"
|
local text = self.lid.." Checking EWR State"
|
||||||
self:T(text)
|
--self:T(text)
|
||||||
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
if self.verbose then self:I(text) end
|
if self.verbose then self:I(text) end
|
||||||
-- start check
|
-- start check
|
||||||
@@ -666,7 +683,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:T(self.lid..string.format(" No of EWR alive is %d", nalive))
|
--self:T(self.lid..string.format(" No of EWR alive is %d", nalive))
|
||||||
if nalive > 0 then
|
if nalive > 0 then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
@@ -682,10 +699,8 @@ do
|
|||||||
-- @return #number Previous state for tracking 0, 1, or 2
|
-- @return #number Previous state for tracking 0, 1, or 2
|
||||||
function MANTIS:_CalcAdvState()
|
function MANTIS:_CalcAdvState()
|
||||||
self:T(self.lid .. "CalcAdvState")
|
self:T(self.lid .. "CalcAdvState")
|
||||||
local text = self.lid.." Calculating Advanced State"
|
local m=MESSAGE:New(self.lid.." Calculating Advanced State",10,"MANTIS"):ToAllIf(self.debug)
|
||||||
self:T(text)
|
if self.verbose then self:I(self.lid.." Calculating Advanced State") end
|
||||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
|
||||||
if self.verbose then self:I(text) end
|
|
||||||
-- start check
|
-- start check
|
||||||
local currstate = self.adv_state -- save curr state for comparison later
|
local currstate = self.adv_state -- save curr state for comparison later
|
||||||
local EWR_State = self:_CheckEWRState()
|
local EWR_State = self:_CheckEWRState()
|
||||||
@@ -703,10 +718,12 @@ do
|
|||||||
local ratio = self.adv_ratio / 100 -- e.g. 80/100 = 0.8
|
local ratio = self.adv_ratio / 100 -- e.g. 80/100 = 0.8
|
||||||
ratio = ratio * self.adv_state -- e.g 0.8*2 = 1.6
|
ratio = ratio * self.adv_state -- e.g 0.8*2 = 1.6
|
||||||
local newinterval = interval + (interval * ratio) -- e.g. 30+(30*1.6) = 78
|
local newinterval = interval + (interval * ratio) -- e.g. 30+(30*1.6) = 78
|
||||||
local text = self.lid..string.format(" Calculated OldState/NewState/Interval: %d / %d / %d", currstate, self.adv_state, newinterval)
|
if self.debug or self.verbose then
|
||||||
self:T(text)
|
local text = self.lid..string.format(" Calculated OldState/NewState/Interval: %d / %d / %d", currstate, self.adv_state, newinterval)
|
||||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
--self:T(text)
|
||||||
if self.verbose then self:I(text) end
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then self:I(text) end
|
||||||
|
end
|
||||||
return newinterval, currstate
|
return newinterval, currstate
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -716,13 +733,13 @@ do
|
|||||||
-- @param #boolean ewr If true, will relocate EWR objects
|
-- @param #boolean ewr If true, will relocate EWR objects
|
||||||
function MANTIS:SetAutoRelocate(hq, ewr)
|
function MANTIS:SetAutoRelocate(hq, ewr)
|
||||||
self:T(self.lid .. "SetAutoRelocate")
|
self:T(self.lid .. "SetAutoRelocate")
|
||||||
self:T({hq, ewr})
|
--self:T({hq, ewr})
|
||||||
local hqrel = hq or false
|
local hqrel = hq or false
|
||||||
local ewrel = ewr or false
|
local ewrel = ewr or false
|
||||||
if hqrel or ewrel then
|
if hqrel or ewrel then
|
||||||
self.autorelocate = true
|
self.autorelocate = true
|
||||||
self.autorelocateunits = { HQ = hqrel, EWR = ewrel }
|
self.autorelocateunits = { HQ = hqrel, EWR = ewrel }
|
||||||
self:T({self.autorelocate, self.autorelocateunits})
|
--self:T({self.autorelocate, self.autorelocateunits})
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -739,7 +756,7 @@ do
|
|||||||
local HQGroup = self.HQ_CC
|
local HQGroup = self.HQ_CC
|
||||||
if self.autorelocateunits.HQ and self.HQ_CC and HQGroup:IsAlive() then --only relocate if HQ exists
|
if self.autorelocateunits.HQ and self.HQ_CC and HQGroup:IsAlive() then --only relocate if HQ exists
|
||||||
local _hqgrp = self.HQ_CC
|
local _hqgrp = self.HQ_CC
|
||||||
self:T(self.lid.." Relocating HQ")
|
--self:T(self.lid.." Relocating HQ")
|
||||||
local text = self.lid.." Relocating HQ"
|
local text = self.lid.." Relocating HQ"
|
||||||
--local m= MESSAGE:New(text,10,"MANTIS"):ToAll()
|
--local m= MESSAGE:New(text,10,"MANTIS"):ToAll()
|
||||||
_hqgrp:RelocateGroundRandomInRadius(20,500,true,true)
|
_hqgrp:RelocateGroundRandomInRadius(20,500,true,true)
|
||||||
@@ -752,7 +769,7 @@ do
|
|||||||
local EWR_Grps = EWR_GRP.Set --table of objects in SET_GROUP
|
local EWR_Grps = EWR_GRP.Set --table of objects in SET_GROUP
|
||||||
for _,_grp in pairs (EWR_Grps) do
|
for _,_grp in pairs (EWR_Grps) do
|
||||||
if _grp:IsAlive() and _grp:IsGround() then
|
if _grp:IsAlive() and _grp:IsGround() then
|
||||||
self:T(self.lid.." Relocating EWR ".._grp:GetName())
|
--self:T(self.lid.." Relocating EWR ".._grp:GetName())
|
||||||
local text = self.lid.." Relocating EWR ".._grp:GetName()
|
local text = self.lid.." Relocating EWR ".._grp:GetName()
|
||||||
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
if self.verbose then self:I(text) end
|
if self.verbose then self:I(text) end
|
||||||
@@ -778,12 +795,14 @@ do
|
|||||||
for _,_coord in pairs (set) do
|
for _,_coord in pairs (set) do
|
||||||
local coord = _coord -- get current coord to check
|
local coord = _coord -- get current coord to check
|
||||||
-- output for cross-check
|
-- output for cross-check
|
||||||
local dectstring = coord:ToStringLLDMS()
|
|
||||||
local samstring = samcoordinate:ToStringLLDMS()
|
|
||||||
local targetdistance = samcoordinate:DistanceFromPointVec2(coord)
|
local targetdistance = samcoordinate:DistanceFromPointVec2(coord)
|
||||||
local text = string.format("Checking SAM at % s - Distance %d m - Target %s", samstring, targetdistance, dectstring)
|
if self.verbose or self.debug then
|
||||||
local m = MESSAGE:New(text,10,"Check"):ToAllIf(self.debug)
|
local dectstring = coord:ToStringLLDMS()
|
||||||
if self.verbose then self:I(self.lid..text) end
|
local samstring = samcoordinate:ToStringLLDMS()
|
||||||
|
local text = string.format("Checking SAM at % s - Distance %d m - Target %s", samstring, targetdistance, dectstring)
|
||||||
|
local m = MESSAGE:New(text,10,"Check"):ToAllIf(self.debug)
|
||||||
|
self:I(self.lid..text)
|
||||||
|
end
|
||||||
-- end output to cross-check
|
-- end output to cross-check
|
||||||
if targetdistance <= radius then
|
if targetdistance <= radius then
|
||||||
return true, targetdistance
|
return true, targetdistance
|
||||||
@@ -888,7 +907,7 @@ do
|
|||||||
end
|
end
|
||||||
self.SAM_Table = SAM_Tbl
|
self.SAM_Table = SAM_Tbl
|
||||||
-- make SAMs evasive
|
-- make SAMs evasive
|
||||||
local mysead = SEAD:New( SEAD_Grps )
|
local mysead = SEAD:New( SEAD_Grps, self.Padding ) -- Functional.Sead#SEAD
|
||||||
mysead:SetEngagementRange(engagerange)
|
mysead:SetEngagementRange(engagerange)
|
||||||
self.mysead = mysead
|
self.mysead = mysead
|
||||||
return self
|
return self
|
||||||
@@ -999,9 +1018,11 @@ do
|
|||||||
self:__ShoradActivated(1,name, radius, ontime)
|
self:__ShoradActivated(1,name, radius, ontime)
|
||||||
end
|
end
|
||||||
-- debug output
|
-- debug output
|
||||||
local text = string.format("SAM %s switched to alarm state RED!", name)
|
if self.debug or self.verbose then
|
||||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
local text = string.format("SAM %s switched to alarm state RED!", name)
|
||||||
if self.verbose then self:I(self.lid..text) end
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then self:I(self.lid..text) end
|
||||||
|
end
|
||||||
end --end alive
|
end --end alive
|
||||||
else
|
else
|
||||||
if samgroup:IsAlive() then
|
if samgroup:IsAlive() then
|
||||||
@@ -1014,9 +1035,11 @@ do
|
|||||||
self:__GreenState(1,samgroup)
|
self:__GreenState(1,samgroup)
|
||||||
self.SamStateTracker[name] = "GREEN"
|
self.SamStateTracker[name] = "GREEN"
|
||||||
end
|
end
|
||||||
local text = string.format("SAM %s switched to alarm state GREEN!", name)
|
if self.debug or self.verbose then
|
||||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
local text = string.format("SAM %s switched to alarm state GREEN!", name)
|
||||||
if self.verbose then self:I(self.lid..text) end
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then self:I(self.lid..text) end
|
||||||
|
end
|
||||||
end --end alive
|
end --end alive
|
||||||
end --end check
|
end --end check
|
||||||
end --for for loop
|
end --for for loop
|
||||||
@@ -1066,6 +1089,20 @@ do
|
|||||||
end -- end newstate vs oldstate
|
end -- end newstate vs oldstate
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [Internal] Check DLink state
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #MANTIS self
|
||||||
|
function MANTIS:_CheckDLinkState()
|
||||||
|
self:T(self.lid .. "_CheckDLinkState")
|
||||||
|
local dlink = self.Detection -- Ops.Intelligence#INTEL_DLINK
|
||||||
|
local TS = timer.getAbsTime()
|
||||||
|
if not dlink:Is("Running") and (TS - self.DLTimeStamp > 29) then
|
||||||
|
self.DLink = false
|
||||||
|
self.Detection = self:StartDetection() -- fall back
|
||||||
|
self:I(self.lid .. "Intel DLink not running - switching back to single detection!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- [Internal] Function to set start state
|
--- [Internal] Function to set start state
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
@@ -1077,11 +1114,13 @@ do
|
|||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
self:T(self.lid.."Starting MANTIS")
|
self:T(self.lid.."Starting MANTIS")
|
||||||
self:SetSAMStartState()
|
self:SetSAMStartState()
|
||||||
self.Detection = self:StartDetection()
|
if not self.DLink then
|
||||||
|
self.Detection = self:StartDetection()
|
||||||
|
end
|
||||||
if self.advAwacs then
|
if self.advAwacs then
|
||||||
self.AWACS_Detection = self:StartAwacsDetection()
|
self.AWACS_Detection = self:StartAwacsDetection()
|
||||||
end
|
end
|
||||||
self:__Status(self.detectinterval)
|
self:__Status(-math.random(1,10))
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1120,11 +1159,16 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- timer for advanced state check
|
-- advanced state check
|
||||||
if self.advanced then
|
if self.advanced then
|
||||||
self:_CheckAdvState()
|
self:_CheckAdvState()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- check DLink state
|
||||||
|
if self.DLink then
|
||||||
|
self:_CheckDLinkState()
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1136,6 +1180,13 @@ do
|
|||||||
-- @return #MANTIS self
|
-- @return #MANTIS self
|
||||||
function MANTIS:onafterStatus(From,Event,To)
|
function MANTIS:onafterStatus(From,Event,To)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
|
-- Display some states
|
||||||
|
if self.debug then
|
||||||
|
self:I(self.lid .. "Status Report")
|
||||||
|
for _name,_state in pairs(self.SamStateTracker) do
|
||||||
|
self:I(string.format("Site %s\tStatus %s",_name,_state))
|
||||||
|
end
|
||||||
|
end
|
||||||
local interval = self.detectinterval * -1
|
local interval = self.detectinterval * -1
|
||||||
self:__Status(interval)
|
self:__Status(interval)
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -2831,6 +2831,7 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
local accur=0
|
local accur=0
|
||||||
if shots>0 then
|
if shots>0 then
|
||||||
accur=_result.hits/shots*100
|
accur=_result.hits/shots*100
|
||||||
|
if accur > 100 then accur = 100 end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Message text.
|
-- Message text.
|
||||||
|
|||||||
@@ -17,14 +17,15 @@
|
|||||||
--
|
--
|
||||||
-- ### Authors: **FlightControl**, **applevangelist**
|
-- ### Authors: **FlightControl**, **applevangelist**
|
||||||
--
|
--
|
||||||
-- Last Update: July 2021
|
-- Last Update: Aug 2021
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Functional.Sead
|
-- @module Functional.Sead
|
||||||
-- @image SEAD.JPG
|
-- @image SEAD.JPG
|
||||||
|
|
||||||
--- @type SEAD
|
---
|
||||||
|
-- @type SEAD
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
||||||
@@ -48,7 +49,8 @@ SEAD = {
|
|||||||
},
|
},
|
||||||
SEADGroupPrefixes = {},
|
SEADGroupPrefixes = {},
|
||||||
SuppressedGroups = {},
|
SuppressedGroups = {},
|
||||||
EngagementRange = 75 -- default 75% engagement range Feature Request #1355
|
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
|
||||||
|
Padding = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Missile enumerators
|
--- Missile enumerators
|
||||||
@@ -59,7 +61,7 @@ SEAD = {
|
|||||||
["AGM_122"] = "AGM_122",
|
["AGM_122"] = "AGM_122",
|
||||||
["AGM_84"] = "AGM_84",
|
["AGM_84"] = "AGM_84",
|
||||||
["AGM_45"] = "AGM_45",
|
["AGM_45"] = "AGM_45",
|
||||||
["ALARN"] = "ALARM",
|
["ALARM"] = "ALARM",
|
||||||
["LD-10"] = "LD-10",
|
["LD-10"] = "LD-10",
|
||||||
["X_58"] = "X_58",
|
["X_58"] = "X_58",
|
||||||
["X_28"] = "X_28",
|
["X_28"] = "X_28",
|
||||||
@@ -68,17 +70,35 @@ SEAD = {
|
|||||||
["Kh25"] = "Kh25",
|
["Kh25"] = "Kh25",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Missile enumerators - from DCS ME and Wikipedia
|
||||||
|
-- @field HarmData
|
||||||
|
SEAD.HarmData = {
|
||||||
|
-- km and mach
|
||||||
|
["AGM_88"] = { 150, 3},
|
||||||
|
["AGM_45"] = { 12, 2},
|
||||||
|
["AGM_122"] = { 16.5, 2.3},
|
||||||
|
["AGM_84"] = { 280, 0.85},
|
||||||
|
["ALARM"] = { 45, 2},
|
||||||
|
["LD-10"] = { 60, 4},
|
||||||
|
["X_58"] = { 70, 4},
|
||||||
|
["X_28"] = { 80, 2.5},
|
||||||
|
["X_25"] = { 25, 0.76},
|
||||||
|
["X_31"] = {150, 3},
|
||||||
|
["Kh25"] = {25, 0.8},
|
||||||
|
}
|
||||||
|
|
||||||
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
||||||
-- When an anti radiation missile is fired (KH-58, KH-31P, KH-31A, KH-25MPU, HARM missiles), the SA will shut down their radars and will take evasive actions...
|
-- When an anti radiation missile is fired (KH-58, KH-31P, KH-31A, KH-25MPU, HARM missiles), the SA will shut down their radars and will take evasive actions...
|
||||||
-- Chances are big that the missile will miss.
|
-- Chances are big that the missile will miss.
|
||||||
-- @param #SEAD self
|
-- @param #SEAD self
|
||||||
-- @param table{string,...}|string SEADGroupPrefixes which is a table of Prefixes of the SA Groups in the DCS mission editor on which evasive actions need to be taken.
|
-- @param #table SEADGroupPrefixes Table of #string entries or single #string, which is a table of Prefixes of the SA Groups in the DCS mission editor on which evasive actions need to be taken.
|
||||||
|
-- @param #number Padding (Optional) Extra number of seconds to add to radar switch-back-on time
|
||||||
-- @return SEAD
|
-- @return SEAD
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- CCCP SEAD Defenses
|
-- -- CCCP SEAD Defenses
|
||||||
-- -- Defends the Russian SA installations from SEAD attacks.
|
-- -- Defends the Russian SA installations from SEAD attacks.
|
||||||
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
|
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
|
||||||
function SEAD:New( SEADGroupPrefixes )
|
function SEAD:New( SEADGroupPrefixes, Padding )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
self:F( SEADGroupPrefixes )
|
self:F( SEADGroupPrefixes )
|
||||||
@@ -91,8 +111,13 @@ function SEAD:New( SEADGroupPrefixes )
|
|||||||
self.SEADGroupPrefixes[SEADGroupPrefixes] = SEADGroupPrefixes
|
self.SEADGroupPrefixes[SEADGroupPrefixes] = SEADGroupPrefixes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local padding = Padding or 10
|
||||||
|
if padding < 10 then padding = 10 end
|
||||||
|
self.Padding = padding
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
|
self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
|
||||||
self:I("*** SEAD - Started Version 0.2.9")
|
|
||||||
|
self:I("*** SEAD - Started Version 0.3.1")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -130,54 +155,100 @@ function SEAD:SetEngagementRange(range)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the padding in seconds, which extends the radar off time calculated by SEAD
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param #number Padding Extra number of seconds to add for the switch-on
|
||||||
|
function SEAD:SetPadding(Padding)
|
||||||
|
self:T( { Padding } )
|
||||||
|
local padding = Padding or 10
|
||||||
|
if padding < 10 then padding = 10 end
|
||||||
|
self.Padding = padding
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if a known HARM was fired
|
--- Check if a known HARM was fired
|
||||||
-- @param #SEAD self
|
-- @param #SEAD self
|
||||||
-- @param #string WeaponName
|
-- @param #string WeaponName
|
||||||
-- @return #boolean Returns true for a match
|
-- @return #boolean Returns true for a match
|
||||||
|
-- @return #string name Name of hit in table
|
||||||
function SEAD:_CheckHarms(WeaponName)
|
function SEAD:_CheckHarms(WeaponName)
|
||||||
self:T( { WeaponName } )
|
self:T( { WeaponName } )
|
||||||
local hit = false
|
local hit = false
|
||||||
|
local name = ""
|
||||||
for _,_name in pairs (SEAD.Harms) do
|
for _,_name in pairs (SEAD.Harms) do
|
||||||
if string.find(WeaponName,_name,1) then hit = true end
|
if string.find(WeaponName,_name,1) then
|
||||||
|
hit = true
|
||||||
|
name = _name
|
||||||
|
break
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return hit
|
return hit, name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Return distance in meters between two coordinates or -1 on error.
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param Core.Point#COORDINATE _point1 Coordinate one
|
||||||
|
-- @param Core.Point#COORDINATE _point2 Coordinate two
|
||||||
|
-- @return #number Distance in meters
|
||||||
|
function SEAD:_GetDistance(_point1, _point2)
|
||||||
|
self:T("_GetDistance")
|
||||||
|
if _point1 and _point2 then
|
||||||
|
local distance1 = _point1:Get2DDistance(_point2)
|
||||||
|
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
||||||
|
--self:T({dist1=distance1, dist2=distance2})
|
||||||
|
if distance1 and type(distance1) == "number" then
|
||||||
|
return distance1
|
||||||
|
elseif distance2 and type(distance2) == "number" then
|
||||||
|
return distance2
|
||||||
|
else
|
||||||
|
self:E("*****Cannot calculate distance!")
|
||||||
|
self:E({_point1,_point2})
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:E("******Cannot calculate distance!")
|
||||||
|
self:E({_point1,_point2})
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
--- Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
||||||
-- @see SEAD
|
-- @see SEAD
|
||||||
-- @param #SEAD
|
-- @param #SEAD
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SEAD:HandleEventShot( EventData )
|
function SEAD:HandleEventShot( EventData )
|
||||||
self:T( { EventData } )
|
self:T( { EventData.id } )
|
||||||
|
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
||||||
|
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
local SEADUnit = EventData.IniDCSUnit
|
local SEADUnit = EventData.IniDCSUnit
|
||||||
local SEADUnitName = EventData.IniDCSUnitName
|
local SEADUnitName = EventData.IniDCSUnitName
|
||||||
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
||||||
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
||||||
|
|
||||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||||
self:T({ SEADWeapon })
|
--self:T({ SEADWeapon })
|
||||||
|
|
||||||
if self:_CheckHarms(SEADWeaponName) then
|
if self:_CheckHarms(SEADWeaponName) then
|
||||||
|
self:T( '*** SEAD - Weapon Match' )
|
||||||
local _targetskill = "Random"
|
local _targetskill = "Random"
|
||||||
local _targetMimgroupName = "none"
|
local _targetgroupname = "none"
|
||||||
local _evade = math.random (1,100) -- random number for chance of evading action
|
local _target = EventData.Weapon:getTarget() -- Identify target
|
||||||
local _targetMim = EventData.Weapon:getTarget() -- Identify target
|
local _targetUnit = UNIT:Find(_target) -- Wrapper.Unit#UNIT
|
||||||
local _targetUnit = UNIT:Find(_targetMim) -- Unit name by DCS Object
|
local _targetgroup = nil -- Wrapper.Group#GROUP
|
||||||
if _targetUnit and _targetUnit:IsAlive() then
|
if _targetUnit and _targetUnit:IsAlive() then
|
||||||
local _targetMimgroup = _targetUnit:GetGroup()
|
_targetgroup = _targetUnit:GetGroup()
|
||||||
_targetMimgroupName = _targetMimgroup:GetName() -- group name
|
_targetgroupname = _targetgroup:GetName() -- group name
|
||||||
--local _targetskill = _DATABASE.Templates.Units[_targetUnit].Template.skill
|
local _targetUnitName = _targetUnit:GetName()
|
||||||
self:T( self.SEADGroupPrefixes )
|
_targetUnit:GetSkill()
|
||||||
self:T( _targetMimgroupName )
|
_targetskill = _targetUnit:GetSkill()
|
||||||
end
|
end
|
||||||
-- see if we are shot at
|
-- see if we are shot at
|
||||||
local SEADGroupFound = false
|
local SEADGroupFound = false
|
||||||
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
|
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
|
||||||
self:T( SEADGroupPrefix )
|
self:T( SEADGroupPrefix )
|
||||||
if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then
|
if string.find( _targetgroupname, SEADGroupPrefix, 1, true ) then
|
||||||
SEADGroupFound = true
|
SEADGroupFound = true
|
||||||
self:T( '*** SEAD - Group Found' )
|
self:T( '*** SEAD - Group Match Found' )
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -186,42 +257,67 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
local Skills = { "Average", "Good", "High", "Excellent" }
|
local Skills = { "Average", "Good", "High", "Excellent" }
|
||||||
_targetskill = Skills[ math.random(1,4) ]
|
_targetskill = Skills[ math.random(1,4) ]
|
||||||
end
|
end
|
||||||
self:T( _targetskill )
|
--self:T( _targetskill )
|
||||||
if self.TargetSkill[_targetskill] then
|
if self.TargetSkill[_targetskill] then
|
||||||
|
local _evade = math.random (1,100) -- random number for chance of evading action
|
||||||
if (_evade > self.TargetSkill[_targetskill].Evade) then
|
if (_evade > self.TargetSkill[_targetskill].Evade) then
|
||||||
|
self:T("*** SEAD - Evading")
|
||||||
self:T( string.format("*** SEAD - Evading, target skill " ..string.format(_targetskill)) )
|
-- calculate distance of attacker
|
||||||
|
local _targetpos = _targetgroup:GetCoordinate()
|
||||||
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
|
local _distance = self:_GetDistance(SEADPlanePos, _targetpos)
|
||||||
local _targetMimcont= _targetMimgroup:getController()
|
-- weapon speed
|
||||||
|
local hit, data = self:_CheckHarms(SEADWeaponName)
|
||||||
routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly
|
local wpnspeed = 666 -- ;)
|
||||||
|
local reach = 10
|
||||||
--tracker ID table to switch groups off and on again
|
if hit then
|
||||||
local id = {
|
local wpndata = SEAD.HarmData[data]
|
||||||
groupName = _targetMimgroup,
|
reach = wpndata[1] * 1,1
|
||||||
ctrl = _targetMimcont
|
local mach = wpndata[2]
|
||||||
}
|
wpnspeed = math.floor(mach * 340.29)
|
||||||
|
|
||||||
local function SuppressionEnd(id) --switch group back on
|
|
||||||
local range = self.EngagementRange -- Feature Request #1355
|
|
||||||
self:T(string.format("*** SEAD - Engagement Range is %d", range))
|
|
||||||
id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED)
|
|
||||||
--id.groupName:enableEmission(true)
|
|
||||||
id.ctrl:setOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,range) --Feature Request #1355
|
|
||||||
self.SuppressedGroups[id.groupName] = nil --delete group id from table when done
|
|
||||||
end
|
end
|
||||||
-- randomize switch-on time
|
-- time to impact
|
||||||
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
|
local _tti = math.floor(_distance / wpnspeed) -- estimated impact time
|
||||||
local SuppressionEndTime = timer.getTime() + delay
|
if _distance > 0 then
|
||||||
--create entry
|
_distance = math.floor(_distance / 1000) -- km
|
||||||
if self.SuppressedGroups[id.groupName] == nil then --no timer entry for this group yet
|
else
|
||||||
self.SuppressedGroups[id.groupName] = {
|
_distance = 0
|
||||||
SuppressionEndTime = delay
|
end
|
||||||
}
|
|
||||||
Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN)
|
self:T( string.format("*** SEAD - target skill %s, distance %dkm, reach %dkm, tti %dsec", _targetskill, _distance,reach,_tti ))
|
||||||
--_targetMimgroup:enableEmission(false)
|
|
||||||
timer.scheduleFunction(SuppressionEnd, id, SuppressionEndTime) --Schedule the SuppressionEnd() function
|
if reach >= _distance then
|
||||||
|
self:T("*** SEAD - Shot in Reach")
|
||||||
|
|
||||||
|
local function SuppressionStart(args)
|
||||||
|
self:T(string.format("*** SEAD - %s Radar Off & Relocating",args[2]))
|
||||||
|
local grp = args[1] -- Wrapper.Group#GROUP
|
||||||
|
grp:OptionAlarmStateGreen()
|
||||||
|
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SuppressionStop(args)
|
||||||
|
self:T(string.format("*** SEAD - %s Radar On",args[2]))
|
||||||
|
local grp = args[1] -- Wrapper.Group#GROUP
|
||||||
|
grp:OptionAlarmStateRed()
|
||||||
|
grp:OptionEngageRange(self.EngagementRange)
|
||||||
|
self.SuppressedGroups[args[2]] = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- randomize switch-on time
|
||||||
|
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
|
||||||
|
if delay > _tti then delay = delay / 2 end -- speed up
|
||||||
|
if _tti > (3*delay) then delay = (_tti / 2) * 0.9 end -- shot from afar
|
||||||
|
|
||||||
|
local SuppressionStartTime = timer.getTime() + delay
|
||||||
|
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
|
||||||
|
|
||||||
|
if not self.SuppressedGroups[_targetgroupname] then
|
||||||
|
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
|
||||||
|
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname},SuppressionStartTime)
|
||||||
|
timer.scheduleFunction(SuppressionStop,{_targetgroup,_targetgroupname},SuppressionEndTime)
|
||||||
|
self.SuppressedGroups[_targetgroupname] = true
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ do
|
|||||||
["AGM_122"] = "AGM_122",
|
["AGM_122"] = "AGM_122",
|
||||||
["AGM_84"] = "AGM_84",
|
["AGM_84"] = "AGM_84",
|
||||||
["AGM_45"] = "AGM_45",
|
["AGM_45"] = "AGM_45",
|
||||||
["ALARN"] = "ALARM",
|
["ALARM"] = "ALARM",
|
||||||
["LD-10"] = "LD-10",
|
["LD-10"] = "LD-10",
|
||||||
["X_58"] = "X_58",
|
["X_58"] = "X_58",
|
||||||
["X_28"] = "X_28",
|
["X_28"] = "X_28",
|
||||||
|
|||||||
@@ -715,20 +715,21 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
|
|
||||||
local UnitHit = EventData.TgtUnit
|
local UnitHit = EventData.TgtUnit
|
||||||
|
|
||||||
|
if UnitHit.ClassName ~= "SCENERY" then
|
||||||
-- Check if unit is inside the capture zone and that it is of the defending coalition.
|
-- Check if unit is inside the capture zone and that it is of the defending coalition.
|
||||||
if UnitHit and UnitHit:IsInZone(self) and UnitHit:GetCoalition()==self.Coalition then
|
if UnitHit and UnitHit:IsInZone(self) and UnitHit:GetCoalition()==self.Coalition then
|
||||||
|
|
||||||
-- Update last hit time.
|
-- Update last hit time.
|
||||||
self.HitTimeLast=timer.getTime()
|
self.HitTimeLast=timer.getTime()
|
||||||
|
|
||||||
-- Only trigger attacked event if not already in state "Attacked".
|
-- Only trigger attacked event if not already in state "Attacked".
|
||||||
if self:GetState()~="Attacked" then
|
if self:GetState()~="Attacked" then
|
||||||
self:F2("Hit ==> Attack")
|
self:F2("Hit ==> Attack")
|
||||||
self:Attack()
|
self:Attack()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -890,12 +891,14 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Status text.
|
-- Status text.
|
||||||
local text=string.format("CAPTURE ZONE %s: Owner=%s (Previous=%s): #blue=%d, #red=%d, Status %s", self:GetZoneName(), self:GetCoalitionName(), UTILS.GetCoalitionName(self:GetPreviousCoalition()), nBlue, nRed, State)
|
if false then
|
||||||
local NewState = self:GetState()
|
local text=string.format("CAPTURE ZONE %s: Owner=%s (Previous=%s): #blue=%d, #red=%d, Status %s", self:GetZoneName(), self:GetCoalitionName(), UTILS.GetCoalitionName(self:GetPreviousCoalition()), nBlue, nRed, State)
|
||||||
if NewState~=State then
|
local NewState = self:GetState()
|
||||||
text=text..string.format(" --> %s", NewState)
|
if NewState~=State then
|
||||||
|
text=text..string.format(" --> %s", NewState)
|
||||||
|
end
|
||||||
|
self:I(text)
|
||||||
end
|
end
|
||||||
self:I(text)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ _DATABASE:_RegisterCargos()
|
|||||||
|
|
||||||
--- Register zones.
|
--- Register zones.
|
||||||
_DATABASE:_RegisterZones()
|
_DATABASE:_RegisterZones()
|
||||||
|
_DATABASE:_RegisterAirbases()
|
||||||
|
|
||||||
--- Check if os etc is available.
|
--- Check if os etc is available.
|
||||||
BASE:I("Checking de-sanitization of os, io and lfs:")
|
BASE:I("Checking de-sanitization of os, io and lfs:")
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@
|
|||||||
-- @module Ops.CSAR
|
-- @module Ops.CSAR
|
||||||
-- @image OPS_CSAR.jpg
|
-- @image OPS_CSAR.jpg
|
||||||
|
|
||||||
-- Date: Aug 2021
|
-- Date: Oct 2021
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||||
@@ -97,6 +97,14 @@
|
|||||||
-- self.pilotmustopendoors = false -- switch to true to enable check of open doors
|
-- self.pilotmustopendoors = false -- switch to true to enable check of open doors
|
||||||
-- -- (added 0.1.9)
|
-- -- (added 0.1.9)
|
||||||
-- self.suppressmessages = false -- switch off all messaging if you want to do your own
|
-- self.suppressmessages = false -- switch off all messaging if you want to do your own
|
||||||
|
-- -- (added 0.1.11)
|
||||||
|
-- self.rescuehoverheight = 20 -- max height for a hovering rescue in meters
|
||||||
|
-- self.rescuehoverdistance = 10 -- max distance for a hovering rescue in meters
|
||||||
|
-- -- (added 0.1.12)
|
||||||
|
-- -- Country codes for spawned pilots
|
||||||
|
-- self.countryblue= country.id.USA
|
||||||
|
-- self.countryred = country.id.RUSSIA
|
||||||
|
-- self.countryneutral = country.id.UN_PEACEKEEPERS
|
||||||
--
|
--
|
||||||
-- ## 2.1 Experimental Features
|
-- ## 2.1 Experimental Features
|
||||||
--
|
--
|
||||||
@@ -230,10 +238,11 @@ CSAR.AircraftType["Mi-8MTV2"] = 12
|
|||||||
CSAR.AircraftType["Mi-8MT"] = 12
|
CSAR.AircraftType["Mi-8MT"] = 12
|
||||||
CSAR.AircraftType["Mi-24P"] = 8
|
CSAR.AircraftType["Mi-24P"] = 8
|
||||||
CSAR.AircraftType["Mi-24V"] = 8
|
CSAR.AircraftType["Mi-24V"] = 8
|
||||||
|
CSAR.AircraftType["Bell-47"] = 2
|
||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="0.1.10r3"
|
CSAR.version="0.1.11r2"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -349,7 +358,7 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
self.csarPrefix = { "helicargo", "MEDEVAC"} -- prefixes used for useprefix=true - DON\'T use # in names!
|
self.csarPrefix = { "helicargo", "MEDEVAC"} -- prefixes used for useprefix=true - DON\'T use # in names!
|
||||||
self.template = Template or "generic" -- template for downed pilot
|
self.template = Template or "generic" -- template for downed pilot
|
||||||
self.mashprefix = {"MASH"} -- prefixes used to find MASHes
|
self.mashprefix = {"MASH"} -- prefixes used to find MASHes
|
||||||
self.mash = SET_GROUP:New():FilterCoalitions(self.coalition):FilterPrefixes(self.mashprefix):FilterOnce() -- currently only GROUP objects, maybe support STATICs also?
|
|
||||||
self.autosmoke = false -- automatically smoke location when heli is near
|
self.autosmoke = false -- automatically smoke location when heli is near
|
||||||
self.autosmokedistance = 2000 -- distance for autosmoke
|
self.autosmokedistance = 2000 -- distance for autosmoke
|
||||||
-- added 0.1.4
|
-- added 0.1.4
|
||||||
@@ -362,6 +371,15 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
self.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters
|
self.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters
|
||||||
self.pilotmustopendoors = false -- switch to true to enable check on open doors
|
self.pilotmustopendoors = false -- switch to true to enable check on open doors
|
||||||
self.suppressmessages = false
|
self.suppressmessages = false
|
||||||
|
|
||||||
|
-- added 0.1.11r1
|
||||||
|
self.rescuehoverheight = 20
|
||||||
|
self.rescuehoverdistance = 10
|
||||||
|
|
||||||
|
-- added 0.1.12
|
||||||
|
self.countryblue= country.id.USA
|
||||||
|
self.countryred = country.id.RUSSIA
|
||||||
|
self.countryneutral = country.id.UN_PEACEKEEPERS
|
||||||
|
|
||||||
-- WARNING - here\'ll be dragons
|
-- WARNING - here\'ll be dragons
|
||||||
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
||||||
@@ -549,6 +567,7 @@ function CSAR:_SpawnPilotInField(country,point,frequency)
|
|||||||
for i=1,10 do
|
for i=1,10 do
|
||||||
math.random(i,10000)
|
math.random(i,10000)
|
||||||
end
|
end
|
||||||
|
if point:IsSurfaceTypeWater() then point.y = 0 end
|
||||||
local template = self.template
|
local template = self.template
|
||||||
local alias = string.format("Pilot %.2fkHz-%d", freq, math.random(1,99))
|
local alias = string.format("Pilot %.2fkHz-%d", freq, math.random(1,99))
|
||||||
local coalition = self.coalition
|
local coalition = self.coalition
|
||||||
@@ -687,11 +706,11 @@ function CSAR:_SpawnCsarAtZone( _zone, _coalition, _description, _randomPoint, _
|
|||||||
|
|
||||||
local _country = 0
|
local _country = 0
|
||||||
if _coalition == coalition.side.BLUE then
|
if _coalition == coalition.side.BLUE then
|
||||||
_country = country.id.USA
|
_country = self.countryblue
|
||||||
elseif _coalition == coalition.side.RED then
|
elseif _coalition == coalition.side.RED then
|
||||||
_country = country.id.RUSSIA
|
_country = self.countryred
|
||||||
else
|
else
|
||||||
_country = country.id.UN_PEACEKEEPERS
|
_country = self.countryneutral
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_AddCsar(_coalition, _country, pos, typename, unitname, _description, freq, _nomessage, _description, forcedesc)
|
self:_AddCsar(_coalition, _country, pos, typename, unitname, _description, freq, _nomessage, _description, forcedesc)
|
||||||
@@ -718,7 +737,6 @@ function CSAR:SpawnCSARAtZone(Zone, Coalition, Description, RandomPoint, Nomessa
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: Split in functions per Event type
|
|
||||||
--- (Internal) Event handler.
|
--- (Internal) Event handler.
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
function CSAR:_EventHandler(EventData)
|
function CSAR:_EventHandler(EventData)
|
||||||
@@ -790,7 +808,7 @@ function CSAR:_EventHandler(EventData)
|
|||||||
if self:_DoubleEjection(_unitname) then
|
if self:_DoubleEjection(_unitname) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self:_DisplayToAllSAR("MAYDAY MAYDAY! " .. _unit:GetTypeName() .. " shot down. No Chute!", self.coalition, self.messageTime)
|
|
||||||
else
|
else
|
||||||
self:T(self.lid .. " Pilot has not taken off, ignore")
|
self:T(self.lid .. " Pilot has not taken off, ignore")
|
||||||
end
|
end
|
||||||
@@ -878,13 +896,6 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
||||||
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
|
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
|
||||||
--[[
|
|
||||||
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_event.IniUnitName) then
|
|
||||||
self:_DisplayMessageToSAR(_unit, "Open the door to let me out!", self.messageTime, true)
|
|
||||||
else
|
|
||||||
self:_RescuePilots(_unit)
|
|
||||||
end
|
|
||||||
--]]
|
|
||||||
else
|
else
|
||||||
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
||||||
end
|
end
|
||||||
@@ -904,7 +915,6 @@ end
|
|||||||
function CSAR:_InitSARForPilot(_downedGroup, _GroupName, _freq, _nomessage)
|
function CSAR:_InitSARForPilot(_downedGroup, _GroupName, _freq, _nomessage)
|
||||||
self:T(self.lid .. " _InitSARForPilot")
|
self:T(self.lid .. " _InitSARForPilot")
|
||||||
local _leader = _downedGroup:GetUnit(1)
|
local _leader = _downedGroup:GetUnit(1)
|
||||||
--local _groupName = _downedGroup:GetName()
|
|
||||||
local _groupName = _GroupName
|
local _groupName = _GroupName
|
||||||
local _freqk = _freq / 1000
|
local _freqk = _freq / 1000
|
||||||
local _coordinatesText = self:_GetPositionOfWounded(_downedGroup)
|
local _coordinatesText = self:_GetPositionOfWounded(_downedGroup)
|
||||||
@@ -920,7 +930,7 @@ function CSAR:_InitSARForPilot(_downedGroup, _GroupName, _freq, _nomessage)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- trigger FSM event
|
-- trigger FSM event
|
||||||
self:__PilotDown(2,_downedGroup, _freqk, _leadername, _coordinatesText)
|
self:__PilotDown(2,_downedGroup, _freqk, _groupName, _coordinatesText)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1090,7 +1100,6 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
|
|||||||
local grouptable = downedgrouptable --#CSAR.DownedPilot
|
local grouptable = downedgrouptable --#CSAR.DownedPilot
|
||||||
self.inTransitGroups[_heliName][_woundedGroupName] =
|
self.inTransitGroups[_heliName][_woundedGroupName] =
|
||||||
{
|
{
|
||||||
-- DONE: Fix with #CSAR.DownedPilot
|
|
||||||
originalUnit = grouptable.originalUnit,
|
originalUnit = grouptable.originalUnit,
|
||||||
woundedGroup = _woundedGroupName,
|
woundedGroup = _woundedGroupName,
|
||||||
side = self.coalition,
|
side = self.coalition,
|
||||||
@@ -1129,42 +1138,7 @@ end
|
|||||||
-- @return #boolean outcome The outcome.
|
-- @return #boolean outcome The outcome.
|
||||||
function CSAR:_IsLoadingDoorOpen( unit_name )
|
function CSAR:_IsLoadingDoorOpen( unit_name )
|
||||||
self:T(self.lid .. " _IsLoadingDoorOpen")
|
self:T(self.lid .. " _IsLoadingDoorOpen")
|
||||||
|
|
||||||
--[[
|
|
||||||
local ret_val = false
|
|
||||||
local unit = Unit.getByName(unit_name)
|
|
||||||
if unit ~= nil then
|
|
||||||
local type_name = unit:getTypeName()
|
|
||||||
|
|
||||||
if type_name == "Mi-8MT" and unit:getDrawArgumentValue(86) == 1 or unit:getDrawArgumentValue(250) == 1 then
|
|
||||||
self:T(unit_name .. " Cargo doors are open or cargo door not present")
|
|
||||||
ret_val = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if type_name == "Mi-24P" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 then
|
|
||||||
self:T(unit_name .. " a side door is open")
|
|
||||||
ret_val = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if type_name == "UH-1H" and unit:getDrawArgumentValue(43) == 1 or unit:getDrawArgumentValue(44) == 1 then
|
|
||||||
self:T(unit_name .. " a side door is open ")
|
|
||||||
ret_val = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if string.find(type_name, "SA342" ) and unit:getDrawArgumentValue(34) == 1 or unit:getDrawArgumentValue(38) == 1 then
|
|
||||||
self:T(unit_name .. " front door(s) are open")
|
|
||||||
ret_val = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if ret_val == false then
|
|
||||||
self:T(unit_name .. " all doors are closed")
|
|
||||||
end
|
|
||||||
return ret_val
|
|
||||||
|
|
||||||
end -- nil
|
|
||||||
--]]
|
|
||||||
return UTILS.IsLoadingDoorOpen(unit_name)
|
return UTILS.IsLoadingDoorOpen(unit_name)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Function to check if heli is close to group.
|
--- (Internal) Function to check if heli is close to group.
|
||||||
@@ -1195,14 +1169,12 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
else
|
else
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", _heliName, _pilotName), self.messageTime,false,true)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", _heliName, _pilotName), self.messageTime,false,true)
|
||||||
end
|
end
|
||||||
--mark as shown for THIS heli and THIS group
|
|
||||||
self.heliCloseMessage[_lookupKeyHeli] = true
|
self.heliCloseMessage[_lookupKeyHeli] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- have we landed close enough?
|
-- have we landed close enough?
|
||||||
if not _heliUnit:InAir() then
|
if not _heliUnit:InAir() then
|
||||||
|
|
||||||
-- if you land on them, doesnt matter if they were heading to someone else as you\'re closer, you win! :)
|
|
||||||
if self.pilotRuntoExtractPoint == true then
|
if self.pilotRuntoExtractPoint == true then
|
||||||
if (_distance < self.extractDistance) then
|
if (_distance < self.extractDistance) then
|
||||||
local _time = self.landedStatus[_lookupKeyHeli]
|
local _time = self.landedStatus[_lookupKeyHeli]
|
||||||
@@ -1246,15 +1218,16 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
end
|
end
|
||||||
|
|
||||||
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
|
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
|
||||||
|
-- TODO - make variable
|
||||||
if _distance < 8.0 then
|
if _distance < self.rescuehoverdistance then
|
||||||
|
|
||||||
--check height!
|
--check height!
|
||||||
local leaderheight = _woundedLeader:GetHeight()
|
local leaderheight = _woundedLeader:GetHeight()
|
||||||
if leaderheight < 0 then leaderheight = 0 end
|
if leaderheight < 0 then leaderheight = 0 end
|
||||||
local _height = _heliUnit:GetHeight() - leaderheight
|
local _height = _heliUnit:GetHeight() - leaderheight
|
||||||
|
|
||||||
if _height <= 20.0 then
|
-- TODO - make variable
|
||||||
|
if _height <= self.rescuehoverheight then
|
||||||
|
|
||||||
local _time = self.hoverStatus[_lookupKeyHeli]
|
local _time = self.hoverStatus[_lookupKeyHeli]
|
||||||
|
|
||||||
@@ -1353,8 +1326,7 @@ function CSAR:_RescuePilots(_heliUnit)
|
|||||||
-- Groups already rescued
|
-- Groups already rescued
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- DONE: count saved units?
|
|
||||||
local PilotsSaved = self:_PilotsOnboard(_heliName)
|
local PilotsSaved = self:_PilotsOnboard(_heliName)
|
||||||
|
|
||||||
self.inTransitGroups[_heliName] = nil
|
self.inTransitGroups[_heliName] = nil
|
||||||
@@ -1450,7 +1422,6 @@ function CSAR:_DisplayActiveSAR(_unitName)
|
|||||||
local _groupName = _value.name
|
local _groupName = _value.name
|
||||||
self:T(string.format("Display Active Pilot: %s", tostring(_groupName)))
|
self:T(string.format("Display Active Pilot: %s", tostring(_groupName)))
|
||||||
self:T({Table=_value})
|
self:T({Table=_value})
|
||||||
--local _woundedGroup = GROUP:FindByName(_groupName)
|
|
||||||
local _woundedGroup = _value.group
|
local _woundedGroup = _value.group
|
||||||
if _woundedGroup and _value.alive then
|
if _woundedGroup and _value.alive then
|
||||||
local _coordinatesText = self:_GetPositionOfWounded(_woundedGroup)
|
local _coordinatesText = self:_GetPositionOfWounded(_woundedGroup)
|
||||||
@@ -1747,7 +1718,6 @@ function CSAR:_GetDistance(_point1, _point2)
|
|||||||
if _point1 and _point2 then
|
if _point1 and _point2 then
|
||||||
local distance1 = _point1:Get2DDistance(_point2)
|
local distance1 = _point1:Get2DDistance(_point2)
|
||||||
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
||||||
self:I({dist1=distance1, dist2=distance2})
|
|
||||||
if distance1 and type(distance1) == "number" then
|
if distance1 and type(distance1) == "number" then
|
||||||
return distance1
|
return distance1
|
||||||
elseif distance2 and type(distance2) == "number" then
|
elseif distance2 and type(distance2) == "number" then
|
||||||
@@ -1768,7 +1738,6 @@ end
|
|||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
function CSAR:_GenerateVHFrequencies()
|
function CSAR:_GenerateVHFrequencies()
|
||||||
self:T(self.lid .. " _GenerateVHFrequencies")
|
self:T(self.lid .. " _GenerateVHFrequencies")
|
||||||
--local _skipFrequencies = self.SkipFrequencies
|
|
||||||
|
|
||||||
local FreeVHFFrequencies = {}
|
local FreeVHFFrequencies = {}
|
||||||
FreeVHFFrequencies = UTILS.GenerateVHFrequencies()
|
FreeVHFFrequencies = UTILS.GenerateVHFrequencies()
|
||||||
@@ -1808,7 +1777,6 @@ function CSAR:_GetClockDirection(_heli, _group)
|
|||||||
if _heading then
|
if _heading then
|
||||||
local Aspect = Angle - _heading
|
local Aspect = Angle - _heading
|
||||||
if Aspect == 0 then Aspect = 360 end
|
if Aspect == 0 then Aspect = 360 end
|
||||||
--clock = math.floor(Aspect / 30)
|
|
||||||
clock = math.abs(UTILS.Round((Aspect / 30),0))
|
clock = math.abs(UTILS.Round((Aspect / 30),0))
|
||||||
if clock == 0 then clock = 12 end
|
if clock == 0 then clock = 12 end
|
||||||
end
|
end
|
||||||
@@ -1917,6 +1885,7 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
else
|
else
|
||||||
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart()
|
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterCategoryHelicopter():FilterStart()
|
||||||
end
|
end
|
||||||
|
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart() -- currently only GROUP objects, maybe support STATICs also?
|
||||||
self:__Status(-10)
|
self:__Status(-10)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -157,7 +157,7 @@ end
|
|||||||
--- Set the frequency for the radio transmission.
|
--- Set the frequency for the radio transmission.
|
||||||
-- If the transmitting positionable is a unit or group, this also set the command "SetFrequency" with the defined frequency and modulation.
|
-- If the transmitting positionable is a unit or group, this also set the command "SetFrequency" with the defined frequency and modulation.
|
||||||
-- @param #RADIO self
|
-- @param #RADIO self
|
||||||
-- @param #number Frequency Frequency in MHz. Ranges allowed for radio transmissions in DCS : 30-87.995 / 108-173.995 / 225-399.975MHz.
|
-- @param #number Frequency Frequency in MHz.
|
||||||
-- @return #RADIO self
|
-- @return #RADIO self
|
||||||
function RADIO:SetFrequency(Frequency)
|
function RADIO:SetFrequency(Frequency)
|
||||||
self:F2(Frequency)
|
self:F2(Frequency)
|
||||||
@@ -165,7 +165,7 @@ function RADIO:SetFrequency(Frequency)
|
|||||||
if type(Frequency) == "number" then
|
if type(Frequency) == "number" then
|
||||||
|
|
||||||
-- If frequency is in range
|
-- If frequency is in range
|
||||||
if (Frequency >= 30 and Frequency <= 87.995) or (Frequency >= 108 and Frequency <= 173.995) or (Frequency >= 225 and Frequency <= 399.975) then
|
-- if (Frequency >= 30 and Frequency <= 87.995) or (Frequency >= 108 and Frequency <= 173.995) or (Frequency >= 225 and Frequency <= 399.975) then
|
||||||
|
|
||||||
-- Convert frequency from MHz to Hz
|
-- Convert frequency from MHz to Hz
|
||||||
self.Frequency = Frequency * 1000000
|
self.Frequency = Frequency * 1000000
|
||||||
@@ -186,10 +186,10 @@ function RADIO:SetFrequency(Frequency)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
-- end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E({"Frequency is outside of DCS Frequency ranges (30-80, 108-152, 225-400). Frequency unchanged.", Frequency})
|
self:E({"Frequency is not a number. Frequency unchanged.", Frequency})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
--- This module contains derived utilities taken from the MIST framework, which are excellent tools to be reused in an OO environment.
|
--- This module contains derived utilities taken from the MIST framework, which are excellent tools to be reused in an OO environment.
|
||||||
--
|
--
|
||||||
-- ### Authors:
|
-- ### Authors:
|
||||||
--
|
--
|
||||||
-- * Grimes : Design & Programming of the MIST framework.
|
-- * Grimes : Design & Programming of the MIST framework.
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- * FlightControl : Rework to OO framework
|
-- * FlightControl : Rework to OO framework.
|
||||||
--
|
--
|
||||||
-- @module Utils
|
-- @module Utils
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
-- @field White
|
-- @field White
|
||||||
-- @field Orange
|
-- @field Orange
|
||||||
-- @field Blue
|
-- @field Blue
|
||||||
|
|
||||||
SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR
|
SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR
|
||||||
|
|
||||||
--- @type FLARECOLOR
|
--- @type FLARECOLOR
|
||||||
@@ -94,7 +94,7 @@ CALLSIGN={
|
|||||||
Texaco=1,
|
Texaco=1,
|
||||||
Arco=2,
|
Arco=2,
|
||||||
Shell=3,
|
Shell=3,
|
||||||
},
|
},
|
||||||
-- JTAC
|
-- JTAC
|
||||||
JTAC={
|
JTAC={
|
||||||
Axeman=1,
|
Axeman=1,
|
||||||
@@ -163,31 +163,31 @@ UTILS = {
|
|||||||
UTILS.IsInstanceOf = function( object, className )
|
UTILS.IsInstanceOf = function( object, className )
|
||||||
-- Is className NOT a string ?
|
-- Is className NOT a string ?
|
||||||
if not type( className ) == 'string' then
|
if not type( className ) == 'string' then
|
||||||
|
|
||||||
-- Is className a Moose class ?
|
-- Is className a Moose class ?
|
||||||
if type( className ) == 'table' and className.IsInstanceOf ~= nil then
|
if type( className ) == 'table' and className.IsInstanceOf ~= nil then
|
||||||
|
|
||||||
-- Get the name of the Moose class as a string
|
-- Get the name of the Moose class as a string
|
||||||
className = className.ClassName
|
className = className.ClassName
|
||||||
|
|
||||||
-- className is neither a string nor a Moose class, throw an error
|
-- className is neither a string nor a Moose class, throw an error
|
||||||
else
|
else
|
||||||
|
|
||||||
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
|
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
|
||||||
local err_str = 'className parameter should be a string; parameter received: '..type( className )
|
local err_str = 'className parameter should be a string; parameter received: '..type( className )
|
||||||
return false
|
return false
|
||||||
-- error( err_str )
|
-- error( err_str )
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Is the object a Moose class instance ?
|
-- Is the object a Moose class instance ?
|
||||||
if type( object ) == 'table' and object.IsInstanceOf ~= nil then
|
if type( object ) == 'table' and object.IsInstanceOf ~= nil then
|
||||||
|
|
||||||
-- Use the IsInstanceOf method of the BASE class
|
-- Use the IsInstanceOf method of the BASE class
|
||||||
return object:IsInstanceOf( className )
|
return object:IsInstanceOf( className )
|
||||||
else
|
else
|
||||||
|
|
||||||
-- If the object is not an instance of a Moose class, evaluate against lua basic data types
|
-- If the object is not an instance of a Moose class, evaluate against lua basic data types
|
||||||
local basicDataTypes = { 'string', 'number', 'function', 'boolean', 'nil', 'table' }
|
local basicDataTypes = { 'string', 'number', 'function', 'boolean', 'nil', 'table' }
|
||||||
for _, basicDataType in ipairs( basicDataTypes ) do
|
for _, basicDataType in ipairs( basicDataTypes ) do
|
||||||
@@ -196,7 +196,7 @@ UTILS.IsInstanceOf = function( object, className )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check failed
|
-- Check failed
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -208,7 +208,7 @@ end
|
|||||||
UTILS.DeepCopy = function(object)
|
UTILS.DeepCopy = function(object)
|
||||||
|
|
||||||
local lookup_table = {}
|
local lookup_table = {}
|
||||||
|
|
||||||
-- Copy function.
|
-- Copy function.
|
||||||
local function _copy(object)
|
local function _copy(object)
|
||||||
if type(object) ~= "table" then
|
if type(object) ~= "table" then
|
||||||
@@ -216,20 +216,20 @@ UTILS.DeepCopy = function(object)
|
|||||||
elseif lookup_table[object] then
|
elseif lookup_table[object] then
|
||||||
return lookup_table[object]
|
return lookup_table[object]
|
||||||
end
|
end
|
||||||
|
|
||||||
local new_table = {}
|
local new_table = {}
|
||||||
|
|
||||||
lookup_table[object] = new_table
|
lookup_table[object] = new_table
|
||||||
|
|
||||||
for index, value in pairs(object) do
|
for index, value in pairs(object) do
|
||||||
new_table[_copy(index)] = _copy(value)
|
new_table[_copy(index)] = _copy(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(new_table, getmetatable(object))
|
return setmetatable(new_table, getmetatable(object))
|
||||||
end
|
end
|
||||||
|
|
||||||
local objectreturn = _copy(object)
|
local objectreturn = _copy(object)
|
||||||
|
|
||||||
return objectreturn
|
return objectreturn
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -239,19 +239,19 @@ end
|
|||||||
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
|
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
|
||||||
|
|
||||||
lookup_table = {}
|
lookup_table = {}
|
||||||
|
|
||||||
local function _Serialize( tbl )
|
local function _Serialize( tbl )
|
||||||
|
|
||||||
if type(tbl) == 'table' then --function only works for tables!
|
if type(tbl) == 'table' then --function only works for tables!
|
||||||
|
|
||||||
if lookup_table[tbl] then
|
if lookup_table[tbl] then
|
||||||
return lookup_table[object]
|
return lookup_table[object]
|
||||||
end
|
end
|
||||||
|
|
||||||
local tbl_str = {}
|
local tbl_str = {}
|
||||||
|
|
||||||
lookup_table[tbl] = tbl_str
|
lookup_table[tbl] = tbl_str
|
||||||
|
|
||||||
tbl_str[#tbl_str + 1] = '{'
|
tbl_str[#tbl_str + 1] = '{'
|
||||||
|
|
||||||
for ind,val in pairs(tbl) do -- serialize its fields
|
for ind,val in pairs(tbl) do -- serialize its fields
|
||||||
@@ -299,7 +299,7 @@ UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a s
|
|||||||
env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
|
env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
|
||||||
env.info( debug.traceback() )
|
env.info( debug.traceback() )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
tbl_str[#tbl_str + 1] = '}'
|
tbl_str[#tbl_str + 1] = '}'
|
||||||
return table.concat(tbl_str)
|
return table.concat(tbl_str)
|
||||||
@@ -307,7 +307,7 @@ UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a s
|
|||||||
return tostring(tbl)
|
return tostring(tbl)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local objectreturn = _Serialize(tbl)
|
local objectreturn = _Serialize(tbl)
|
||||||
return objectreturn
|
return objectreturn
|
||||||
end
|
end
|
||||||
@@ -339,18 +339,34 @@ UTILS.MetersToNM = function(meters)
|
|||||||
return meters/1852
|
return meters/1852
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UTILS.KiloMetersToNM = function(kilometers)
|
||||||
|
return kilometers/1852*1000
|
||||||
|
end
|
||||||
|
|
||||||
UTILS.MetersToSM = function(meters)
|
UTILS.MetersToSM = function(meters)
|
||||||
return meters/1609.34
|
return meters/1609.34
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UTILS.KiloMetersToSM = function(kilometers)
|
||||||
|
return kilometers/1609.34*1000
|
||||||
|
end
|
||||||
|
|
||||||
UTILS.MetersToFeet = function(meters)
|
UTILS.MetersToFeet = function(meters)
|
||||||
return meters/0.3048
|
return meters/0.3048
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UTILS.KiloMetersToFeet = function(kilometers)
|
||||||
|
return kilometers/0.3048*1000
|
||||||
|
end
|
||||||
|
|
||||||
UTILS.NMToMeters = function(NM)
|
UTILS.NMToMeters = function(NM)
|
||||||
return NM*1852
|
return NM*1852
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UTILS.NMToKiloMeters = function(NM)
|
||||||
|
return NM*1852/1000
|
||||||
|
end
|
||||||
|
|
||||||
UTILS.FeetToMeters = function(feet)
|
UTILS.FeetToMeters = function(feet)
|
||||||
return feet*0.3048
|
return feet*0.3048
|
||||||
end
|
end
|
||||||
@@ -400,7 +416,7 @@ end
|
|||||||
-- @param #number Celcius Temperature in degrees Celsius.
|
-- @param #number Celcius Temperature in degrees Celsius.
|
||||||
-- @return #number Temperature in degrees Farenheit.
|
-- @return #number Temperature in degrees Farenheit.
|
||||||
UTILS.CelciusToFarenheit = function( Celcius )
|
UTILS.CelciusToFarenheit = function( Celcius )
|
||||||
return Celcius * 9/5 + 32
|
return Celcius * 9/5 + 32
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert pressure from hecto Pascal (hPa) to inches of mercury (inHg).
|
--- Convert pressure from hecto Pascal (hPa) to inches of mercury (inHg).
|
||||||
@@ -415,7 +431,7 @@ end
|
|||||||
-- @param #number altitude Altitude in feet
|
-- @param #number altitude Altitude in feet
|
||||||
-- @return #number Corrected KIAS
|
-- @return #number Corrected KIAS
|
||||||
UTILS.KnotsToAltKIAS = function( knots, altitude )
|
UTILS.KnotsToAltKIAS = function( knots, altitude )
|
||||||
return (knots * 0.018 * (altitude / 1000)) + knots
|
return (knots * 0.018 * (altitude / 1000)) + knots
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert pressure from hecto Pascal (hPa) to millimeters of mercury (mmHg).
|
--- Convert pressure from hecto Pascal (hPa) to millimeters of mercury (mmHg).
|
||||||
@@ -534,23 +550,23 @@ UTILS.tostringMGRS = function(MGRS, acc) --R2.1
|
|||||||
-- Test if Easting/Northing have less than 4 digits.
|
-- Test if Easting/Northing have less than 4 digits.
|
||||||
--MGRS.Easting=123 -- should be 00123
|
--MGRS.Easting=123 -- should be 00123
|
||||||
--MGRS.Northing=5432 -- should be 05432
|
--MGRS.Northing=5432 -- should be 05432
|
||||||
|
|
||||||
-- Truncate rather than round MGRS grid!
|
-- Truncate rather than round MGRS grid!
|
||||||
local Easting=tostring(MGRS.Easting)
|
local Easting=tostring(MGRS.Easting)
|
||||||
local Northing=tostring(MGRS.Northing)
|
local Northing=tostring(MGRS.Northing)
|
||||||
|
|
||||||
-- Count number of missing digits. Easting/Northing should have 5 digits. However, it is passed as a number. Therefore, any leading zeros would not be displayed by lua.
|
-- Count number of missing digits. Easting/Northing should have 5 digits. However, it is passed as a number. Therefore, any leading zeros would not be displayed by lua.
|
||||||
local nE=5-string.len(Easting)
|
local nE=5-string.len(Easting)
|
||||||
local nN=5-string.len(Northing)
|
local nN=5-string.len(Northing)
|
||||||
|
|
||||||
-- Get leading zeros (if any).
|
-- Get leading zeros (if any).
|
||||||
for i=1,nE do Easting="0"..Easting end
|
for i=1,nE do Easting="0"..Easting end
|
||||||
for i=1,nN do Northing="0"..Northing end
|
for i=1,nN do Northing="0"..Northing end
|
||||||
|
|
||||||
-- Return MGRS string.
|
-- Return MGRS string.
|
||||||
return string.format("%s %s %s %s", MGRS.UTMZone, MGRS.MGRSDigraph, string.sub(Easting, 1, acc), string.sub(Northing, 1, acc))
|
return string.format("%s %s %s %s", MGRS.UTMZone, MGRS.MGRSDigraph, string.sub(Easting, 1, acc), string.sub(Northing, 1, acc))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -578,7 +594,7 @@ function UTILS.spairs( t, order )
|
|||||||
for k in pairs(t) do keys[#keys+1] = k end
|
for k in pairs(t) do keys[#keys+1] = k end
|
||||||
|
|
||||||
-- if order function given, sort by it by passing the table and keys a, b,
|
-- if order function given, sort by it by passing the table and keys a, b,
|
||||||
-- otherwise just sort the keys
|
-- otherwise just sort the keys
|
||||||
if order then
|
if order then
|
||||||
table.sort(keys, function(a,b) return order(t, a, b) end)
|
table.sort(keys, function(a,b) return order(t, a, b) end)
|
||||||
else
|
else
|
||||||
@@ -604,7 +620,7 @@ function UTILS.kpairs( t, getkey, order )
|
|||||||
for k, o in pairs(t) do keys[#keys+1] = k keyso[#keyso+1] = getkey( o ) end
|
for k, o in pairs(t) do keys[#keys+1] = k keyso[#keyso+1] = getkey( o ) end
|
||||||
|
|
||||||
-- if order function given, sort by it by passing the table and keys a, b,
|
-- if order function given, sort by it by passing the table and keys a, b,
|
||||||
-- otherwise just sort the keys
|
-- otherwise just sort the keys
|
||||||
if order then
|
if order then
|
||||||
table.sort(keys, function(a,b) return order(t, a, b) end)
|
table.sort(keys, function(a,b) return order(t, a, b) end)
|
||||||
else
|
else
|
||||||
@@ -624,7 +640,7 @@ end
|
|||||||
-- Here is a customized version of pairs, which I called rpairs because it iterates over the table in a random order.
|
-- Here is a customized version of pairs, which I called rpairs because it iterates over the table in a random order.
|
||||||
function UTILS.rpairs( t )
|
function UTILS.rpairs( t )
|
||||||
-- collect the keys
|
-- collect the keys
|
||||||
|
|
||||||
local keys = {}
|
local keys = {}
|
||||||
for k in pairs(t) do keys[#keys+1] = k end
|
for k in pairs(t) do keys[#keys+1] = k end
|
||||||
|
|
||||||
@@ -635,7 +651,7 @@ function UTILS.rpairs( t )
|
|||||||
random[i] = keys[k]
|
random[i] = keys[k]
|
||||||
table.remove( keys, k )
|
table.remove( keys, k )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- return the iterator function
|
-- return the iterator function
|
||||||
local i = 0
|
local i = 0
|
||||||
return function()
|
return function()
|
||||||
@@ -751,12 +767,12 @@ end
|
|||||||
function UTILS.GetCharacters(str)
|
function UTILS.GetCharacters(str)
|
||||||
|
|
||||||
local chars={}
|
local chars={}
|
||||||
|
|
||||||
for i=1,#str do
|
for i=1,#str do
|
||||||
local c=str:sub(i,i)
|
local c=str:sub(i,i)
|
||||||
table.insert(chars, c)
|
table.insert(chars, c)
|
||||||
end
|
end
|
||||||
|
|
||||||
return chars
|
return chars
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -765,15 +781,15 @@ end
|
|||||||
-- @param #boolean short (Optional) If true, use short output, i.e. (HH:)MM:SS without day.
|
-- @param #boolean short (Optional) If true, use short output, i.e. (HH:)MM:SS without day.
|
||||||
-- @return #string Time in format Hours:Minutes:Seconds+Days (HH:MM:SS+D).
|
-- @return #string Time in format Hours:Minutes:Seconds+Days (HH:MM:SS+D).
|
||||||
function UTILS.SecondsToClock(seconds, short)
|
function UTILS.SecondsToClock(seconds, short)
|
||||||
|
|
||||||
-- Nil check.
|
-- Nil check.
|
||||||
if seconds==nil then
|
if seconds==nil then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Seconds
|
-- Seconds
|
||||||
local seconds = tonumber(seconds)
|
local seconds = tonumber(seconds)
|
||||||
|
|
||||||
-- Seconds of this day.
|
-- Seconds of this day.
|
||||||
local _seconds=seconds%(60*60*24)
|
local _seconds=seconds%(60*60*24)
|
||||||
|
|
||||||
@@ -803,10 +819,10 @@ function UTILS.SecondsOfToday()
|
|||||||
|
|
||||||
-- Time in seconds.
|
-- Time in seconds.
|
||||||
local time=timer.getAbsTime()
|
local time=timer.getAbsTime()
|
||||||
|
|
||||||
-- Short format without days since mission start.
|
-- Short format without days since mission start.
|
||||||
local clock=UTILS.SecondsToClock(time, true)
|
local clock=UTILS.SecondsToClock(time, true)
|
||||||
|
|
||||||
-- Time is now the seconds passed since last midnight.
|
-- Time is now the seconds passed since last midnight.
|
||||||
return UTILS.ClockToSeconds(clock)
|
return UTILS.ClockToSeconds(clock)
|
||||||
end
|
end
|
||||||
@@ -821,24 +837,24 @@ end
|
|||||||
-- @param #string clock String of clock time. E.g., "06:12:35" or "5:1:30+1". Format is (H)H:(M)M:((S)S)(+D) H=Hours, M=Minutes, S=Seconds, D=Days.
|
-- @param #string clock String of clock time. E.g., "06:12:35" or "5:1:30+1". Format is (H)H:(M)M:((S)S)(+D) H=Hours, M=Minutes, S=Seconds, D=Days.
|
||||||
-- @return #number Seconds. Corresponds to what you cet from timer.getAbsTime() function.
|
-- @return #number Seconds. Corresponds to what you cet from timer.getAbsTime() function.
|
||||||
function UTILS.ClockToSeconds(clock)
|
function UTILS.ClockToSeconds(clock)
|
||||||
|
|
||||||
-- Nil check.
|
-- Nil check.
|
||||||
if clock==nil then
|
if clock==nil then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Seconds init.
|
-- Seconds init.
|
||||||
local seconds=0
|
local seconds=0
|
||||||
|
|
||||||
-- Split additional days.
|
-- Split additional days.
|
||||||
local dsplit=UTILS.Split(clock, "+")
|
local dsplit=UTILS.Split(clock, "+")
|
||||||
|
|
||||||
-- Convert days to seconds.
|
-- Convert days to seconds.
|
||||||
if #dsplit>1 then
|
if #dsplit>1 then
|
||||||
seconds=seconds+tonumber(dsplit[2])*60*60*24
|
seconds=seconds+tonumber(dsplit[2])*60*60*24
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Split hours, minutes, seconds
|
-- Split hours, minutes, seconds
|
||||||
local tsplit=UTILS.Split(dsplit[1], ":")
|
local tsplit=UTILS.Split(dsplit[1], ":")
|
||||||
|
|
||||||
-- Get time in seconds
|
-- Get time in seconds
|
||||||
@@ -856,7 +872,7 @@ function UTILS.ClockToSeconds(clock)
|
|||||||
end
|
end
|
||||||
i=i+1
|
i=i+1
|
||||||
end
|
end
|
||||||
|
|
||||||
return seconds
|
return seconds
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -868,12 +884,12 @@ function UTILS.DisplayMissionTime(duration)
|
|||||||
local mission_time=Tnow-timer.getTime0()
|
local mission_time=Tnow-timer.getTime0()
|
||||||
local mission_time_minutes=mission_time/60
|
local mission_time_minutes=mission_time/60
|
||||||
local mission_time_seconds=mission_time%60
|
local mission_time_seconds=mission_time%60
|
||||||
local local_time=UTILS.SecondsToClock(Tnow)
|
local local_time=UTILS.SecondsToClock(Tnow)
|
||||||
local text=string.format("Time: %s - %02d:%02d", local_time, mission_time_minutes, mission_time_seconds)
|
local text=string.format("Time: %s - %02d:%02d", local_time, mission_time_minutes, mission_time_seconds)
|
||||||
MESSAGE:New(text, duration):ToAll()
|
MESSAGE:New(text, duration):ToAll()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Replace illegal characters [<>|/?*:\\] in a string.
|
--- Replace illegal characters [<>|/?*:\\] in a string.
|
||||||
-- @param #string Text Input text.
|
-- @param #string Text Input text.
|
||||||
-- @param #string ReplaceBy Replace illegal characters by this character or string. Default underscore "_".
|
-- @param #string ReplaceBy Replace illegal characters by this character or string. Default underscore "_".
|
||||||
-- @return #string The input text with illegal chars replaced.
|
-- @return #string The input text with illegal chars replaced.
|
||||||
@@ -894,28 +910,28 @@ function UTILS.RandomGaussian(x0, sigma, xmin, xmax, imax)
|
|||||||
|
|
||||||
-- Standard deviation. Default 10 if not given.
|
-- Standard deviation. Default 10 if not given.
|
||||||
sigma=sigma or 10
|
sigma=sigma or 10
|
||||||
|
|
||||||
-- Max attempts.
|
-- Max attempts.
|
||||||
imax=imax or 100
|
imax=imax or 100
|
||||||
|
|
||||||
local r
|
local r
|
||||||
local gotit=false
|
local gotit=false
|
||||||
local i=0
|
local i=0
|
||||||
while not gotit do
|
while not gotit do
|
||||||
|
|
||||||
-- Uniform numbers in [0,1). We need two.
|
-- Uniform numbers in [0,1). We need two.
|
||||||
local x1=math.random()
|
local x1=math.random()
|
||||||
local x2=math.random()
|
local x2=math.random()
|
||||||
|
|
||||||
-- Transform to Gaussian exp(-(x-x0)²/(2*sigma²).
|
-- Transform to Gaussian exp(-(x-x0)°/(2*sigma°).
|
||||||
r = math.sqrt(-2*sigma*sigma * math.log(x1)) * math.cos(2*math.pi * x2) + x0
|
r = math.sqrt(-2*sigma*sigma * math.log(x1)) * math.cos(2*math.pi * x2) + x0
|
||||||
|
|
||||||
i=i+1
|
i=i+1
|
||||||
if (r>=xmin and r<=xmax) or i>imax then
|
if (r>=xmin and r<=xmax) or i>imax then
|
||||||
gotit=true
|
gotit=true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -940,9 +956,9 @@ function UTILS.Randomize(value, fac, lower, upper)
|
|||||||
else
|
else
|
||||||
max=value+value*fac
|
max=value+value*fac
|
||||||
end
|
end
|
||||||
|
|
||||||
local r=math.random(min, max)
|
local r=math.random(min, max)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -961,6 +977,33 @@ function UTILS.VecNorm(a)
|
|||||||
return math.sqrt(UTILS.VecDot(a, a))
|
return math.sqrt(UTILS.VecDot(a, a))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Calculate the distance between two 2D vectors.
|
||||||
|
-- @param DCS#Vec2 a Vector in 3D with x, y components.
|
||||||
|
-- @param DCS#Vec2 b Vector in 3D with x, y components.
|
||||||
|
-- @return #number Distance between the vectors.
|
||||||
|
function UTILS.VecDist2D(a, b)
|
||||||
|
|
||||||
|
local c={x=b.x-a.x, y=b.y-a.y}
|
||||||
|
|
||||||
|
local d=math.sqrt(c.x*c.x+c.y*c.y)
|
||||||
|
|
||||||
|
return d
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Calculate the distance between two 3D vectors.
|
||||||
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
|
-- @return #number Distance between the vectors.
|
||||||
|
function UTILS.VecDist3D(a, b)
|
||||||
|
|
||||||
|
local c={x=b.x-a.x, y=b.y-a.y, z=b.z-a.z}
|
||||||
|
|
||||||
|
local d=math.sqrt(UTILS.VecDot(c, c))
|
||||||
|
|
||||||
|
return d
|
||||||
|
end
|
||||||
|
|
||||||
--- Calculate the [cross product](https://en.wikipedia.org/wiki/Cross_product) of two 3D vectors. The result is a 3D vector.
|
--- Calculate the [cross product](https://en.wikipedia.org/wiki/Cross_product) of two 3D vectors. The result is a 3D vector.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
@@ -969,7 +1012,7 @@ function UTILS.VecCross(a, b)
|
|||||||
return {x=a.y*b.z - a.z*b.y, y=a.z*b.x - a.x*b.z, z=a.x*b.y - a.y*b.x}
|
return {x=a.y*b.z - a.z*b.y, y=a.z*b.x - a.x*b.z, z=a.x*b.y - a.y*b.x}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Calculate the difference between two 3D vectors by substracting the x,y,z components from each other.
|
--- Calculate the difference between two 3D vectors by substracting the x,y,z components from each other.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
-- @return DCS#Vec3 Vector c=a-b with c(i)=a(i)-b(i), i=x,y,z.
|
-- @return DCS#Vec3 Vector c=a-b with c(i)=a(i)-b(i), i=x,y,z.
|
||||||
@@ -977,7 +1020,7 @@ function UTILS.VecSubstract(a, b)
|
|||||||
return {x=a.x-b.x, y=a.y-b.y, z=a.z-b.z}
|
return {x=a.x-b.x, y=a.y-b.y, z=a.z-b.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Calculate the total vector of two 3D vectors by adding the x,y,z components of each other.
|
--- Calculate the total vector of two 3D vectors by adding the x,y,z components of each other.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
-- @return DCS#Vec3 Vector c=a+b with c(i)=a(i)+b(i), i=x,y,z.
|
-- @return DCS#Vec3 Vector c=a+b with c(i)=a(i)+b(i), i=x,y,z.
|
||||||
@@ -985,14 +1028,14 @@ function UTILS.VecAdd(a, b)
|
|||||||
return {x=a.x+b.x, y=a.y+b.y, z=a.z+b.z}
|
return {x=a.x+b.x, y=a.y+b.y, z=a.z+b.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Calculate the angle between two 3D vectors.
|
--- Calculate the angle between two 3D vectors.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
-- @return #number Angle alpha between and b in degrees. alpha=acos(a*b)/(|a||b|), (* denotes the dot product).
|
-- @return #number Angle alpha between and b in degrees. alpha=acos(a*b)/(|a||b|), (* denotes the dot product).
|
||||||
function UTILS.VecAngle(a, b)
|
function UTILS.VecAngle(a, b)
|
||||||
|
|
||||||
local cosalpha=UTILS.VecDot(a,b)/(UTILS.VecNorm(a)*UTILS.VecNorm(b))
|
local cosalpha=UTILS.VecDot(a,b)/(UTILS.VecNorm(a)*UTILS.VecNorm(b))
|
||||||
|
|
||||||
local alpha=0
|
local alpha=0
|
||||||
if cosalpha>=0.9999999999 then --acos(1) is not defined.
|
if cosalpha>=0.9999999999 then --acos(1) is not defined.
|
||||||
alpha=0
|
alpha=0
|
||||||
@@ -1000,8 +1043,8 @@ function UTILS.VecAngle(a, b)
|
|||||||
alpha=math.pi
|
alpha=math.pi
|
||||||
else
|
else
|
||||||
alpha=math.acos(cosalpha)
|
alpha=math.acos(cosalpha)
|
||||||
end
|
end
|
||||||
|
|
||||||
return math.deg(alpha)
|
return math.deg(alpha)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1025,18 +1068,18 @@ function UTILS.HdgDiff(h1, h2)
|
|||||||
-- Angle in rad.
|
-- Angle in rad.
|
||||||
local alpha= math.rad(tonumber(h1))
|
local alpha= math.rad(tonumber(h1))
|
||||||
local beta = math.rad(tonumber(h2))
|
local beta = math.rad(tonumber(h2))
|
||||||
|
|
||||||
-- Runway vector.
|
-- Runway vector.
|
||||||
local v1={x=math.cos(alpha), y=0, z=math.sin(alpha)}
|
local v1={x=math.cos(alpha), y=0, z=math.sin(alpha)}
|
||||||
local v2={x=math.cos(beta), y=0, z=math.sin(beta)}
|
local v2={x=math.cos(beta), y=0, z=math.sin(beta)}
|
||||||
|
|
||||||
local delta=UTILS.VecAngle(v1, v2)
|
local delta=UTILS.VecAngle(v1, v2)
|
||||||
|
|
||||||
return math.abs(delta)
|
return math.abs(delta)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Translate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged.
|
--- Translate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param #number distance The distance to translate.
|
-- @param #number distance The distance to translate.
|
||||||
-- @param #number angle Rotation angle in degrees.
|
-- @param #number angle Rotation angle in degrees.
|
||||||
@@ -1052,21 +1095,21 @@ function UTILS.VecTranslate(a, distance, angle)
|
|||||||
return {x=TX, y=a.y, z=TY}
|
return {x=TX, y=a.y, z=TY}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Rotate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged.
|
--- Rotate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param #number angle Rotation angle in degrees.
|
-- @param #number angle Rotation angle in degrees.
|
||||||
-- @return DCS#Vec3 Vector rotated in the (x,z) plane.
|
-- @return DCS#Vec3 Vector rotated in the (x,z) plane.
|
||||||
function UTILS.Rotate2D(a, angle)
|
function UTILS.Rotate2D(a, angle)
|
||||||
|
|
||||||
local phi=math.rad(angle)
|
local phi=math.rad(angle)
|
||||||
|
|
||||||
local x=a.z
|
local x=a.z
|
||||||
local y=a.x
|
local y=a.x
|
||||||
|
|
||||||
local Z=x*math.cos(phi)-y*math.sin(phi)
|
local Z=x*math.cos(phi)-y*math.sin(phi)
|
||||||
local X=x*math.sin(phi)+y*math.cos(phi)
|
local X=x*math.sin(phi)+y*math.cos(phi)
|
||||||
local Y=a.y
|
local Y=a.y
|
||||||
|
|
||||||
local A={x=X, y=Y, z=Z}
|
local A={x=X, y=Y, z=Z}
|
||||||
|
|
||||||
return A
|
return A
|
||||||
@@ -1084,17 +1127,17 @@ function UTILS.TACANToFrequency(TACANChannel, TACANMode)
|
|||||||
end
|
end
|
||||||
if TACANMode ~= "X" and TACANMode ~= "Y" then
|
if TACANMode ~= "X" and TACANMode ~= "Y" then
|
||||||
return nil -- error in arguments
|
return nil -- error in arguments
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
||||||
-- I have no idea what it does but it seems to work
|
-- I have no idea what it does but it seems to work
|
||||||
local A = 1151 -- 'X', channel >= 64
|
local A = 1151 -- 'X', channel >= 64
|
||||||
local B = 64 -- channel >= 64
|
local B = 64 -- channel >= 64
|
||||||
|
|
||||||
if TACANChannel < 64 then
|
if TACANChannel < 64 then
|
||||||
B = 1
|
B = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if TACANMode == 'Y' then
|
if TACANMode == 'Y' then
|
||||||
A = 1025
|
A = 1025
|
||||||
if TACANChannel < 64 then
|
if TACANChannel < 64 then
|
||||||
@@ -1105,7 +1148,7 @@ function UTILS.TACANToFrequency(TACANChannel, TACANMode)
|
|||||||
A = 962
|
A = 962
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return (A + TACANChannel - B) * 1000000
|
return (A + TACANChannel - B) * 1000000
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1132,13 +1175,13 @@ end
|
|||||||
-- @param #number Time (Optional) Abs. time in seconds. Default now, i.e. the value return from timer.getAbsTime().
|
-- @param #number Time (Optional) Abs. time in seconds. Default now, i.e. the value return from timer.getAbsTime().
|
||||||
-- @return #number Day of the mission. Mission starts on day 0.
|
-- @return #number Day of the mission. Mission starts on day 0.
|
||||||
function UTILS.GetMissionDay(Time)
|
function UTILS.GetMissionDay(Time)
|
||||||
|
|
||||||
Time=Time or timer.getAbsTime()
|
Time=Time or timer.getAbsTime()
|
||||||
|
|
||||||
local clock=UTILS.SecondsToClock(Time, false)
|
local clock=UTILS.SecondsToClock(Time, false)
|
||||||
|
|
||||||
local x=tonumber(UTILS.Split(clock, "+")[2])
|
local x=tonumber(UTILS.Split(clock, "+")[2])
|
||||||
|
|
||||||
return x
|
return x
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1148,11 +1191,11 @@ end
|
|||||||
function UTILS.GetMissionDayOfYear(Time)
|
function UTILS.GetMissionDayOfYear(Time)
|
||||||
|
|
||||||
local Date, Year, Month, Day=UTILS.GetDCSMissionDate()
|
local Date, Year, Month, Day=UTILS.GetDCSMissionDate()
|
||||||
|
|
||||||
local d=UTILS.GetMissionDay(Time)
|
local d=UTILS.GetMissionDay(Time)
|
||||||
|
|
||||||
return UTILS.GetDayOfYear(Year, Month, Day)+d
|
return UTILS.GetDayOfYear(Year, Month, Day)+d
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the current date.
|
--- Returns the current date.
|
||||||
@@ -1164,20 +1207,20 @@ function UTILS.GetDate()
|
|||||||
|
|
||||||
-- Mission start date
|
-- Mission start date
|
||||||
local date, year, month, day=UTILS.GetDCSMissionDate()
|
local date, year, month, day=UTILS.GetDCSMissionDate()
|
||||||
|
|
||||||
local time=timer.getAbsTime()
|
local time=timer.getAbsTime()
|
||||||
|
|
||||||
local clock=UTILS.SecondsToClock(time, false)
|
local clock=UTILS.SecondsToClock(time, false)
|
||||||
|
|
||||||
local x=tonumber(UTILS.Split(clock, "+")[2])
|
local x=tonumber(UTILS.Split(clock, "+")[2])
|
||||||
|
|
||||||
local day=day+x
|
local day=day+x
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the magnetic declination of the map.
|
--- Returns the magnetic declination of the map.
|
||||||
-- Returned values for the current maps are:
|
-- Returned values for the current maps are:
|
||||||
--
|
--
|
||||||
-- * Caucasus +6 (East), year ~ 2011
|
-- * Caucasus +6 (East), year ~ 2011
|
||||||
-- * NTTR +12 (East), year ~ 2011
|
-- * NTTR +12 (East), year ~ 2011
|
||||||
-- * Normandy -10 (West), year ~ 1944
|
-- * Normandy -10 (West), year ~ 1944
|
||||||
@@ -1191,7 +1234,7 @@ function UTILS.GetMagneticDeclination(map)
|
|||||||
|
|
||||||
-- Map.
|
-- Map.
|
||||||
map=map or UTILS.GetDCSMap()
|
map=map or UTILS.GetDCSMap()
|
||||||
|
|
||||||
local declination=0
|
local declination=0
|
||||||
if map==DCSMAP.Caucasus then
|
if map==DCSMAP.Caucasus then
|
||||||
declination=6
|
declination=6
|
||||||
@@ -1228,12 +1271,12 @@ function UTILS.FileExists(file)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Checks the current memory usage collectgarbage("count"). Info is printed to the DCS log file. Time stamp is the current mission runtime.
|
--- Checks the current memory usage collectgarbage("count"). Info is printed to the DCS log file. Time stamp is the current mission runtime.
|
||||||
-- @param #boolean output If true, print to DCS log file.
|
-- @param #boolean output If true, print to DCS log file.
|
||||||
-- @return #number Memory usage in kByte.
|
-- @return #number Memory usage in kByte.
|
||||||
function UTILS.CheckMemory(output)
|
function UTILS.CheckMemory(output)
|
||||||
local time=timer.getTime()
|
local time=timer.getTime()
|
||||||
local clock=UTILS.SecondsToClock(time)
|
local clock=UTILS.SecondsToClock(time)
|
||||||
@@ -1263,7 +1306,7 @@ function UTILS.GetCoalitionName(Coalition)
|
|||||||
else
|
else
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the modulation name from its numerical value.
|
--- Get the modulation name from its numerical value.
|
||||||
@@ -1282,7 +1325,7 @@ function UTILS.GetModulationName(Modulation)
|
|||||||
else
|
else
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the callsign name from its enumerator value
|
--- Get the callsign name from its enumerator value
|
||||||
@@ -1295,7 +1338,7 @@ function UTILS.GetCallsignName(Callsign)
|
|||||||
return name
|
return name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for name, value in pairs(CALLSIGN.AWACS) do
|
for name, value in pairs(CALLSIGN.AWACS) do
|
||||||
if value==Callsign then
|
if value==Callsign then
|
||||||
return name
|
return name
|
||||||
@@ -1307,7 +1350,7 @@ function UTILS.GetCallsignName(Callsign)
|
|||||||
return name
|
return name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for name, value in pairs(CALLSIGN.Tanker) do
|
for name, value in pairs(CALLSIGN.Tanker) do
|
||||||
if value==Callsign then
|
if value==Callsign then
|
||||||
return name
|
return name
|
||||||
@@ -1336,7 +1379,7 @@ function UTILS.GMTToLocalTimeDifference()
|
|||||||
elseif theatre==DCSMAP.Syria then
|
elseif theatre==DCSMAP.Syria then
|
||||||
return 3 -- Damascus is UTC+3 hours
|
return 3 -- Damascus is UTC+3 hours
|
||||||
elseif theatre==DCSMAP.MarianaIslands then
|
elseif theatre==DCSMAP.MarianaIslands then
|
||||||
return 10 -- Guam is UTC+10 hours.
|
return 10 -- Guam is UTC+10 hours.
|
||||||
else
|
else
|
||||||
BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre)))
|
BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre)))
|
||||||
return 0
|
return 0
|
||||||
@@ -1353,11 +1396,11 @@ end
|
|||||||
function UTILS.GetDayOfYear(Year, Month, Day)
|
function UTILS.GetDayOfYear(Year, Month, Day)
|
||||||
|
|
||||||
local floor = math.floor
|
local floor = math.floor
|
||||||
|
|
||||||
local n1 = floor(275 * Month / 9)
|
local n1 = floor(275 * Month / 9)
|
||||||
local n2 = floor((Month + 9) / 12)
|
local n2 = floor((Month + 9) / 12)
|
||||||
local n3 = (1 + floor((Year - 4 * floor(Year / 4) + 2) / 3))
|
local n3 = (1 + floor((Year - 4 * floor(Year / 4) + 2) / 3))
|
||||||
|
|
||||||
return n1 - (n2 * n3) + Day - 30
|
return n1 - (n2 * n3) + Day - 30
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1370,14 +1413,14 @@ end
|
|||||||
-- @return #number Sun rise/set in seconds of the day.
|
-- @return #number Sun rise/set in seconds of the day.
|
||||||
function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal)
|
function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal)
|
||||||
|
|
||||||
-- Defaults
|
-- Defaults
|
||||||
local zenith=90.83
|
local zenith=90.83
|
||||||
local latitude=Latitude
|
local latitude=Latitude
|
||||||
local longitude=Longitude
|
local longitude=Longitude
|
||||||
local rising=Rising
|
local rising=Rising
|
||||||
local n=DayOfYear
|
local n=DayOfYear
|
||||||
Tlocal=Tlocal or 0
|
Tlocal=Tlocal or 0
|
||||||
|
|
||||||
|
|
||||||
-- Short cuts.
|
-- Short cuts.
|
||||||
local rad = math.rad
|
local rad = math.rad
|
||||||
@@ -1404,47 +1447,47 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal)
|
|||||||
return val
|
return val
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Convert the longitude to hour value and calculate an approximate time
|
-- Convert the longitude to hour value and calculate an approximate time
|
||||||
local lng_hour = longitude / 15
|
local lng_hour = longitude / 15
|
||||||
|
|
||||||
local t
|
local t
|
||||||
if rising then -- Rising time is desired
|
if rising then -- Rising time is desired
|
||||||
t = n + ((6 - lng_hour) / 24)
|
t = n + ((6 - lng_hour) / 24)
|
||||||
else -- Setting time is desired
|
else -- Setting time is desired
|
||||||
t = n + ((18 - lng_hour) / 24)
|
t = n + ((18 - lng_hour) / 24)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Calculate the Sun's mean anomaly
|
-- Calculate the Sun's mean anomaly
|
||||||
local M = (0.9856 * t) - 3.289
|
local M = (0.9856 * t) - 3.289
|
||||||
|
|
||||||
-- Calculate the Sun's true longitude
|
-- Calculate the Sun's true longitude
|
||||||
local L = fit_into_range(M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634, 0, 360)
|
local L = fit_into_range(M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634, 0, 360)
|
||||||
|
|
||||||
-- Calculate the Sun's right ascension
|
-- Calculate the Sun's right ascension
|
||||||
local RA = fit_into_range(atan(0.91764 * tan(L)), 0, 360)
|
local RA = fit_into_range(atan(0.91764 * tan(L)), 0, 360)
|
||||||
|
|
||||||
-- Right ascension value needs to be in the same quadrant as L
|
-- Right ascension value needs to be in the same quadrant as L
|
||||||
local Lquadrant = floor(L / 90) * 90
|
local Lquadrant = floor(L / 90) * 90
|
||||||
local RAquadrant = floor(RA / 90) * 90
|
local RAquadrant = floor(RA / 90) * 90
|
||||||
RA = RA + Lquadrant - RAquadrant
|
RA = RA + Lquadrant - RAquadrant
|
||||||
|
|
||||||
-- Right ascension value needs to be converted into hours
|
-- Right ascension value needs to be converted into hours
|
||||||
RA = RA / 15
|
RA = RA / 15
|
||||||
|
|
||||||
-- Calculate the Sun's declination
|
-- Calculate the Sun's declination
|
||||||
local sinDec = 0.39782 * sin(L)
|
local sinDec = 0.39782 * sin(L)
|
||||||
local cosDec = cos(asin(sinDec))
|
local cosDec = cos(asin(sinDec))
|
||||||
|
|
||||||
-- Calculate the Sun's local hour angle
|
-- Calculate the Sun's local hour angle
|
||||||
local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude))
|
local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude))
|
||||||
|
|
||||||
if rising and cosH > 1 then
|
if rising and cosH > 1 then
|
||||||
return "N/R" -- The sun never rises on this location on the specified date
|
return "N/R" -- The sun never rises on this location on the specified date
|
||||||
elseif cosH < -1 then
|
elseif cosH < -1 then
|
||||||
return "N/S" -- The sun never sets on this location on the specified date
|
return "N/S" -- The sun never sets on this location on the specified date
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Finish calculating H and convert into hours
|
-- Finish calculating H and convert into hours
|
||||||
local H
|
local H
|
||||||
if rising then
|
if rising then
|
||||||
@@ -1453,13 +1496,13 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal)
|
|||||||
H = acos(cosH)
|
H = acos(cosH)
|
||||||
end
|
end
|
||||||
H = H / 15
|
H = H / 15
|
||||||
|
|
||||||
-- Calculate local mean time of rising/setting
|
-- Calculate local mean time of rising/setting
|
||||||
local T = H + RA - (0.06571 * t) - 6.622
|
local T = H + RA - (0.06571 * t) - 6.622
|
||||||
|
|
||||||
-- Adjust back to UTC
|
-- Adjust back to UTC
|
||||||
local UT = fit_into_range(T - lng_hour +Tlocal, 0, 24)
|
local UT = fit_into_range(T - lng_hour +Tlocal, 0, 24)
|
||||||
|
|
||||||
return floor(UT)*60*60+frac(UT)*60*60--+Tlocal*60*60
|
return floor(UT)*60*60+frac(UT)*60*60--+Tlocal*60*60
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1534,17 +1577,17 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
|||||||
local unit = Unit.getByName(unit_name)
|
local unit = Unit.getByName(unit_name)
|
||||||
if unit ~= nil then
|
if unit ~= nil then
|
||||||
local type_name = unit:getTypeName()
|
local type_name = unit:getTypeName()
|
||||||
|
|
||||||
if type_name == "Mi-8MT" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 or unit:getDrawArgumentValue(250) == 1 then
|
if type_name == "Mi-8MT" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 or unit:getDrawArgumentValue(250) < 0 then
|
||||||
BASE:T(unit_name .. " Cargo doors are open or cargo door not present")
|
BASE:T(unit_name .. " Cargo doors are open or cargo door not present")
|
||||||
ret_val = true
|
ret_val = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if type_name == "Mi-24P" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 then
|
if type_name == "Mi-24P" and unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 then
|
||||||
BASE:T(unit_name .. " a side door is open")
|
BASE:T(unit_name .. " a side door is open")
|
||||||
ret_val = true
|
ret_val = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if type_name == "UH-1H" and unit:getDrawArgumentValue(43) == 1 or unit:getDrawArgumentValue(44) == 1 then
|
if type_name == "UH-1H" and unit:getDrawArgumentValue(43) == 1 or unit:getDrawArgumentValue(44) == 1 then
|
||||||
BASE:T(unit_name .. " a side door is open ")
|
BASE:T(unit_name .. " a side door is open ")
|
||||||
ret_val = true
|
ret_val = true
|
||||||
@@ -1555,13 +1598,33 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
|||||||
ret_val = true
|
ret_val = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if string.find(type_name, "Hercules") and unit:getDrawArgumentValue(1215) == 1 and unit:getDrawArgumentValue(1216) == 1 then
|
||||||
|
BASE:T(unit_name .. " rear doors are open")
|
||||||
|
ret_val = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1220) == 1 or unit:getDrawArgumentValue(1221) == 1) then
|
||||||
|
BASE:T(unit_name .. " para doors are open")
|
||||||
|
ret_val = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if string.find(type_name, "Hercules") and unit:getDrawArgumentValue(1217) == 1 then
|
||||||
|
BASE:T(unit_name .. " side door is open")
|
||||||
|
ret_val = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if string.find(type_name, "Bell-47") then -- bell aint got no doors so always ready to load injured soldiers
|
||||||
|
BASE:T(unit_name .. " door is open")
|
||||||
|
ret_val = true
|
||||||
|
end
|
||||||
|
|
||||||
if ret_val == false then
|
if ret_val == false then
|
||||||
BASE:T(unit_name .. " all doors are closed")
|
BASE:T(unit_name .. " all doors are closed")
|
||||||
end
|
end
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
end -- nil
|
end -- nil
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1588,10 +1651,10 @@ function UTILS.GenerateVHFrequencies()
|
|||||||
local _skipFrequencies = {
|
local _skipFrequencies = {
|
||||||
214,274,291.5,295,297.5,
|
214,274,291.5,295,297.5,
|
||||||
300.5,304,307,309.5,311,312,312.5,316,
|
300.5,304,307,309.5,311,312,312.5,316,
|
||||||
320,324,328,329,330,336,337,
|
320,324,328,329,330,332,336,337,
|
||||||
342,343,348,351,352,353,358,
|
342,343,348,351,352,353,358,
|
||||||
363,365,368,372.5,374,
|
363,365,368,372.5,374,
|
||||||
380,381,384,389,395,396,
|
380,381,384,385,389,395,396,
|
||||||
414,420,430,432,435,440,450,455,462,470,485,
|
414,420,430,432,435,440,450,455,462,470,485,
|
||||||
507,515,520,525,528,540,550,560,570,577,580,
|
507,515,520,525,528,540,550,560,570,577,580,
|
||||||
602,625,641,662,670,680,682,690,
|
602,625,641,662,670,680,682,690,
|
||||||
@@ -1600,13 +1663,13 @@ function UTILS.GenerateVHFrequencies()
|
|||||||
905,907,920,935,942,950,995,
|
905,907,920,935,942,950,995,
|
||||||
1000,1025,1030,1050,1065,1116,1175,1182,1210
|
1000,1025,1030,1050,1065,1116,1175,1182,1210
|
||||||
}
|
}
|
||||||
|
|
||||||
local FreeVHFFrequencies = {}
|
local FreeVHFFrequencies = {}
|
||||||
|
|
||||||
-- first range
|
-- first range
|
||||||
local _start = 200000
|
local _start = 200000
|
||||||
while _start < 400000 do
|
while _start < 400000 do
|
||||||
|
|
||||||
-- skip existing NDB frequencies#
|
-- skip existing NDB frequencies#
|
||||||
local _found = false
|
local _found = false
|
||||||
for _, value in pairs(_skipFrequencies) do
|
for _, value in pairs(_skipFrequencies) do
|
||||||
@@ -1620,7 +1683,7 @@ function UTILS.GenerateVHFrequencies()
|
|||||||
end
|
end
|
||||||
_start = _start + 10000
|
_start = _start + 10000
|
||||||
end
|
end
|
||||||
|
|
||||||
-- second range
|
-- second range
|
||||||
_start = 400000
|
_start = 400000
|
||||||
while _start < 850000 do
|
while _start < 850000 do
|
||||||
@@ -1637,7 +1700,7 @@ function UTILS.GenerateVHFrequencies()
|
|||||||
end
|
end
|
||||||
_start = _start + 10000
|
_start = _start + 10000
|
||||||
end
|
end
|
||||||
|
|
||||||
-- third range
|
-- third range
|
||||||
_start = 850000
|
_start = 850000
|
||||||
while _start <= 999000 do -- adjusted for Gazelle
|
while _start <= 999000 do -- adjusted for Gazelle
|
||||||
@@ -1677,7 +1740,7 @@ end
|
|||||||
-- @return #table Laser Codes.
|
-- @return #table Laser Codes.
|
||||||
function UTILS.GenerateLaserCodes()
|
function UTILS.GenerateLaserCodes()
|
||||||
local jtacGeneratedLaserCodes = {}
|
local jtacGeneratedLaserCodes = {}
|
||||||
|
|
||||||
-- helper function
|
-- helper function
|
||||||
local function ContainsDigit(_number, _numberToFind)
|
local function ContainsDigit(_number, _numberToFind)
|
||||||
local _thisNumber = _number
|
local _thisNumber = _number
|
||||||
@@ -1691,14 +1754,14 @@ function UTILS.GenerateLaserCodes()
|
|||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- generate list of laser codes
|
-- generate list of laser codes
|
||||||
local _code = 1111
|
local _code = 1111
|
||||||
local _count = 1
|
local _count = 1
|
||||||
while _code < 1777 and _count < 30 do
|
while _code < 1777 and _count < 30 do
|
||||||
while true do
|
while true do
|
||||||
_code = _code + 1
|
_code = _code + 1
|
||||||
if not self:_ContainsDigit(_code, 8)
|
if not ContainsDigit(_code, 8)
|
||||||
and not ContainsDigit(_code, 9)
|
and not ContainsDigit(_code, 9)
|
||||||
and not ContainsDigit(_code, 0) then
|
and not ContainsDigit(_code, 0) then
|
||||||
table.insert(jtacGeneratedLaserCodes, _code)
|
table.insert(jtacGeneratedLaserCodes, _code)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
-- @field #table CategoryName Names of airbase categories.
|
-- @field #table CategoryName Names of airbase categories.
|
||||||
-- @field #string AirbaseName Name of the airbase.
|
-- @field #string AirbaseName Name of the airbase.
|
||||||
-- @field #number AirbaseID Airbase ID.
|
-- @field #number AirbaseID Airbase ID.
|
||||||
|
-- @field Core.Zone#ZONE AirbaseZone Circular zone around the airbase with a radius of 2500 meters. For ships this is a ZONE_UNIT object.
|
||||||
-- @field #number category Airbase category.
|
-- @field #number category Airbase category.
|
||||||
-- @field #table descriptors DCS descriptors.
|
-- @field #table descriptors DCS descriptors.
|
||||||
-- @field #boolean isAirdrome Airbase is an airdrome.
|
-- @field #boolean isAirdrome Airbase is an airdrome.
|
||||||
@@ -526,19 +527,19 @@ function AIRBASE:Register(AirbaseName)
|
|||||||
|
|
||||||
-- Inherit everything from positionable.
|
-- Inherit everything from positionable.
|
||||||
local self=BASE:Inherit(self, POSITIONABLE:New(AirbaseName)) --#AIRBASE
|
local self=BASE:Inherit(self, POSITIONABLE:New(AirbaseName)) --#AIRBASE
|
||||||
|
|
||||||
-- Set airbase name.
|
-- Set airbase name.
|
||||||
self.AirbaseName=AirbaseName
|
self.AirbaseName=AirbaseName
|
||||||
|
|
||||||
-- Set airbase ID.
|
-- Set airbase ID.
|
||||||
self.AirbaseID=self:GetID(true)
|
self.AirbaseID=self:GetID(true)
|
||||||
|
|
||||||
-- Get descriptors.
|
-- Get descriptors.
|
||||||
self.descriptors=self:GetDesc()
|
self.descriptors=self:GetDesc()
|
||||||
|
|
||||||
-- Category.
|
-- Category.
|
||||||
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
|
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
|
||||||
|
|
||||||
-- Set category.
|
-- Set category.
|
||||||
if self.category==Airbase.Category.AIRDROME then
|
if self.category==Airbase.Category.AIRDROME then
|
||||||
self.isAirdrome=true
|
self.isAirdrome=true
|
||||||
@@ -546,20 +547,33 @@ function AIRBASE:Register(AirbaseName)
|
|||||||
self.isHelipad=true
|
self.isHelipad=true
|
||||||
elseif self.category==Airbase.Category.SHIP then
|
elseif self.category==Airbase.Category.SHIP then
|
||||||
self.isShip=true
|
self.isShip=true
|
||||||
|
-- DCS bug: Oil rigs and gas platforms have category=2 (ship). Also they cannot be retrieved by coalition.getStaticObjects()
|
||||||
|
if self.descriptors.typeName=="Oil rig" or self.descriptors.typeName=="Ga" then
|
||||||
|
self.isHelipad=true
|
||||||
|
self.isShip=false
|
||||||
|
self.category=Airbase.Category.HELIPAD
|
||||||
|
_DATABASE:AddStatic(AirbaseName)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
self:E("ERROR: Unknown airbase category!")
|
self:E("ERROR: Unknown airbase category!")
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_InitParkingSpots()
|
self:_InitParkingSpots()
|
||||||
|
|
||||||
local vec2=self:GetVec2()
|
local vec2=self:GetVec2()
|
||||||
|
|
||||||
-- Init coordinate.
|
-- Init coordinate.
|
||||||
self:GetCoordinate()
|
self:GetCoordinate()
|
||||||
|
|
||||||
if vec2 then
|
if vec2 then
|
||||||
-- TODO: For ships we need a moving zone.
|
if self.isShip then
|
||||||
self.AirbaseZone=ZONE_RADIUS:New( AirbaseName, vec2, 2500 )
|
local unit=UNIT:FindByName(AirbaseName)
|
||||||
|
if unit then
|
||||||
|
self.AirbaseZone=ZONE_UNIT:New(AirbaseName, unit, 2500)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.AirbaseZone=ZONE_RADIUS:New(AirbaseName, vec2, 2500)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
self:E(string.format("ERROR: Cound not get position Vec2 of airbase %s", AirbaseName))
|
self:E(string.format("ERROR: Cound not get position Vec2 of airbase %s", AirbaseName))
|
||||||
end
|
end
|
||||||
@@ -693,7 +707,7 @@ function AIRBASE:GetID(unique)
|
|||||||
local airbaseID=tonumber(DCSAirbase:getID())
|
local airbaseID=tonumber(DCSAirbase:getID())
|
||||||
|
|
||||||
local airbaseCategory=self:GetAirbaseCategory()
|
local airbaseCategory=self:GetAirbaseCategory()
|
||||||
|
|
||||||
if AirbaseName==self.AirbaseName then
|
if AirbaseName==self.AirbaseName then
|
||||||
if airbaseCategory==Airbase.Category.SHIP or airbaseCategory==Airbase.Category.HELIPAD then
|
if airbaseCategory==Airbase.Category.SHIP or airbaseCategory==Airbase.Category.HELIPAD then
|
||||||
-- Ships get a negative sign as their unit number might be the same as the ID of another airbase.
|
-- Ships get a negative sign as their unit number might be the same as the ID of another airbase.
|
||||||
@@ -932,16 +946,16 @@ function AIRBASE:_InitParkingSpots()
|
|||||||
-- Init table.
|
-- Init table.
|
||||||
self.parking={}
|
self.parking={}
|
||||||
self.parkingByID={}
|
self.parkingByID={}
|
||||||
|
|
||||||
self.NparkingTotal=0
|
self.NparkingTotal=0
|
||||||
self.NparkingTerminal={}
|
self.NparkingTerminal={}
|
||||||
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
||||||
self.NparkingTerminal[terminalType]=0
|
self.NparkingTerminal[terminalType]=0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Put coordinates of parking spots into table.
|
-- Put coordinates of parking spots into table.
|
||||||
for _,spot in pairs(parkingdata) do
|
for _,spot in pairs(parkingdata) do
|
||||||
|
|
||||||
-- New parking spot.
|
-- New parking spot.
|
||||||
local park={} --#AIRBASE.ParkingSpot
|
local park={} --#AIRBASE.ParkingSpot
|
||||||
park.Vec3=spot.vTerminalPos
|
park.Vec3=spot.vTerminalPos
|
||||||
@@ -952,15 +966,15 @@ function AIRBASE:_InitParkingSpots()
|
|||||||
park.TerminalID0=spot.Term_Index_0
|
park.TerminalID0=spot.Term_Index_0
|
||||||
park.TerminalType=spot.Term_Type
|
park.TerminalType=spot.Term_Type
|
||||||
park.TOAC=spot.TO_AC
|
park.TOAC=spot.TO_AC
|
||||||
|
|
||||||
self.NparkingTotal=self.NparkingTotal+1
|
self.NparkingTotal=self.NparkingTotal+1
|
||||||
|
|
||||||
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
||||||
if self._CheckTerminalType(terminalType, park.TerminalType) then
|
if self._CheckTerminalType(terminalType, park.TerminalType) then
|
||||||
self.NparkingTerminal[terminalType]=self.NparkingTerminal[terminalType]+1
|
self.NparkingTerminal[terminalType]=self.NparkingTerminal[terminalType]+1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.parkingByID[park.TerminalID]=park
|
self.parkingByID[park.TerminalID]=park
|
||||||
table.insert(self.parking, park)
|
table.insert(self.parking, park)
|
||||||
end
|
end
|
||||||
@@ -984,7 +998,7 @@ function AIRBASE:GetParkingSpotsTable(termtype)
|
|||||||
|
|
||||||
-- Get parking data of all spots (free or occupied)
|
-- Get parking data of all spots (free or occupied)
|
||||||
local parkingdata=self:GetParkingData(false)
|
local parkingdata=self:GetParkingData(false)
|
||||||
|
|
||||||
-- Get parking data of all free spots.
|
-- Get parking data of all free spots.
|
||||||
local parkingfree=self:GetParkingData(true)
|
local parkingfree=self:GetParkingData(true)
|
||||||
|
|
||||||
@@ -1001,17 +1015,26 @@ function AIRBASE:GetParkingSpotsTable(termtype)
|
|||||||
-- Put coordinates of parking spots into table.
|
-- Put coordinates of parking spots into table.
|
||||||
local spots={}
|
local spots={}
|
||||||
for _,_spot in pairs(parkingdata) do
|
for _,_spot in pairs(parkingdata) do
|
||||||
|
|
||||||
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then
|
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) then
|
||||||
|
|
||||||
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
|
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
|
||||||
|
|
||||||
spot.Free=_isfree(_spot) -- updated
|
if spot then
|
||||||
spot.TOAC=_spot.TO_AC -- updated
|
|
||||||
|
spot.Free=_isfree(_spot) -- updated
|
||||||
table.insert(spots, spot)
|
spot.TOAC=_spot.TO_AC -- updated
|
||||||
|
|
||||||
|
table.insert(spots, spot)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
self:E(string.format("ERROR: Parking spot %s is nil!", tostring(_spot.Term_Index)))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return spots
|
return spots
|
||||||
@@ -1032,14 +1055,14 @@ function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC)
|
|||||||
for _,_spot in pairs(parkingfree) do
|
for _,_spot in pairs(parkingfree) do
|
||||||
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) and _spot.Term_Index>0 then
|
if AIRBASE._CheckTerminalType(_spot.Term_Type, termtype) and _spot.Term_Index>0 then
|
||||||
if (allowTOAC and allowTOAC==true) or _spot.TO_AC==false then
|
if (allowTOAC and allowTOAC==true) or _spot.TO_AC==false then
|
||||||
|
|
||||||
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
|
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
|
||||||
|
|
||||||
spot.Free=true -- updated
|
spot.Free=true -- updated
|
||||||
spot.TOAC=_spot.TO_AC -- updated
|
spot.TOAC=_spot.TO_AC -- updated
|
||||||
|
|
||||||
table.insert(freespots, spot)
|
table.insert(freespots, spot)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1084,7 +1107,7 @@ function AIRBASE:MarkParkingSpots(termtype, mark)
|
|||||||
|
|
||||||
-- Get airbase name.
|
-- Get airbase name.
|
||||||
local airbasename=self:GetName()
|
local airbasename=self:GetName()
|
||||||
self:E(string.format("Parking spots at %s for termial type %s:", airbasename, tostring(termtype)))
|
self:E(string.format("Parking spots at %s for terminal type %s:", airbasename, tostring(termtype)))
|
||||||
|
|
||||||
for _,_spot in pairs(parkingdata) do
|
for _,_spot in pairs(parkingdata) do
|
||||||
|
|
||||||
@@ -1118,7 +1141,7 @@ end
|
|||||||
-- @param #table parkingdata (Optional) Parking spots data table. If not given it is automatically derived from the GetParkingSpotsTable() function.
|
-- @param #table parkingdata (Optional) Parking spots data table. If not given it is automatically derived from the GetParkingSpotsTable() function.
|
||||||
-- @return #table Table of coordinates and terminal IDs of free parking spots. Each table entry has the elements .Coordinate and .TerminalID.
|
-- @return #table Table of coordinates and terminal IDs of free parking spots. Each table entry has the elements .Coordinate and .TerminalID.
|
||||||
function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nspots, parkingdata)
|
function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nspots, parkingdata)
|
||||||
|
|
||||||
-- Init default
|
-- Init default
|
||||||
scanradius=scanradius or 50
|
scanradius=scanradius or 50
|
||||||
if scanunits==nil then
|
if scanunits==nil then
|
||||||
@@ -1161,14 +1184,25 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
parkingdata=parkingdata or self:GetParkingSpotsTable(terminaltype)
|
parkingdata=parkingdata or self:GetParkingSpotsTable(terminaltype)
|
||||||
|
|
||||||
-- Get the aircraft size, i.e. it's longest side of x,z.
|
-- Get the aircraft size, i.e. it's longest side of x,z.
|
||||||
local aircraft=group:GetUnit(1)
|
local aircraft = nil -- fix local problem below
|
||||||
local _aircraftsize, ax,ay,az=aircraft:GetObjectSize()
|
local _aircraftsize, ax,ay,az
|
||||||
|
if group and group.ClassName == "GROUP" then
|
||||||
|
aircraft=group:GetUnit(1)
|
||||||
|
_aircraftsize, ax,ay,az=aircraft:GetObjectSize()
|
||||||
|
else
|
||||||
|
-- SU27 dimensions
|
||||||
|
_aircraftsize = 23
|
||||||
|
ax = 23 -- length
|
||||||
|
ay = 7 -- height
|
||||||
|
az = 17 -- width
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Number of spots we are looking for. Note that, e.g. grouping can require a number different from the group size!
|
-- Number of spots we are looking for. Note that, e.g. grouping can require a number different from the group size!
|
||||||
local _nspots=nspots or group:GetSize()
|
local _nspots=nspots or group:GetSize()
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:E(string.format("%s: Looking for %d parking spot(s) for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at termial type %s.", airport, _nspots, _aircraftsize, ax, ay, az, tostring(terminaltype)))
|
self:E(string.format("%s: Looking for %d parking spot(s) for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at terminal type %s.", airport, _nspots, _aircraftsize, ax, ay, az, tostring(terminaltype)))
|
||||||
|
|
||||||
-- Table of valid spots.
|
-- Table of valid spots.
|
||||||
local validspots={}
|
local validspots={}
|
||||||
@@ -1291,6 +1325,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
|
|
||||||
-- Retrun spots we found, even if there were not enough.
|
-- Retrun spots we found, even if there were not enough.
|
||||||
return validspots
|
return validspots
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check black and white lists.
|
--- Check black and white lists.
|
||||||
@@ -1392,7 +1427,7 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
|
|
||||||
-- Get spawn points on runway. These can be used to determine the runway heading.
|
-- Get spawn points on runway. These can be used to determine the runway heading.
|
||||||
local runwaycoords=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
|
local runwaycoords=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
|
||||||
|
|
||||||
-- Debug: For finding the numbers of the spawn points belonging to each runway.
|
-- Debug: For finding the numbers of the spawn points belonging to each runway.
|
||||||
if false then
|
if false then
|
||||||
for i,_coord in pairs(runwaycoords) do
|
for i,_coord in pairs(runwaycoords) do
|
||||||
@@ -1411,7 +1446,7 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
|
|
||||||
-- Airbase name.
|
-- Airbase name.
|
||||||
local name=self:GetName()
|
local name=self:GetName()
|
||||||
|
|
||||||
|
|
||||||
-- Exceptions
|
-- Exceptions
|
||||||
if name==AIRBASE.Nevada.Jean_Airport or
|
if name==AIRBASE.Nevada.Jean_Airport or
|
||||||
@@ -1424,36 +1459,36 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
|
|
||||||
-- 1-->4, 2-->3, 3-->2, 4-->1
|
-- 1-->4, 2-->3, 3-->2, 4-->1
|
||||||
exception=1
|
exception=1
|
||||||
|
|
||||||
elseif UTILS.GetDCSMap()==DCSMAP.Syria and N>=2 and
|
elseif UTILS.GetDCSMap()==DCSMAP.Syria and N>=2 and
|
||||||
name~=AIRBASE.Syria.Minakh and
|
name~=AIRBASE.Syria.Minakh and
|
||||||
name~=AIRBASE.Syria.Damascus and
|
name~=AIRBASE.Syria.Damascus and
|
||||||
name~=AIRBASE.Syria.Khalkhalah and
|
name~=AIRBASE.Syria.Khalkhalah and
|
||||||
name~=AIRBASE.Syria.Marj_Ruhayyil and
|
name~=AIRBASE.Syria.Marj_Ruhayyil and
|
||||||
name~=AIRBASE.Syria.Beirut_Rafic_Hariri then
|
name~=AIRBASE.Syria.Beirut_Rafic_Hariri then
|
||||||
|
|
||||||
-- 1-->3, 2-->4, 3-->1, 4-->2
|
-- 1-->3, 2-->4, 3-->1, 4-->2
|
||||||
exception=2
|
exception=2
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function returning the index of the runway coordinate belonding to the given index i.
|
--- Function returning the index of the runway coordinate belonding to the given index i.
|
||||||
local function f(i)
|
local function f(i)
|
||||||
|
|
||||||
local j
|
local j
|
||||||
|
|
||||||
if exception==1 then
|
if exception==1 then
|
||||||
|
|
||||||
j=N-(i-1) -- 1-->4, 2-->3
|
j=N-(i-1) -- 1-->4, 2-->3
|
||||||
|
|
||||||
elseif exception==2 then
|
elseif exception==2 then
|
||||||
|
|
||||||
if i<=N2 then
|
if i<=N2 then
|
||||||
j=i+N2 -- 1-->3, 2-->4
|
j=i+N2 -- 1-->3, 2-->4
|
||||||
else
|
else
|
||||||
j=i-N2 -- 3-->1, 4-->3
|
j=i-N2 -- 3-->1, 4-->3
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if i%2==0 then
|
if i%2==0 then
|
||||||
@@ -1461,9 +1496,9 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
else
|
else
|
||||||
j=i+1 -- odd 1-->2, 3-->4
|
j=i+1 -- odd 1-->2, 3-->4
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Special case where there is no obvious order.
|
-- Special case where there is no obvious order.
|
||||||
if name==AIRBASE.Syria.Beirut_Rafic_Hariri then
|
if name==AIRBASE.Syria.Beirut_Rafic_Hariri then
|
||||||
if i==1 then
|
if i==1 then
|
||||||
@@ -1496,7 +1531,7 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
j=2
|
j=2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return j
|
return j
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1505,7 +1540,7 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
|
|
||||||
-- Get the other spawn point coordinate.
|
-- Get the other spawn point coordinate.
|
||||||
local j=f(i)
|
local j=f(i)
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
--env.info(string.format("Runway i=%s j=%s (N=%d #runwaycoord=%d)", tostring(i), tostring(j), N, #runwaycoords))
|
--env.info(string.format("Runway i=%s j=%s (N=%d #runwaycoord=%d)", tostring(i), tostring(j), N, #runwaycoords))
|
||||||
|
|
||||||
|
|||||||
@@ -3779,8 +3779,9 @@ end
|
|||||||
-- @param #number radius Radius of the relocation zone, default 500
|
-- @param #number radius Radius of the relocation zone, default 500
|
||||||
-- @param #boolean onroad If true, route on road (less problems with AI way finding), default true
|
-- @param #boolean onroad If true, route on road (less problems with AI way finding), default true
|
||||||
-- @param #boolean shortcut If true and onroad is set, take a shorter route - if available - off road, default false
|
-- @param #boolean shortcut If true and onroad is set, take a shorter route - if available - off road, default false
|
||||||
|
-- @param #string formation Formation string as in the mission editor, e.g. "Vee", "Diamond", "Line abreast", etc. Defaults to "Off Road"
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:RelocateGroundRandomInRadius(speed, radius, onroad, shortcut)
|
function CONTROLLABLE:RelocateGroundRandomInRadius(speed, radius, onroad, shortcut, formation)
|
||||||
self:F2( { self.ControllableName } )
|
self:F2( { self.ControllableName } )
|
||||||
|
|
||||||
local _coord = self:GetCoordinate()
|
local _coord = self:GetCoordinate()
|
||||||
@@ -3791,14 +3792,14 @@ function CONTROLLABLE:RelocateGroundRandomInRadius(speed, radius, onroad, shortc
|
|||||||
local _grptsk = {}
|
local _grptsk = {}
|
||||||
local _candoroad = false
|
local _candoroad = false
|
||||||
local _shortcut = shortcut or false
|
local _shortcut = shortcut or false
|
||||||
|
local _formation = formation or "Off Road"
|
||||||
|
|
||||||
-- create a DCS Task an push it on the group
|
-- create a DCS Task an push it on the group
|
||||||
-- TaskGroundOnRoad(ToCoordinate,Speed,OffRoadFormation,Shortcut,FromCoordinate,WaypointFunction,WaypointFunctionArguments)
|
|
||||||
if onroad then
|
if onroad then
|
||||||
_grptsk, _candoroad = self:TaskGroundOnRoad(_tocoord,_speed,"Off Road",_shortcut)
|
_grptsk, _candoroad = self:TaskGroundOnRoad(_tocoord,_speed,_formation,_shortcut)
|
||||||
self:Route(_grptsk,5)
|
self:Route(_grptsk,5)
|
||||||
else
|
else
|
||||||
self:TaskRouteToVec2(_tocoord:GetVec2(),_speed,"Off Road")
|
self:TaskRouteToVec2(_tocoord:GetVec2(),_speed,_formation)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -1137,7 +1137,7 @@ end
|
|||||||
-- @return #number Number of shells left.
|
-- @return #number Number of shells left.
|
||||||
-- @return #number Number of rockets left.
|
-- @return #number Number of rockets left.
|
||||||
-- @return #number Number of bombs left.
|
-- @return #number Number of bombs left.
|
||||||
-- @return #number Number of missiles left.
|
-- @return #number Number of missiles left.
|
||||||
function GROUP:GetAmmunition()
|
function GROUP:GetAmmunition()
|
||||||
self:F( self.ControllableName )
|
self:F( self.ControllableName )
|
||||||
|
|
||||||
@@ -1147,6 +1147,7 @@ function GROUP:GetAmmunition()
|
|||||||
local Nshells=0
|
local Nshells=0
|
||||||
local Nrockets=0
|
local Nrockets=0
|
||||||
local Nmissiles=0
|
local Nmissiles=0
|
||||||
|
local Nbombs=0
|
||||||
|
|
||||||
if DCSControllable then
|
if DCSControllable then
|
||||||
|
|
||||||
@@ -1155,18 +1156,19 @@ function GROUP:GetAmmunition()
|
|||||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
-- Get ammo of the unit
|
-- Get ammo of the unit
|
||||||
local ntot, nshells, nrockets, nmissiles = Unit:GetAmmunition()
|
local ntot, nshells, nrockets, nbombs, nmissiles = Unit:GetAmmunition()
|
||||||
|
|
||||||
Ntot=Ntot+ntot
|
Ntot=Ntot+ntot
|
||||||
Nshells=Nshells+nshells
|
Nshells=Nshells+nshells
|
||||||
Nrockets=Nrockets+nrockets
|
Nrockets=Nrockets+nrockets
|
||||||
Nmissiles=Nmissiles+nmissiles
|
Nmissiles=Nmissiles+nmissiles
|
||||||
|
Nbombs=Nbombs+nbombs
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return Ntot, Nshells, Nrockets, Nmissiles
|
return Ntot, Nshells, Nrockets, Nbombs, Nmissiles
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -2576,8 +2578,10 @@ end
|
|||||||
-- @return #GROUP self
|
-- @return #GROUP self
|
||||||
function GROUP:SetCommandInvisible(switch)
|
function GROUP:SetCommandInvisible(switch)
|
||||||
self:F2( self.GroupName )
|
self:F2( self.GroupName )
|
||||||
local switch = switch or false
|
if switch==nil then
|
||||||
local SetInvisible = {id = 'SetInvisible', params = {value = true}}
|
switch=false
|
||||||
|
end
|
||||||
|
local SetInvisible = {id = 'SetInvisible', params = {value = switch}}
|
||||||
self:SetCommand(SetInvisible)
|
self:SetCommand(SetInvisible)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2588,12 +2592,25 @@ end
|
|||||||
-- @return #GROUP self
|
-- @return #GROUP self
|
||||||
function GROUP:SetCommandImmortal(switch)
|
function GROUP:SetCommandImmortal(switch)
|
||||||
self:F2( self.GroupName )
|
self:F2( self.GroupName )
|
||||||
local switch = switch or false
|
if switch==nil then
|
||||||
local SetInvisible = {id = 'SetImmortal', params = {value = true}}
|
switch=false
|
||||||
self:SetCommand(SetInvisible)
|
end
|
||||||
|
local SetImmortal = {id = 'SetImmortal', params = {value = switch}}
|
||||||
|
self:SetCommand(SetImmortal)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get skill from Group. Effectively gets the skill from Unit 1 as the group holds no skill value.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @return #string Skill String of skill name.
|
||||||
|
function GROUP:GetSkill()
|
||||||
|
self:F2( self.GroupName )
|
||||||
|
local unit = self:GetUnit(1)
|
||||||
|
local name = unit:GetName()
|
||||||
|
local skill = _DATABASE.Templates.Units[name].Template.skill or "Random"
|
||||||
|
return skill
|
||||||
|
end
|
||||||
|
|
||||||
--do -- Smoke
|
--do -- Smoke
|
||||||
--
|
--
|
||||||
----- Signal a flare at the position of the GROUP.
|
----- Signal a flare at the position of the GROUP.
|
||||||
|
|||||||
@@ -684,6 +684,27 @@ function POSITIONABLE:IsShip()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Returns if the unit is a submarine.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @return #boolean Submarines attributes result.
|
||||||
|
function POSITIONABLE:IsSubmarine()
|
||||||
|
self:F2()
|
||||||
|
|
||||||
|
local DCSUnit = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSUnit then
|
||||||
|
local UnitDescriptor = DCSUnit:getDesc()
|
||||||
|
if UnitDescriptor.attributes["Submarines"] == true then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns true if the POSITIONABLE is in the air.
|
--- Returns true if the POSITIONABLE is in the air.
|
||||||
-- Polymorphic, is overridden in GROUP and UNIT.
|
-- Polymorphic, is overridden in GROUP and UNIT.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
@@ -1513,6 +1534,7 @@ do -- Cargo
|
|||||||
["Ural-4320 APA-5D"] = 10,
|
["Ural-4320 APA-5D"] = 10,
|
||||||
["Ural-4320T"] = 14,
|
["Ural-4320T"] = 14,
|
||||||
["ZBD04A"] = 7, -- new by kappa
|
["ZBD04A"] = 7, -- new by kappa
|
||||||
|
["VAB_Mephisto"] = 8, -- new by Apple
|
||||||
}
|
}
|
||||||
|
|
||||||
local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 95
|
local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 95
|
||||||
|
|||||||
@@ -1426,3 +1426,13 @@ function UNIT:EnableEmission(switch)
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get skill from Unit.
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @return #string Skill String of skill name.
|
||||||
|
function UNIT:GetSkill()
|
||||||
|
self:F2( self.UnitName )
|
||||||
|
local name = self.UnitName
|
||||||
|
local skill = _DATABASE.Templates.Units[name].Template.skill or "Random"
|
||||||
|
return skill
|
||||||
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user