Merge branch 'master' into develop

This commit is contained in:
Frank 2021-03-28 20:30:19 +02:00
commit 00ff9a11b8
2 changed files with 159 additions and 141 deletions

View File

@ -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
@ -92,7 +92,7 @@ CALLSIGN={
Texaco=1, Texaco=1,
Arco=2, Arco=2,
Shell=3, Shell=3,
}, },
-- JTAC -- JTAC
JTAC={ JTAC={
Axeman=1, Axeman=1,
@ -161,31 +161,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
@ -194,7 +194,7 @@ UTILS.IsInstanceOf = function( object, className )
end end
end end
end end
-- Check failed -- Check failed
return false return false
end end
@ -206,7 +206,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
@ -214,20 +214,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
@ -237,19 +237,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
@ -297,7 +297,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)
@ -305,7 +305,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
@ -414,7 +414,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).
@ -424,6 +424,14 @@ UTILS.hPa2inHg = function( hPa )
return hPa * 0.0295299830714 return hPa * 0.0295299830714
end end
--- Convert knots to alitude corrected KIAS, e.g. for tankers.
-- @param #number knots Speed in knots.
-- @param #number altitude Altitude in feet
-- @return #number Corrected KIAS
UTILS.KnotsToAltKIAS = function( knots, altitude )
return (knots * 0.018 * (altitude / 1000)) + knots
end
--- Convert pressure from hecto Pascal (hPa) to millimeters of mercury (mmHg). --- Convert pressure from hecto Pascal (hPa) to millimeters of mercury (mmHg).
-- @param #number hPa Pressure in hPa. -- @param #number hPa Pressure in hPa.
-- @return #number Pressure in mmHg. -- @return #number Pressure in mmHg.
@ -540,23 +548,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
@ -584,7 +592,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
@ -610,7 +618,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
@ -630,7 +638,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
@ -641,7 +649,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()
@ -742,15 +750,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)
@ -780,10 +788,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
@ -798,24 +806,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
@ -833,7 +841,7 @@ function UTILS.ClockToSeconds(clock)
end end
i=i+1 i=i+1
end end
return seconds return seconds
end end
@ -845,12 +853,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.
@ -871,28 +879,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
@ -917,9 +925,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
@ -945,7 +953,7 @@ end
function UTILS.VecDist2D(a, b) function UTILS.VecDist2D(a, b)
local c={x=b.x-a.x, y=b.y-a.y} local c={x=b.x-a.x, y=b.y-a.y}
local d=math.sqrt(c.x*c.x+c.y*c.y) local d=math.sqrt(c.x*c.x+c.y*c.y)
return d return d
@ -959,7 +967,7 @@ end
function UTILS.VecDist3D(a, b) function UTILS.VecDist3D(a, b)
local c={x=b.x-a.x, y=b.y-a.y, z=b.z-a.z} 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)) local d=math.sqrt(UTILS.VecDot(c, c))
return d return d
@ -973,7 +981,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.
@ -981,7 +989,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.
@ -989,14 +997,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
@ -1004,8 +1012,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
@ -1029,18 +1037,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.
@ -1056,21 +1064,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
@ -1088,17 +1096,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
@ -1109,7 +1117,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
@ -1136,13 +1144,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
@ -1152,11 +1160,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.
@ -1168,20 +1176,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
@ -1192,7 +1200,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
@ -1227,12 +1235,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)
@ -1262,7 +1270,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.
@ -1281,7 +1289,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
@ -1294,7 +1302,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
@ -1306,7 +1314,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
@ -1350,11 +1358,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
@ -1367,14 +1375,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
@ -1401,47 +1409,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
@ -1450,13 +1458,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
@ -1506,9 +1514,9 @@ end
--@param #table table to be shuffled --@param #table table to be shuffled
--@return #table --@return #table
function UTILS.ShuffleTable(t) function UTILS.ShuffleTable(t)
if t == nil or type(t) ~= "table" then if t == nil or type(t) ~= "table" then
BASE:I("Error in ShuffleTable: Missing or wrong tyåe of Argument") BASE:I("Error in ShuffleTable: Missing or wrong tyåe of Argument")
return return
end end
math.random() math.random()
math.random() math.random()

View File

@ -1458,11 +1458,14 @@ do -- Cargo
self:F({Desc=Desc}) self:F({Desc=Desc})
local Weights = { local Weights = {
["Type_071"] = 245000, ["Type_071"] = 245000,
["LHA_Tarawa"] = 500000, ["LHA_Tarawa"] = 500000,
["Ropucha-class"] = 150000, ["Ropucha-class"] = 150000,
["Dry-cargo ship-1"] = 70000, ["Dry-cargo ship-1"] = 70000,
["Dry-cargo ship-2"] = 70000, ["Dry-cargo ship-2"] = 70000,
["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia).
["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops.
["LST_Mk2"] =2100000, -- Can carry 2100 tons according to wiki source!
} }
self.__.CargoBayWeightLimit = ( Weights[Desc.typeName] or 50000 ) self.__.CargoBayWeightLimit = ( Weights[Desc.typeName] or 50000 )
@ -1470,40 +1473,47 @@ do -- Cargo
local Desc = self:GetDesc() local Desc = self:GetDesc()
local Weights = { local Weights = {
["M1126 Stryker ICV"] = 9,
["M-113"] = 9,
["AAV7"] = 25, ["AAV7"] = 25,
["M2A1_halftrack"] = 9, ["Bedford_MWD"] = 8, -- new by kappa
["BMD-1"] = 9, ["Blitz_36-6700A"] = 10, -- new by kappa
["BMD-1"] = 9, -- IRL should be 4 passengers
["BMP-1"] = 8, ["BMP-1"] = 8,
["BMP-2"] = 7, ["BMP-2"] = 7,
["BMP-3"] = 8, ["BMP-3"] = 8, -- IRL should be 7+2 passengers
["Boman"] = 25, ["Boman"] = 25,
["BTR-80"] = 9, ["BTR-80"] = 9, -- IRL should be 7 passengers
["BTR_D"] = 12, ["BTR-82A"] = 9, -- new by kappa -- IRL should be 7 passengers
["BTR_D"] = 12, -- IRL should be 10 passengers
["Cobra"] = 8, ["Cobra"] = 8,
["Land_Rover_101_FC"] = 11, -- new by kappa
["Land_Rover_109_S3"] = 7, -- new by kappa
["LAV-25"] = 6, ["LAV-25"] = 6,
["M-2 Bradley"] = 6, ["M-2 Bradley"] = 6,
["M1043 HMMWV Armament"] = 4, ["M1043 HMMWV Armament"] = 4,
["M1045 HMMWV TOW"] = 4, ["M1045 HMMWV TOW"] = 4,
["M1126 Stryker ICV"] = 9, ["M1126 Stryker ICV"] = 9,
["M1134 Stryker ATGM"] = 9, ["M1134 Stryker ATGM"] = 9,
["M2A1_halftrack"] = 9,
["M-113"] = 9, -- IRL should be 11 passengers
["Marder"] = 6, ["Marder"] = 6,
["MCV-80"] = 9, ["MCV-80"] = 9, -- IRL should be 7 passengers
["MLRS FDDM"] = 4, ["MLRS FDDM"] = 4,
["MTLB"] = 25, ["MTLB"] = 25, -- IRL should be 11 passengers
["TPZ"] = 10,
["Ural-4320 APA-5D"] = 10,
["GAZ-66"] = 8, ["GAZ-66"] = 8,
["GAZ-3307"] = 12, ["GAZ-3307"] = 12,
["GAZ-3308"] = 14, ["GAZ-3308"] = 14,
["Tigr_233036"] = 6, ["Grad_FDDM"] = 6, -- new by kappa
["KAMAZ Truck"] = 12, ["KAMAZ Truck"] = 12,
["KrAZ6322"] = 12, ["KrAZ6322"] = 12,
["M 818"] = 12, ["M 818"] = 12,
["Tigr_233036"] = 6,
["TPZ"] = 10,
["UAZ-469"] = 4, -- new by kappa
["Ural-375"] = 12, ["Ural-375"] = 12,
["Ural-4320-31"] = 14, ["Ural-4320-31"] = 14,
["Ural-4320 APA-5D"] = 10,
["Ural-4320T"] = 14, ["Ural-4320T"] = 14,
["ZBD04A"] = 7, -- new by kappa
} }
local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 95 local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 95