mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
243 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc64b98c59 | ||
|
|
e6dde7335a | ||
|
|
bbb2174957 | ||
|
|
b37b50a0c6 | ||
|
|
459ff8038b | ||
|
|
f2da862442 | ||
|
|
9c6c2ec5ca | ||
|
|
aa13583aa7 | ||
|
|
002f1e09ef | ||
|
|
5091ed7d6d | ||
|
|
2475f22937 | ||
|
|
f4f12f786c | ||
|
|
eb659446df | ||
|
|
62c42adebc | ||
|
|
0fc91595b8 | ||
|
|
18fca6461b | ||
|
|
869b819a4f | ||
|
|
8ae6192a5f | ||
|
|
3b2af6ea07 | ||
|
|
82da7a8f24 | ||
|
|
3749686882 | ||
|
|
b2eba4911a | ||
|
|
40700a387c | ||
|
|
0577940d58 | ||
|
|
1d6be07cff | ||
|
|
2d6545429a | ||
|
|
9f095a1d28 | ||
|
|
91b6da70af | ||
|
|
235e40cb26 | ||
|
|
8ba3a30278 | ||
|
|
3675ddaf04 | ||
|
|
62a59e7b2a | ||
|
|
1f949463aa | ||
|
|
6d53a30b1f | ||
|
|
5aeb480069 | ||
|
|
4b6aa3b56f | ||
|
|
4209569f29 | ||
|
|
7106efbc04 | ||
|
|
4e878e49a7 | ||
|
|
3e470e557d | ||
|
|
5f567fcf66 | ||
|
|
2289e16d91 | ||
|
|
40415ef933 | ||
|
|
6519c30b3a | ||
|
|
42d253a9ca | ||
|
|
38b40e2931 | ||
|
|
f7a7ea14a3 | ||
|
|
41e0f92cc0 | ||
|
|
2c5e9789db | ||
|
|
e198aae1dd | ||
|
|
d040cc0d03 | ||
|
|
f078e94a7a | ||
|
|
9973099f57 | ||
|
|
9ca7785a64 | ||
|
|
e7d5fd6c1b | ||
|
|
9eed35ace7 | ||
|
|
c7ec1b4e5e | ||
|
|
34ffebb46a | ||
|
|
e8a2167934 | ||
|
|
fa342a5b6b | ||
|
|
4ebcaf913c | ||
|
|
7a4c9806a4 | ||
|
|
bddc1d7fdc | ||
|
|
cb813b70e1 | ||
|
|
f161f08fc1 | ||
|
|
3e22411328 | ||
|
|
b00778bb86 | ||
|
|
564f95781e | ||
|
|
6c2f8aa6ff | ||
|
|
2e342e4341 | ||
|
|
3c6089884e | ||
|
|
884ea866e2 | ||
|
|
1af1ada7dc | ||
|
|
c72c3fd091 | ||
|
|
0848718313 | ||
|
|
832abd7860 | ||
|
|
12e745af54 | ||
|
|
f18c818b8e | ||
|
|
4deca4f816 | ||
|
|
b023ecfb99 | ||
|
|
cdb491bb5f | ||
|
|
3ac47c967e | ||
|
|
e577062720 | ||
|
|
95dc7ad2b4 | ||
|
|
fccf58cd6c | ||
|
|
6791e4d4ba | ||
|
|
11f8ac4820 | ||
|
|
8f2672f928 | ||
|
|
fb66d74ab7 | ||
|
|
37c061bcbd | ||
|
|
9491b18ff4 | ||
|
|
8cff2eaac0 | ||
|
|
f64550f7c8 | ||
|
|
0addafa627 | ||
|
|
b643d73f7f | ||
|
|
798c5b292a | ||
|
|
688c57d91d | ||
|
|
d4c8d5d91b | ||
|
|
154cc9fbeb | ||
|
|
327bac3058 | ||
|
|
c0e58e9c92 | ||
|
|
e8bfab515c | ||
|
|
695f204493 | ||
|
|
a7202ccd0d | ||
|
|
c71c6c5178 | ||
|
|
155b06edc8 | ||
|
|
64b8f2fb46 | ||
|
|
7a07e15032 | ||
|
|
3d74312d43 | ||
|
|
6baf85d429 | ||
|
|
311ab19389 | ||
|
|
e9f92d2250 | ||
|
|
d469374ed5 | ||
|
|
a6ff84c09a | ||
|
|
3ed8ca63a8 | ||
|
|
89aa08829e | ||
|
|
5146106885 | ||
|
|
f05fc956db | ||
|
|
d10adb5de8 | ||
|
|
45aac21b63 | ||
|
|
b52643bb36 | ||
|
|
036010c39d | ||
|
|
9440d2b2c3 | ||
|
|
29727ec9a6 | ||
|
|
eb0b43cea8 | ||
|
|
a6e16fb7ad | ||
|
|
616b80710a | ||
|
|
94f206af68 | ||
|
|
ae6613fae1 | ||
|
|
b61cfc7390 | ||
|
|
e2c5688670 | ||
|
|
1d016d9fce | ||
|
|
cbc5b5bb89 | ||
|
|
218c7736e0 | ||
|
|
8e46e41b34 | ||
|
|
bcf639d076 | ||
|
|
697d12aefc | ||
|
|
89afd2b4c0 | ||
|
|
3358f98bc4 | ||
|
|
417af6a93c | ||
|
|
9a2f6c7faa | ||
|
|
e52b0edc4e | ||
|
|
c51a65f058 | ||
|
|
5b2e67df19 | ||
|
|
7b7605e501 | ||
|
|
49d7d9ee2e | ||
|
|
774c8971c8 | ||
|
|
545c0886fa | ||
|
|
721d027fb3 | ||
|
|
5185ea35fe | ||
|
|
ec039f2999 | ||
|
|
c0fc649f8b | ||
|
|
c49497e68c | ||
|
|
57bc6de12b | ||
|
|
1b80d68f50 | ||
|
|
787151597c | ||
|
|
f725039da5 | ||
|
|
a4f15a0830 | ||
|
|
084f00afad | ||
|
|
87f4ebee64 | ||
|
|
a0276821d9 | ||
|
|
01a5b523da | ||
|
|
13477e17ec | ||
|
|
c32cec4c5b | ||
|
|
e08df3f9ce | ||
|
|
f958130b92 | ||
|
|
9a19dd254e | ||
|
|
4869ae4baa | ||
|
|
1fd41eaa55 | ||
|
|
25a7260d7f | ||
|
|
478934ddd1 | ||
|
|
3d7234de19 | ||
|
|
fed1fb2839 | ||
|
|
08ba001b45 | ||
|
|
ce5aaf0b48 | ||
|
|
ee6954a4b9 | ||
|
|
6b6e845a18 | ||
|
|
c01b94518f | ||
|
|
9cf5f74e5e | ||
|
|
4fda0414a0 | ||
|
|
effa4af3a1 | ||
|
|
80b7e49eed | ||
|
|
63748c3841 | ||
|
|
1c68b66047 | ||
|
|
6c9dce70e7 | ||
|
|
5515aa43d6 | ||
|
|
47c461e504 | ||
|
|
65174ceaae | ||
|
|
2500cfb3c7 | ||
|
|
7e673271ee | ||
|
|
e165cb156c | ||
|
|
82bfb0cc55 | ||
|
|
b0fe0663f1 | ||
|
|
1bd5193786 | ||
|
|
64c3fb985a | ||
|
|
1536c94319 | ||
|
|
e7efd89d7a | ||
|
|
c486167b01 | ||
|
|
e5201f3363 | ||
|
|
ff4927dbb7 | ||
|
|
5842562ce1 | ||
|
|
5f545fd3c5 | ||
|
|
aab2f20280 | ||
|
|
76ac68ce51 | ||
|
|
f034e3680c | ||
|
|
e5c57269bb | ||
|
|
ab5167717d | ||
|
|
176abf74a1 | ||
|
|
da4f13d0d7 | ||
|
|
7ddec7609a | ||
|
|
53c3996aef | ||
|
|
bf61f22dd1 | ||
|
|
5e8a36802c | ||
|
|
b34b537a26 | ||
|
|
812fb99e66 | ||
|
|
9cb3111dd5 | ||
|
|
1312555690 | ||
|
|
aa4f8452fa | ||
|
|
e2c1097ec5 | ||
|
|
4b8b13dd68 | ||
|
|
59f795fc17 | ||
|
|
26a935c29c | ||
|
|
848336f8ac | ||
|
|
8e6e9cbb4d | ||
|
|
15cb9bec40 | ||
|
|
38f5fd8249 | ||
|
|
6a04f83280 | ||
|
|
ec4d12a0d5 | ||
|
|
999aba5d77 | ||
|
|
652f29b782 | ||
|
|
0c6aae45c1 | ||
|
|
25b8cff442 | ||
|
|
9f7471178b | ||
|
|
f3f3406d64 | ||
|
|
4eb886d0f3 | ||
|
|
5c6e50e7f9 | ||
|
|
18fd9cdc3d | ||
|
|
fb3115a0f1 | ||
|
|
fdcdf52d9a | ||
|
|
5dcefff28d | ||
|
|
833d4f7b65 | ||
|
|
61bb59d8b3 | ||
|
|
21652de804 |
@@ -26,24 +26,25 @@ init:
|
|||||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- cmd:
|
||||||
# Outcomment if lua environment invalidates and needs to be reinstalled, otherwise all will run from the cache.
|
# Outcomment if lua environment invalidates and needs to be reinstalled, otherwise all will run from the cache.
|
||||||
# - call choco install 7zip.commandline
|
call choco install 7zip.commandline
|
||||||
# - call choco install lua51
|
call choco install lua51
|
||||||
# - call choco install luarocks
|
call choco install luarocks
|
||||||
# - call refreshenv
|
call refreshenv
|
||||||
# - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||||
# - cmd: PATH = %PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\bin
|
cmd: PATH = %PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\bin
|
||||||
# - cmd: set LUA_PATH = %LUA_PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?.lua;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?\init.lua
|
cmd: set LUA_PATH = %LUA_PATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?.lua;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\share\lua\5.1\?\init.lua
|
||||||
# - cmd: set LUA_CPATH = %LUA_CPATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\lib\lua\5.1\?.dll
|
cmd: set LUA_CPATH = %LUA_CPATH%;C:\ProgramData\chocolatey\lib\luarocks\luarocks-2.4.3-win32\systree\lib\lua\5.1\?.dll
|
||||||
# - call luarocks install luasrcdiet
|
call luarocks install luasrcdiet
|
||||||
# - call luarocks install checks
|
call luarocks install checks
|
||||||
# - call luarocks install luadocumentor
|
call luarocks install luadocumentor
|
||||||
# - call luarocks install luacheck
|
call luarocks install luacheck
|
||||||
|
|
||||||
|
|
||||||
#cache:
|
cache:
|
||||||
# - C:\ProgramData\chocolatey\lib
|
C:\ProgramData\chocolatey\lib
|
||||||
# - C:\ProgramData\chocolatey\bin
|
C:\ProgramData\chocolatey\bin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -51,8 +52,9 @@ build_script:
|
|||||||
- ps: |
|
- ps: |
|
||||||
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
||||||
{
|
{
|
||||||
|
echo "Hello World!"
|
||||||
$apiUrl = 'https://ci.appveyor.com/api'
|
$apiUrl = 'https://ci.appveyor.com/api'
|
||||||
$token = 'qts80b5kpq0ooj4x6vvw'
|
$token = 'v2.6hcv3ige78kg3yvg4ge8'
|
||||||
$headers = @{
|
$headers = @{
|
||||||
"Authorization" = "Bearer $token"
|
"Authorization" = "Bearer $token"
|
||||||
"Content-type" = "application/json"
|
"Content-type" = "application/json"
|
||||||
@@ -65,7 +67,7 @@ build_script:
|
|||||||
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
if( $env:appveyor_repo_branch -eq 'master' -or $env:appveyor_repo_branch -eq 'develop' )
|
||||||
{
|
{
|
||||||
$apiUrl = 'https://ci.appveyor.com/api'
|
$apiUrl = 'https://ci.appveyor.com/api'
|
||||||
$token = 'qts80b5kpq0ooj4x6vvw'
|
$token = 'v2.6hcv3ige78kg3yvg4ge8'
|
||||||
$headers = @{
|
$headers = @{
|
||||||
"Authorization" = "Bearer $token"
|
"Authorization" = "Bearer $token"
|
||||||
"Content-type" = "application/json"
|
"Content-type" = "application/json"
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -18,6 +18,8 @@ local.properties
|
|||||||
# External tool builders
|
# External tool builders
|
||||||
.externalToolBuilders/
|
.externalToolBuilders/
|
||||||
|
|
||||||
|
# AppVeyor
|
||||||
|
.appveyor/
|
||||||
|
|
||||||
# CDT-specific
|
# CDT-specific
|
||||||
.cproject
|
.cproject
|
||||||
|
|||||||
54
.luacheckrc
Normal file
54
.luacheckrc
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
ignore = {
|
||||||
|
"011", -- A syntax error.
|
||||||
|
"021", -- An invalid inline option.
|
||||||
|
"022", -- An unpaired inline push directive.
|
||||||
|
"023", -- An unpaired inline pop directive.
|
||||||
|
"111", -- Setting an undefined global variable.
|
||||||
|
"112", -- Mutating an undefined global variable.
|
||||||
|
"113", -- Accessing an undefined global variable.
|
||||||
|
"121", -- Setting a read-only global variable.
|
||||||
|
"122", -- Setting a read-only field of a global variable.
|
||||||
|
"131", -- Unused implicitly defined global variable.
|
||||||
|
"142", -- Setting an undefined field of a global variable.
|
||||||
|
"143", -- Accessing an undefined field of a global variable.
|
||||||
|
"211", -- Unused local variable.
|
||||||
|
"212", -- Unused argument.
|
||||||
|
"213", -- Unused loop variable.
|
||||||
|
"221", -- Local variable is accessed but never set.
|
||||||
|
"231", -- Local variable is set but never accessed.
|
||||||
|
"232", -- An argument is set but never accessed.
|
||||||
|
"233", -- Loop variable is set but never accessed.
|
||||||
|
"241", -- Local variable is mutated but never accessed.
|
||||||
|
"311", -- Value assigned to a local variable is unused.
|
||||||
|
"312", -- Value of an argument is unused.
|
||||||
|
"313", -- Value of a loop variable is unused.
|
||||||
|
"314", -- Value of a field in a table literal is unused.
|
||||||
|
"321", -- Accessing uninitialized local variable.
|
||||||
|
"331", -- Value assigned to a local variable is mutated but never accessed.
|
||||||
|
"341", -- Mutating uninitialized local variable.
|
||||||
|
"411", -- Redefining a local variable.
|
||||||
|
"412", -- Redefining an argument.
|
||||||
|
"413", -- Redefining a loop variable.
|
||||||
|
"421", -- Shadowing a local variable.
|
||||||
|
"422", -- Shadowing an argument.
|
||||||
|
"423", -- Shadowing a loop variable.
|
||||||
|
"431", -- Shadowing an upvalue.
|
||||||
|
"432", -- Shadowing an upvalue argument.
|
||||||
|
"433", -- Shadowing an upvalue loop variable.
|
||||||
|
"511", -- Unreachable code.
|
||||||
|
"512", -- Loop can be executed at most once.
|
||||||
|
"521", -- Unused label.
|
||||||
|
"531", -- Left-hand side of an assignment is too short.
|
||||||
|
"532", -- Left-hand side of an assignment is too long.
|
||||||
|
"541", -- An empty do end block.
|
||||||
|
"542", -- An empty if branch.
|
||||||
|
"551", -- An empty statement.
|
||||||
|
"561", -- Cyclomatic complexity of a function is too high.
|
||||||
|
"571", -- A numeric for loop goes from #(expr) down to 1 or less without negative step.
|
||||||
|
"611", -- A line consists of nothing but whitespace.
|
||||||
|
"612", -- A line contains trailing whitespace.
|
||||||
|
"613", -- Trailing whitespace in a string.
|
||||||
|
"614", -- Trailing whitespace in a comment.
|
||||||
|
"621", -- Inconsistent indentation (SPACE followed by TAB).
|
||||||
|
"631", -- Line is too long.
|
||||||
|
}
|
||||||
@@ -143,7 +143,7 @@ end
|
|||||||
-- @return #AI_A2A_CAP
|
-- @return #AI_A2A_CAP
|
||||||
function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
||||||
|
|
||||||
return self:New2( AICap, EngageMinSpeed, EngageMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolZone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, PatrolAltType )
|
return self:New2( AICap, EngageMinSpeed, EngageMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType, PatrolZone, PatrolMinSpeed, PatrolMaxSpeed, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolAltType )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -658,7 +658,9 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- of the race track will randomly selected between 90 (West to East) and 180 (North to South) degrees.
|
-- of the race track will randomly selected between 90 (West to East) and 180 (North to South) degrees.
|
||||||
-- After a random duration between 10 and 20 minutes, the flight will get a new random orbit location.
|
-- After a random duration between 10 and 20 minutes, the flight will get a new random orbit location.
|
||||||
--
|
--
|
||||||
-- Note that all parameters except the squadron name are optional. If not specified, default values are taken. Speed and altitude are taken from the
|
-- Note that all parameters except the squadron name are optional. If not specified, default values are taken. Speed and altitude are taken from the CAP command used earlier on, e.g.
|
||||||
|
--
|
||||||
|
-- A2ADispatcher:SetSquadronCap( "Mineralnye", CAPZoneEast, 4000, 10000, 500, 600, 800, 900 )
|
||||||
--
|
--
|
||||||
-- Also note that the center of the race track pattern is chosen randomly within the patrol zone and can be close the the boarder of the zone. Hence, it cannot be guaranteed that the
|
-- Also note that the center of the race track pattern is chosen randomly within the patrol zone and can be close the the boarder of the zone. Hence, it cannot be guaranteed that the
|
||||||
-- whole pattern lies within the patrol zone.
|
-- whole pattern lies within the patrol zone.
|
||||||
@@ -2774,7 +2776,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel treshold.
|
||||||
-- A2ADispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2ADispatcher:SetSquadronFuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
function AI_A2A_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold )
|
function AI_A2A_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold )
|
||||||
|
|
||||||
@@ -2817,7 +2819,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
-- A2ADispatcher = AI_A2A_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the squadron fuel treshold.
|
-- -- Now Setup the squadron fuel treshold.
|
||||||
-- A2ADispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2ADispatcher:SetSquadronFuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
-- -- Now Setup the squadron tanker.
|
-- -- Now Setup the squadron tanker.
|
||||||
-- A2ADispatcher:SetSquadronTanker( "SquadronName", "Tanker" ) -- The group name of the tanker is "Tanker" in the Mission Editor.
|
-- A2ADispatcher:SetSquadronTanker( "SquadronName", "Tanker" ) -- The group name of the tanker is "Tanker" in the Mission Editor.
|
||||||
@@ -2919,9 +2921,13 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- @return #AI_A2A_DISPATCHER.Squadron Squadron The squadron.
|
-- @return #AI_A2A_DISPATCHER.Squadron Squadron The squadron.
|
||||||
function AI_A2A_DISPATCHER:GetSquadronFromDefender( Defender )
|
function AI_A2A_DISPATCHER:GetSquadronFromDefender( Defender )
|
||||||
self.Defenders = self.Defenders or {}
|
self.Defenders = self.Defenders or {}
|
||||||
|
if Defender ~= nil then
|
||||||
local DefenderName = Defender:GetName()
|
local DefenderName = Defender:GetName()
|
||||||
self:F( { DefenderName = DefenderName } )
|
self:F( { DefenderName = DefenderName } )
|
||||||
return self.Defenders[ DefenderName ]
|
return self.Defenders[ DefenderName ]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- ### 2.2. The **Defense Reactivity**.
|
-- ### 2.2. The **Defense Reactivity**.
|
||||||
--
|
--
|
||||||
-- There are 5 levels that can be configured to tweak the defense reactivity. As explained above, the threat to a defense coordinate is
|
-- There are three levels that can be configured to tweak the defense reactivity. As explained above, the threat to a defense coordinate is
|
||||||
-- also determined by the distance of the enemy ground target to the defense coordinate.
|
-- also determined by the distance of the enemy ground target to the defense coordinate.
|
||||||
-- If you want to have a **low** defense reactivity, that is, the probability that an A2G defense will engage to the enemy ground target, then
|
-- If you want to have a **low** defense reactivity, that is, the probability that an A2G defense will engage to the enemy ground target, then
|
||||||
-- use the @{#AI_A2G_DISPATCHER.SetDefenseReactivityLow}() method. For medium and high reactivity, use the methods
|
-- use the @{#AI_A2G_DISPATCHER.SetDefenseReactivityLow}() method. For medium and high reactivity, use the methods
|
||||||
|
|||||||
@@ -595,19 +595,24 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
|
|
||||||
local FromCoord = AIGroup:GetCoordinate()
|
local FromCoord = AIGroup:GetCoordinate()
|
||||||
local ToTargetCoord = self.HomeAirbase:GetCoordinate()
|
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
||||||
|
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
||||||
|
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+1000 -- let's set this 1000m/3000 feet above ground
|
||||||
|
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
||||||
|
|
||||||
if not self.RTBMinSpeed and not self.RTBMaxSpeed then
|
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
|
||||||
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
||||||
self:SetRTBSpeed( RTBSpeedMax * 0.25, RTBSpeedMax * 0.25 )
|
self:SetRTBSpeed( RTBSpeedMax * 0.5, RTBSpeedMax * 0.6 )
|
||||||
end
|
end
|
||||||
|
|
||||||
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
||||||
local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord ) )
|
--local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord2 ) )
|
||||||
|
|
||||||
local Distance = FromCoord:Get2DDistance( ToTargetCoord )
|
local Distance = FromCoord:Get2DDistance( ToTargetCoord2 )
|
||||||
|
|
||||||
|
--local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
|
||||||
|
local ToAirbaseCoord = ToTargetCoord2
|
||||||
|
|
||||||
local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
|
|
||||||
if Distance < 5000 then
|
if Distance < 5000 then
|
||||||
self:I( "RTB and near the airbase!" )
|
self:I( "RTB and near the airbase!" )
|
||||||
self:Home()
|
self:Home()
|
||||||
|
|||||||
@@ -418,6 +418,7 @@ end
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
-- @param Core.Set#SET_UNIT AttackSetUnit Unit set to be attacked.
|
||||||
function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
|
function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
self:I( { DefenderGroup, From, Event, To, AttackSetUnit } )
|
self:I( { DefenderGroup, From, Event, To, AttackSetUnit } )
|
||||||
|
|
||||||
@@ -425,7 +426,7 @@ function AI_AIR_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
|||||||
|
|
||||||
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
||||||
|
|
||||||
local AttackCount = AttackSetUnit:Count()
|
local AttackCount = AttackSetUnit:CountAlive()
|
||||||
|
|
||||||
if AttackCount > 0 then
|
if AttackCount > 0 then
|
||||||
|
|
||||||
@@ -510,6 +511,7 @@ end
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
-- @param Core.Set#SET_UNIT AttackSetUnit Set of units to be attacked.
|
||||||
function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
|
function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
||||||
|
|
||||||
@@ -517,8 +519,8 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
|
|
||||||
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
||||||
|
|
||||||
local AttackCount = AttackSetUnit:Count()
|
local AttackCount = AttackSetUnit:CountAlive()
|
||||||
self:I({AttackCount = AttackCount})
|
self:T({AttackCount = AttackCount})
|
||||||
|
|
||||||
if AttackCount > 0 then
|
if AttackCount > 0 then
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
|
--- **AI** - Models the intelligent transportation of infantry and other cargo.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -35,10 +35,9 @@ AI_CARGO = {
|
|||||||
|
|
||||||
--- Creates a new AI_CARGO object.
|
--- Creates a new AI_CARGO object.
|
||||||
-- @param #AI_CARGO self
|
-- @param #AI_CARGO self
|
||||||
-- @param Wrapper.Group#GROUP Carrier
|
-- @param Wrapper.Group#GROUP Carrier Cargo carrier group.
|
||||||
-- @param Core.Set#SET_CARGO CargoSet
|
-- @param Core.Set#SET_CARGO CargoSet Set of cargo(s) to transport.
|
||||||
-- @param #number CombatRadius
|
-- @return #AI_CARGO self
|
||||||
-- @return #AI_CARGO
|
|
||||||
function AI_CARGO:New( Carrier, CargoSet )
|
function AI_CARGO:New( Carrier, CargoSet )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( Carrier ) ) -- #AI_CARGO
|
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( Carrier ) ) -- #AI_CARGO
|
||||||
@@ -52,7 +51,8 @@ function AI_CARGO:New( Carrier, CargoSet )
|
|||||||
self:AddTransition( "Loaded", "Deploy", "*" )
|
self:AddTransition( "Loaded", "Deploy", "*" )
|
||||||
|
|
||||||
self:AddTransition( "*", "Load", "Boarding" )
|
self:AddTransition( "*", "Load", "Boarding" )
|
||||||
self:AddTransition( { "Boarding", "Loaded" }, "Board", "Boarding" )
|
self:AddTransition( "Boarding", "Board", "Boarding" )
|
||||||
|
self:AddTransition( "Loaded", "Board", "Loaded" )
|
||||||
self:AddTransition( "Boarding", "Loaded", "Boarding" )
|
self:AddTransition( "Boarding", "Loaded", "Boarding" )
|
||||||
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
|
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
|
||||||
|
|
||||||
@@ -393,7 +393,7 @@ end
|
|||||||
function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, PickupZone )
|
function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, PickupZone )
|
||||||
self:F( { Carrier, From, Event, To, Cargo, CarrierUnit:GetName() } )
|
self:F( { Carrier, From, Event, To, Cargo, CarrierUnit:GetName() } )
|
||||||
|
|
||||||
if Carrier and Carrier:IsAlive() then
|
if Carrier and Carrier:IsAlive() and From == "Boarding" then
|
||||||
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
|
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
|
||||||
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
|
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
|
||||||
self:__Board( -10, Cargo, CarrierUnit, PickupZone )
|
self:__Board( -10, Cargo, CarrierUnit, PickupZone )
|
||||||
@@ -509,7 +509,7 @@ end
|
|||||||
function AI_CARGO:onafterUnboard( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
|
function AI_CARGO:onafterUnboard( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone, Defend = Defend } )
|
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
if Carrier and Carrier:IsAlive() then
|
if Carrier and Carrier:IsAlive() and From == "Unboarding" then
|
||||||
if not Cargo:IsUnLoaded() then
|
if not Cargo:IsUnLoaded() then
|
||||||
self:__Unboard( 10, Cargo, CarrierUnit, DeployZone, Defend )
|
self:__Unboard( 10, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
|
--- **AI** - Models the intelligent transportation of cargo using ground vehicles.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -157,6 +157,45 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set whether or not the carrier will use roads to *pickup* and *deploy* the cargo.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param #boolean Offroad If true, carrier will not use roads. If `nil` or `false` the carrier will use roads when available.
|
||||||
|
-- @param #number Formation Offroad formation used. Default is `ENUMS.Formation.Vehicle.Offroad`.
|
||||||
|
-- @return #AI_CARGO_APC self
|
||||||
|
function AI_CARGO_APC:SetOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
self:SetPickupOffRoad(Offroad, Formation)
|
||||||
|
self:SetDeployOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set whether the carrier will *not* use roads to *pickup* the cargo.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param #boolean Offroad If true, carrier will not use roads.
|
||||||
|
-- @param #number Formation Offroad formation used. Default is `ENUMS.Formation.Vehicle.Offroad`.
|
||||||
|
-- @return #AI_CARGO_APC self
|
||||||
|
function AI_CARGO_APC:SetPickupOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
self.pickupOffroad=Offroad
|
||||||
|
self.pickupFormation=Formation or ENUMS.Formation.Vehicle.OffRoad
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set whether the carrier will *not* use roads to *deploy* the cargo.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param #boolean Offroad If true, carrier will not use roads.
|
||||||
|
-- @param #number Formation Offroad formation used. Default is `ENUMS.Formation.Vehicle.Offroad`.
|
||||||
|
-- @return #AI_CARGO_APC self
|
||||||
|
function AI_CARGO_APC:SetDeployOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
self.deployOffroad=Offroad
|
||||||
|
self.deployFormation=Formation or ENUMS.Formation.Vehicle.OffRoad
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Find a free Carrier within a radius.
|
--- Find a free Carrier within a radius.
|
||||||
-- @param #AI_CARGO_APC self
|
-- @param #AI_CARGO_APC self
|
||||||
@@ -350,10 +389,13 @@ function AI_CARGO_APC:onafterFollow( APC, From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Pickup task function. Triggers Load event.
|
||||||
--- @param #AI_CARGO_APC
|
-- @param Wrapper.Group#GROUP APC The cargo carrier group.
|
||||||
-- @param Wrapper.Group#GROUP APC
|
-- @param #AI_CARGO_APC sel `AI_CARGO_APC` class.
|
||||||
function AI_CARGO_APC._Pickup( APC, self, Coordinate, Speed, PickupZone )
|
-- @param Core.Point#COORDINATE Coordinate. The coordinate (not used).
|
||||||
|
-- @param #number Speed Speed (not used).
|
||||||
|
-- @param Core.Zone#ZONE PickupZone Pickup zone.
|
||||||
|
function AI_CARGO_APC._Pickup(APC, self, Coordinate, Speed, PickupZone)
|
||||||
|
|
||||||
APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } )
|
APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } )
|
||||||
|
|
||||||
@@ -362,8 +404,12 @@ function AI_CARGO_APC._Pickup( APC, self, Coordinate, Speed, PickupZone )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Deploy task function. Triggers Unload event.
|
||||||
function AI_CARGO_APC._Deploy( APC, self, Coordinate, DeployZone )
|
-- @param Wrapper.Group#GROUP APC The cargo carrier group.
|
||||||
|
-- @param #AI_CARGO_APC self `AI_CARGO_APC` class.
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate. The coordinate (not used).
|
||||||
|
-- @param Core.Zone#ZONE DeployZone Deploy zone.
|
||||||
|
function AI_CARGO_APC._Deploy(APC, self, Coordinate, DeployZone)
|
||||||
|
|
||||||
APC:F( { "AI_CARGO_APC._Deploy:", APC } )
|
APC:F( { "AI_CARGO_APC._Deploy:", APC } )
|
||||||
|
|
||||||
@@ -393,11 +439,19 @@ function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, He
|
|||||||
|
|
||||||
local _speed=Speed or APC:GetSpeedMax()*0.5
|
local _speed=Speed or APC:GetSpeedMax()*0.5
|
||||||
|
|
||||||
local Waypoints = APC:TaskGroundOnRoad( Coordinate, _speed, "Line abreast", true )
|
-- Route on road.
|
||||||
|
local Waypoints = {}
|
||||||
|
|
||||||
|
if self.pickupOffroad then
|
||||||
|
Waypoints[1]=APC:GetCoordinate():WaypointGround(Speed, self.pickupFormation)
|
||||||
|
Waypoints[2]=Coordinate:WaypointGround(_speed, self.pickupFormation, DCSTasks)
|
||||||
|
else
|
||||||
|
Waypoints=APC:TaskGroundOnRoad(Coordinate, _speed, ENUMS.Formation.Vehicle.OffRoad, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self, Coordinate, Speed, PickupZone )
|
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self, Coordinate, Speed, PickupZone )
|
||||||
|
|
||||||
self:F({Waypoints = Waypoints})
|
|
||||||
local Waypoint = Waypoints[#Waypoints]
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||||
|
|
||||||
@@ -428,18 +482,34 @@ function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, He
|
|||||||
|
|
||||||
self.RouteDeploy = true
|
self.RouteDeploy = true
|
||||||
|
|
||||||
local _speed=Speed or APC:GetSpeedMax()*0.5
|
-- Set speed in km/h.
|
||||||
|
local speedmax=APC:GetSpeedMax()
|
||||||
|
local _speed=Speed or speedmax*0.5
|
||||||
|
_speed=math.min(_speed, speedmax)
|
||||||
|
|
||||||
local Waypoints = APC:TaskGroundOnRoad( Coordinate, _speed, "Line abreast", true )
|
-- Route on road.
|
||||||
|
local Waypoints = {}
|
||||||
|
|
||||||
|
if self.deployOffroad then
|
||||||
|
Waypoints[1]=APC:GetCoordinate():WaypointGround(Speed, self.deployFormation)
|
||||||
|
Waypoints[2]=Coordinate:WaypointGround(_speed, self.deployFormation, DCSTasks)
|
||||||
|
else
|
||||||
|
Waypoints=APC:TaskGroundOnRoad(Coordinate, _speed, ENUMS.Formation.Vehicle.OffRoad, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Task function
|
||||||
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self, Coordinate, DeployZone )
|
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self, Coordinate, DeployZone )
|
||||||
|
|
||||||
self:F({Waypoints = Waypoints})
|
-- Last waypoint
|
||||||
local Waypoint = Waypoints[#Waypoints]
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
|
||||||
|
|
||||||
|
-- Set task function
|
||||||
|
APC:SetTaskWaypoint(Waypoint, TaskFunction) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||||
|
|
||||||
|
-- Route group
|
||||||
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||||
|
|
||||||
|
-- Call parent function.
|
||||||
self:GetParent( self, AI_CARGO_APC ).onafterDeploy( self, APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
self:GetParent( self, AI_CARGO_APC ).onafterDeploy( self, APC, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry (cargo).
|
--- **AI** - Models the intelligent transportation of cargo using airplanes.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -408,9 +408,6 @@ function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To, DeployZone
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Route the airplane from one airport or it's current position to another airbase.
|
--- Route the airplane from one airport or it's current position to another airbase.
|
||||||
-- @param #AI_CARGO_AIRPLANE self
|
-- @param #AI_CARGO_AIRPLANE self
|
||||||
-- @param Wrapper.Group#GROUP Airplane Airplane group to be routed.
|
-- @param Wrapper.Group#GROUP Airplane Airplane group to be routed.
|
||||||
@@ -438,14 +435,10 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Height, Uncontrolled
|
|||||||
|
|
||||||
-- To point.
|
-- To point.
|
||||||
local AirbasePointVec2 = Airbase:GetPointVec2()
|
local AirbasePointVec2 = Airbase:GetPointVec2()
|
||||||
local ToWaypoint = AirbasePointVec2:WaypointAir(
|
local ToWaypoint = AirbasePointVec2:WaypointAir(POINT_VEC3.RoutePointAltType.BARO, "Land", "Landing", Speed or Airplane:GetSpeedMax()*0.8, true, Airbase)
|
||||||
POINT_VEC3.RoutePointAltType.BARO,
|
|
||||||
"Land",
|
--ToWaypoint["airdromeId"] = Airbase:GetID()
|
||||||
"Landing",
|
--ToWaypoint["speed_locked"] = true
|
||||||
Speed or Airplane:GetSpeedMax()*0.8
|
|
||||||
)
|
|
||||||
ToWaypoint["airdromeId"] = Airbase:GetID()
|
|
||||||
ToWaypoint["speed_locked"] = true
|
|
||||||
|
|
||||||
|
|
||||||
-- If self.Airbase~=nil then group is currently at an airbase, where it should be respawned.
|
-- If self.Airbase~=nil then group is currently at an airbase, where it should be respawned.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo.
|
--- **AI** - Models the intelligent transportation of infantry and other cargo.
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
@@ -1104,7 +1104,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
|
|||||||
-- The Pickup sequence ...
|
-- The Pickup sequence ...
|
||||||
-- Check if this Carrier need to go and Pickup something...
|
-- Check if this Carrier need to go and Pickup something...
|
||||||
-- So, if the cargo bay is not full yet with cargo to be loaded ...
|
-- So, if the cargo bay is not full yet with cargo to be loaded ...
|
||||||
self:I( { Carrier = CarrierGroupName, IsRelocating = AI_Cargo:IsRelocating(), IsTransporting = AI_Cargo:IsTransporting() } )
|
self:T( { Carrier = CarrierGroupName, IsRelocating = AI_Cargo:IsRelocating(), IsTransporting = AI_Cargo:IsTransporting() } )
|
||||||
if AI_Cargo:IsRelocating() == false and AI_Cargo:IsTransporting() == false then
|
if AI_Cargo:IsRelocating() == false and AI_Cargo:IsTransporting() == false then
|
||||||
-- ok, so there is a free Carrier
|
-- ok, so there is a free Carrier
|
||||||
-- now find the first cargo that is Unloaded
|
-- now find the first cargo that is Unloaded
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using APCs.
|
--- **AI** - Models the intelligent transportation of infantry and other cargo using APCs.
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
@@ -181,25 +181,36 @@ function AI_CARGO_DISPATCHER_APC:New( APCSet, CargoSet, PickupZoneSet, DeployZon
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- AI cargo
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP APC The APC carrier.
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet Cargo set.
|
||||||
|
-- @return AI.AI_Cargo_APC#AI_CARGO_DISPATCHER_APC AI cargo APC object.
|
||||||
function AI_CARGO_DISPATCHER_APC:AICargo( APC, CargoSet )
|
function AI_CARGO_DISPATCHER_APC:AICargo( APC, CargoSet )
|
||||||
|
|
||||||
return AI_CARGO_APC:New( APC, CargoSet, self.CombatRadius )
|
local aicargoapc=AI_CARGO_APC:New(APC, CargoSet, self.CombatRadius)
|
||||||
|
|
||||||
|
aicargoapc:SetDeployOffRoad(self.deployOffroad, self.deployFormation)
|
||||||
|
aicargoapc:SetPickupOffRoad(self.pickupOffroad, self.pickupFormation)
|
||||||
|
|
||||||
|
return aicargoapc
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
|
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
|
||||||
-- This is only valid for APCs and trucks etc, thus ground vehicles.
|
-- This is only valid for APCs and trucks etc, thus ground vehicles.
|
||||||
-- @param #AI_CARGO_DISPATCHER_APC self
|
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||||
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
|
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
|
||||||
-- When the combat radius is 0, no defense will happen of the carrier.
|
-- When the combat radius is 0 (default), no defense will happen of the carrier.
|
||||||
-- When the combat radius is not provided, no defense will happen!
|
-- When the combat radius is not provided, no defense will happen!
|
||||||
-- @return #AI_CARGO_DISPATCHER_APC
|
-- @return #AI_CARGO_DISPATCHER_APC
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Disembark the infantry when the carrier is under attack.
|
-- -- Disembark the infantry when the carrier is under attack.
|
||||||
-- AICargoDispatcher:SetCombatRadius( true )
|
-- AICargoDispatcher:SetCombatRadius( 500 )
|
||||||
--
|
--
|
||||||
-- -- Keep the cargo in the carrier when the carrier is under attack.
|
-- -- Keep the cargo in the carrier when the carrier is under attack.
|
||||||
-- AICargoDispatcher:SetCombatRadius( false )
|
-- AICargoDispatcher:SetCombatRadius( 0 )
|
||||||
function AI_CARGO_DISPATCHER_APC:SetCombatRadius( CombatRadius )
|
function AI_CARGO_DISPATCHER_APC:SetCombatRadius( CombatRadius )
|
||||||
|
|
||||||
self.CombatRadius = CombatRadius or 0
|
self.CombatRadius = CombatRadius or 0
|
||||||
@@ -207,3 +218,41 @@ function AI_CARGO_DISPATCHER_APC:SetCombatRadius( CombatRadius )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set whether the carrier will *not* use roads to *pickup* and *deploy* the cargo.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||||
|
-- @param #boolean Offroad If true, carrier will not use roads.
|
||||||
|
-- @param #number Formation Offroad formation used. Default is `ENUMS.Formation.Vehicle.Offroad`.
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_APC self
|
||||||
|
function AI_CARGO_DISPATCHER_APC:SetOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
self:SetPickupOffRoad(Offroad, Formation)
|
||||||
|
self:SetDeployOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set whether the carrier will *not* use roads to *pickup* the cargo.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||||
|
-- @param #boolean Offroad If true, carrier will not use roads.
|
||||||
|
-- @param #number Formation Offroad formation used. Default is `ENUMS.Formation.Vehicle.Offroad`.
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_APC self
|
||||||
|
function AI_CARGO_DISPATCHER_APC:SetPickupOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
self.pickupOffroad=Offroad
|
||||||
|
self.pickupFormation=Formation or ENUMS.Formation.Vehicle.OffRoad
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set whether the carrier will *not* use roads to *deploy* the cargo.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||||
|
-- @param #boolean Offroad If true, carrier will not use roads.
|
||||||
|
-- @param #number Formation Offroad formation used. Default is `ENUMS.Formation.Vehicle.Offroad`.
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_APC self
|
||||||
|
function AI_CARGO_DISPATCHER_APC:SetDeployOffRoad(Offroad, Formation)
|
||||||
|
|
||||||
|
self.deployOffroad=Offroad
|
||||||
|
self.deployFormation=Formation or ENUMS.Formation.Vehicle.OffRoad
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
193
Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua
Normal file
193
Moose Development/Moose/AI/AI_Cargo_Dispatcher_Ship.lua
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
--- **AI** -- (2.5.1) - Models the intelligent transportation of infantry and other cargo using Ships
|
||||||
|
--
|
||||||
|
-- ## Features:
|
||||||
|
--
|
||||||
|
-- * Transport cargo to various deploy zones using naval vehicles.
|
||||||
|
-- * Various @{Cargo.Cargo#CARGO} types can be transported, including infantry, vehicles, and crates.
|
||||||
|
-- * Define a deploy zone of various types to determine the destination of the cargo.
|
||||||
|
-- * Ships will follow shipping lanes as defined in the Mission Editor.
|
||||||
|
-- * Multiple ships can transport multiple cargo as a single group.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Test Missions:
|
||||||
|
--
|
||||||
|
-- NEED TO DO
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **acrojason** (derived from AI_Cargo_Dispatcher_APC by FlightControl)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_Dispatcher_Ship
|
||||||
|
-- @image AI_Cargo_Dispatching_For_Ship.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO_DISPATCHER_SHIP
|
||||||
|
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
||||||
|
|
||||||
|
|
||||||
|
--- A dynamic cargo transportation capability for AI groups.
|
||||||
|
--
|
||||||
|
-- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation.
|
||||||
|
--
|
||||||
|
-- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
--
|
||||||
|
-- ## Note! In order to fully understand the mechanisms of the AI_CARGO_DISPATCHER_SHIP class, it is recommended that you first consult and READ the documentation of the @{AI.AI_Cargo_Dispatcher} module!!!
|
||||||
|
--
|
||||||
|
-- This will be particularly helpful in order to determine how to **Tailor the different cargo handling events**.
|
||||||
|
--
|
||||||
|
-- The AI_CARGO_DISPATCHER_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framwork.
|
||||||
|
-- Also ensure that you fully understand how to declare and setup Cargo objects within the MOOSE framework before using this class.
|
||||||
|
-- CARGO derived objects must generally be declared within the mission to make the AI_CARGO_DISPATCHER_SHIP object recognize the cargo.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # 1) AI_CARGO_DISPATCHER_SHIP constructor.
|
||||||
|
--
|
||||||
|
-- * @{AI_CARGO_DISPATCHER_SHIP.New}(): Creates a new AI_CARGO_DISPATCHER_SHIP object.
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 2) AI_CARGO_DISPATCHER_SHIP is a Finite State Machine.
|
||||||
|
--
|
||||||
|
-- This section must be read as follows... Each of the rows indicate a state transition, triggered through an event, and with an ending state of the event was executed.
|
||||||
|
-- The first column is the **From** state, the second column the **Event**, and the third column the **To** state.
|
||||||
|
--
|
||||||
|
-- So, each of the rows have the following structure.
|
||||||
|
--
|
||||||
|
-- * **From** => **Event** => **To**
|
||||||
|
--
|
||||||
|
-- Important to know is that an event can only be executed if the **current state** is the **From** state.
|
||||||
|
-- This, when an **Event** that is being triggered has a **From** state that is equal to the **Current** state of the state machine, the event will be executed,
|
||||||
|
-- and the resulting state will be the **To** state.
|
||||||
|
--
|
||||||
|
-- These are the different possible state transitions of this state machine implementation:
|
||||||
|
--
|
||||||
|
-- * Idle => Start => Monitoring
|
||||||
|
-- * Monitoring => Monitor => Monitoring
|
||||||
|
-- * Monitoring => Stop => Idle
|
||||||
|
--
|
||||||
|
-- * Monitoring => Pickup => Monitoring
|
||||||
|
-- * Monitoring => Load => Monitoring
|
||||||
|
-- * Monitoring => Loading => Monitoring
|
||||||
|
-- * Monitoring => Loaded => Monitoring
|
||||||
|
-- * Monitoring => PickedUp => Monitoring
|
||||||
|
-- * Monitoring => Deploy => Monitoring
|
||||||
|
-- * Monitoring => Unload => Monitoring
|
||||||
|
-- * Monitoring => Unloaded => Monitoring
|
||||||
|
-- * Monitoring => Deployed => Monitoring
|
||||||
|
-- * Monitoring => Home => Monitoring
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- ## 2.1) AI_CARGO_DISPATCHER States.
|
||||||
|
--
|
||||||
|
-- * **Monitoring**: The process is dispatching.
|
||||||
|
-- * **Idle**: The process is idle.
|
||||||
|
--
|
||||||
|
-- ## 2.2) AI_CARGO_DISPATCHER Events.
|
||||||
|
--
|
||||||
|
-- * **Start**: Start the transport process.
|
||||||
|
-- * **Stop**: Stop the transport process.
|
||||||
|
-- * **Monitor**: Monitor and take action.
|
||||||
|
--
|
||||||
|
-- * **Pickup**: Pickup cargo.
|
||||||
|
-- * **Load**: Load the cargo.
|
||||||
|
-- * **Loading**: The dispatcher is coordinating the loading of a cargo.
|
||||||
|
-- * **Loaded**: Flag that the cargo is loaded.
|
||||||
|
-- * **PickedUp**: The dispatcher has loaded all requested cargo into the CarrierGroup.
|
||||||
|
-- * **Deploy**: Deploy cargo to a location.
|
||||||
|
-- * **Unload**: Unload the cargo.
|
||||||
|
-- * **Unloaded**: Flag that the cargo is unloaded.
|
||||||
|
-- * **Deployed**: All cargo is unloaded from the carriers in the group.
|
||||||
|
-- * **Home**: A Carrier is going home.
|
||||||
|
--
|
||||||
|
-- ## 2.3) Enhance your mission scripts with **Tailored** Event Handling!
|
||||||
|
--
|
||||||
|
-- Within your mission, you can capture these events when triggered, and tailor the events with your own code!
|
||||||
|
-- Check out the @{AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER} class at chapter 3 for details on the different event handlers that are available and how to use them.
|
||||||
|
--
|
||||||
|
-- **There are a lot of templates available that allows you to quickly setup an event handler for a specific event type!**
|
||||||
|
--
|
||||||
|
-- ---
|
||||||
|
--
|
||||||
|
-- # 3) Set the pickup parameters.
|
||||||
|
--
|
||||||
|
-- Several parameters can be set to pickup cargo:
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_SHIP.SetPickupRadius}(): Sets or randomizes the pickup location for the Ship around the cargo coordinate in a radius defined an outer and optional inner radius.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_SHIP.SetPickupSpeed}(): Set the speed or randomizes the speed in km/h to pickup the cargo.
|
||||||
|
--
|
||||||
|
-- # 4) Set the deploy parameters.
|
||||||
|
--
|
||||||
|
-- Several parameters can be set to deploy cargo:
|
||||||
|
--
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_SHIP.SetDeployRadius}(): Sets or randomizes the deploy location for the Ship around the cargo coordinate in a radius defined an outer and an optional inner radius.
|
||||||
|
-- * @{#AI_CARGO_DISPATCHER_SHIP.SetDeploySpeed}(): Set the speed or randomizes the speed in km/h to deploy the cargo.
|
||||||
|
--
|
||||||
|
-- # 5) Set the home zone when there isn't any more cargo to pickup.
|
||||||
|
--
|
||||||
|
-- A home zone can be specified to where the Ship will move when there isn't any cargo left for pickup.
|
||||||
|
-- Use @{#AI_CARGO_DISPATCHER_SHIP.SetHomeZone}() to specify the home zone.
|
||||||
|
--
|
||||||
|
-- If no home zone is specified, the Ship will wait near the deploy zone for a new pickup command.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_DISPATCHER_SHIP
|
||||||
|
AI_CARGO_DISPATCHER_SHIP = {
|
||||||
|
ClassName = "AI_CARGO_DISPATCHER_SHIP"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_DISPATCHER_SHIP object.
|
||||||
|
-- @param #AI_CARGO_DISPATCHER_SHIP self
|
||||||
|
-- @param Core.Set#SET_GROUP ShipSet The set of @{Wrapper.Group#GROUP} objects of Ships that will transport the cargo
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet The set of @{Cargo.Cargo#CARGO} objects, which can be CARGO_GROUP, CARGO_CRATE, or CARGO_SLINGLOAD objects.
|
||||||
|
-- @param Core.Set#SET_ZONE PickupZoneSet The set of pickup zones which are used to determine from where the cargo can be picked up by the Ship.
|
||||||
|
-- @param Core.Set#SET_ZONE DeployZoneSet The set of deploy zones which determine where the cargo will be deployed by the Ship.
|
||||||
|
-- @param #table ShippingLane Table containing list of Shipping Lanes to be used
|
||||||
|
-- @return #AI_CARGO_DISPATCHER_SHIP
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- An AI dispatcher object for a naval group, moving cargo from pickup zones to deploy zones via a predetermined Shipping Lane
|
||||||
|
--
|
||||||
|
-- local SetCargoInfantry = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
|
||||||
|
-- local SetShip = SET_GROUP:New():FilterPrefixes( "Ship" ):FilterStart()
|
||||||
|
-- local SetPickupZones = SET_ZONE:New():FilterPrefixes( "Pickup" ):FilterStart()
|
||||||
|
-- local SetDeployZones = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
|
||||||
|
-- NEED MORE THOUGHT - ShippingLane is part of Warehouse.......
|
||||||
|
-- local ShippingLane = GROUP:New():FilterPrefixes( "ShippingLane" ):FilterStart()
|
||||||
|
--
|
||||||
|
-- AICargoDispatcherShip = AI_CARGO_DISPATCHER_SHIP:New( SetShip, SetCargoInfantry, SetPickupZones, SetDeployZones, ShippingLane )
|
||||||
|
-- AICargoDispatcherShip:Start()
|
||||||
|
--
|
||||||
|
function AI_CARGO_DISPATCHER_SHIP:New( ShipSet, CargoSet, PickupZoneSet, DeployZoneSet, ShippingLane )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( ShipSet, CargoSet, PickupZoneSet, DeployZoneSet ) )
|
||||||
|
|
||||||
|
self:SetPickupSpeed( 60, 10 )
|
||||||
|
self:SetDeploySpeed( 60, 10 )
|
||||||
|
|
||||||
|
self:SetPickupRadius( 500, 6000 )
|
||||||
|
self:SetDeployRadius( 500, 6000 )
|
||||||
|
|
||||||
|
self:SetPickupHeight( 0, 0 )
|
||||||
|
self:SetDeployHeight( 0, 0 )
|
||||||
|
|
||||||
|
self:SetShippingLane( ShippingLane )
|
||||||
|
|
||||||
|
self:SetMonitorTimeInterval( 600 )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO_DISPATCHER_SHIP:SetShippingLane( ShippingLane )
|
||||||
|
self.ShippingLane = ShippingLane
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO_DISPATCHER_SHIP:AICargo( Ship, CargoSet )
|
||||||
|
|
||||||
|
return AI_CARGO_SHIP:New( Ship, CargoSet, 0, self.ShippingLane )
|
||||||
|
end
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry (cargo).
|
--- **AI** - Models the intelligent transportation of cargo using helicopters.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Infantry health.
|
-- ## Infantry health.
|
||||||
--
|
--
|
||||||
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield.
|
-- When infantry is unboarded from the helicopters, the infantry is actually respawned into the battlefield.
|
||||||
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
|
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
|
||||||
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
|
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
|
||||||
-- However, infantry that was destroyed when unboarded, won't be respawned again. Destroyed is destroyed.
|
-- However, infantry that was destroyed when unboarded, won't be respawned again. Destroyed is destroyed.
|
||||||
@@ -67,16 +67,11 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
|||||||
|
|
||||||
self:AddTransition( "Unloaded", "Pickup", "*" )
|
self:AddTransition( "Unloaded", "Pickup", "*" )
|
||||||
self:AddTransition( "Loaded", "Deploy", "*" )
|
self:AddTransition( "Loaded", "Deploy", "*" )
|
||||||
|
self:AddTransition( "*", "Loaded", "Loaded" )
|
||||||
self:AddTransition( { "Unloaded", "Loading" }, "Load", "Boarding" )
|
self:AddTransition( "Unboarding", "Pickup", "Unloaded" )
|
||||||
self:AddTransition( "Boarding", "Board", "Boarding" )
|
self:AddTransition( "Unloaded", "Unboard", "Unloaded" )
|
||||||
self:AddTransition( "Boarding", "Loaded", "Boarding" )
|
self:AddTransition( "Unloaded", "Unloaded", "Unloaded" )
|
||||||
self:AddTransition( "Boarding", "PickedUp", "Loaded" )
|
self:AddTransition( "*", "PickedUp", "*" )
|
||||||
self:AddTransition( "Loaded", "Unload", "Unboarding" )
|
|
||||||
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
|
|
||||||
self:AddTransition( "Unboarding", "Unloaded", "Unboarding" )
|
|
||||||
self:AddTransition( "Unboarding", "Deployed", "Unloaded" )
|
|
||||||
|
|
||||||
self:AddTransition( "*", "Landed", "*" )
|
self:AddTransition( "*", "Landed", "*" )
|
||||||
self:AddTransition( "*", "Queue", "*" )
|
self:AddTransition( "*", "Queue", "*" )
|
||||||
self:AddTransition( "*", "Orbit" , "*" )
|
self:AddTransition( "*", "Orbit" , "*" )
|
||||||
@@ -100,13 +95,31 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#COORDINATE Coordinate
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- PickedUp Handler OnAfter for AI_CARGO_HELICOPTER - Cargo set has been picked up, ready to deploy
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterPickedUp
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Wrapper.Group#GROUP Helicopter The helicopter #GROUP object
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit The helicopter #UNIT object
|
||||||
|
|
||||||
|
--- Unloaded Handler OnAfter for AI_CARGO_HELICOPTER - Cargo unloaded, carrier is empty
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterUnloaded
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @param Cargo.CargoGroup#CARGO_GROUP Cargo The #CARGO_GROUP object.
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit The helicopter #UNIT object
|
||||||
|
|
||||||
--- Pickup Trigger for AI_CARGO_HELICOPTER
|
--- Pickup Trigger for AI_CARGO_HELICOPTER
|
||||||
-- @function [parent=#AI_CARGO_HELICOPTER] Pickup
|
-- @function [parent=#AI_CARGO_HELICOPTER] Pickup
|
||||||
-- @param #AI_CARGO_HELICOPTER self
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
-- @param Core.Point#COORDINATE Coordinate
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
--- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER
|
--- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER
|
||||||
-- @function [parent=#AI_CARGO_HELICOPTER] __Pickup
|
-- @function [parent=#AI_CARGO_HELICOPTER] __Pickup
|
||||||
@@ -122,7 +135,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#COORDINATE Coordinate Place at which cargo is deployed.
|
-- @param Core.Point#COORDINATE Coordinate Place at which cargo is deployed.
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
--- Deploy Handler OnAfter for AI_CARGO_HELICOPTER
|
--- Deploy Handler OnAfter for AI_CARGO_HELICOPTER
|
||||||
@@ -132,21 +145,42 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#COORDINATE Coordinate
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- Deployed Handler OnAfter for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] OnAfterDeployed
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
|
||||||
--- Deploy Trigger for AI_CARGO_HELICOPTER
|
--- Deploy Trigger for AI_CARGO_HELICOPTER
|
||||||
-- @function [parent=#AI_CARGO_HELICOPTER] Deploy
|
-- @function [parent=#AI_CARGO_HELICOPTER] Deploy
|
||||||
-- @param #AI_CARGO_HELICOPTER self
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
--- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER
|
--- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER
|
||||||
-- @function [parent=#AI_CARGO_HELICOPTER] __Deploy
|
-- @function [parent=#AI_CARGO_HELICOPTER] __Deploy
|
||||||
-- @param #number Delay Delay in seconds.
|
-- @param #number Delay Delay in seconds.
|
||||||
-- @param #AI_CARGO_HELICOPTER self
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
|
||||||
|
--- Home Trigger for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] Home
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Place to which the helicopter will go.
|
||||||
|
-- @param #number Speed (optional) Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height (optional) Height the Helicopter should be flying at.
|
||||||
|
|
||||||
|
--- Home Asynchronous Trigger for AI_CARGO_HELICOPTER
|
||||||
|
-- @function [parent=#AI_CARGO_HELICOPTER] __Home
|
||||||
|
-- @param #number Delay Delay in seconds.
|
||||||
|
-- @param #AI_CARGO_HELICOPTER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Place to which the helicopter will go.
|
||||||
|
-- @param #number Speed (optional) Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
|
-- @param #number Height (optional) Height the Helicopter should be flying at.
|
||||||
|
|
||||||
-- We need to capture the Crash events for the helicopters.
|
-- We need to capture the Crash events for the helicopters.
|
||||||
-- The helicopter reference is used in the semaphore AI_CARGO_QUEUE.
|
-- The helicopter reference is used in the semaphore AI_CARGO_QUEUE.
|
||||||
@@ -228,7 +262,7 @@ end
|
|||||||
-- @param Event
|
-- @param Event
|
||||||
-- @param To
|
-- @param To
|
||||||
function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
|
function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
|
||||||
|
self:F({From, Event, To})
|
||||||
Helicopter:F( { Name = Helicopter:GetName() } )
|
Helicopter:F( { Name = Helicopter:GetName() } )
|
||||||
|
|
||||||
if Helicopter and Helicopter:IsAlive() then
|
if Helicopter and Helicopter:IsAlive() then
|
||||||
@@ -243,7 +277,7 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
|
|||||||
self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } )
|
self:F( { Helicopter:GetName(), Height = Helicopter:GetHeight( true ), Velocity = Helicopter:GetVelocityKMH() } )
|
||||||
|
|
||||||
if self.RoutePickup == true then
|
if self.RoutePickup == true then
|
||||||
if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then
|
if Helicopter:GetHeight( true ) <= 5.5 and Helicopter:GetVelocityKMH() < 10 then
|
||||||
--self:Load( Helicopter:GetPointVec2() )
|
--self:Load( Helicopter:GetPointVec2() )
|
||||||
self:Load( self.PickupZone )
|
self:Load( self.PickupZone )
|
||||||
self.RoutePickup = false
|
self.RoutePickup = false
|
||||||
@@ -251,7 +285,7 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if self.RouteDeploy == true then
|
if self.RouteDeploy == true then
|
||||||
if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then
|
if Helicopter:GetHeight( true ) <= 5.5 and Helicopter:GetVelocityKMH() < 10 then
|
||||||
self:Unload( self.DeployZone )
|
self:Unload( self.DeployZone )
|
||||||
self.RouteDeploy = false
|
self.RouteDeploy = false
|
||||||
end
|
end
|
||||||
@@ -269,7 +303,7 @@ end
|
|||||||
-- @param Core.Point#COORDINATE Coordinate
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
-- @param #number Speed
|
-- @param #number Speed
|
||||||
function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate, Speed, DeployZone )
|
function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordinate, Speed, DeployZone )
|
||||||
|
self:F({From, Event, To, Coordinate, Speed, DeployZone})
|
||||||
local HelicopterInZone = false
|
local HelicopterInZone = false
|
||||||
|
|
||||||
if Helicopter and Helicopter:IsAlive() == true then
|
if Helicopter and Helicopter:IsAlive() == true then
|
||||||
@@ -309,6 +343,10 @@ function AI_CARGO_HELICOPTER:onafterQueue( Helicopter, From, Event, To, Coordina
|
|||||||
-- )
|
-- )
|
||||||
-- Route[#Route+1] = WaypointFrom
|
-- Route[#Route+1] = WaypointFrom
|
||||||
local CoordinateTo = Coordinate
|
local CoordinateTo = Coordinate
|
||||||
|
|
||||||
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
|
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||||
|
|
||||||
local WaypointTo = CoordinateTo:WaypointAir(
|
local WaypointTo = CoordinateTo:WaypointAir(
|
||||||
"RADIO",
|
"RADIO",
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
@@ -348,28 +386,17 @@ end
|
|||||||
-- @param Core.Point#COORDINATE Coordinate
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
-- @param #number Speed
|
-- @param #number Speed
|
||||||
function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate )
|
function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordinate )
|
||||||
|
self:F({From, Event, To, Coordinate})
|
||||||
|
|
||||||
if Helicopter and Helicopter:IsAlive() then
|
if Helicopter and Helicopter:IsAlive() then
|
||||||
|
|
||||||
local Route = {}
|
local Route = {}
|
||||||
|
|
||||||
-- local CoordinateFrom = Helicopter:GetCoordinate()
|
|
||||||
-- local WaypointFrom = CoordinateFrom:WaypointAir(
|
|
||||||
-- "RADIO",
|
|
||||||
-- POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
-- POINT_VEC3.RoutePointAction.TurningPoint,
|
|
||||||
-- Speed,
|
|
||||||
-- true
|
|
||||||
-- )
|
|
||||||
-- Route[#Route+1] = WaypointFrom
|
|
||||||
local CoordinateTo = Coordinate
|
local CoordinateTo = Coordinate
|
||||||
local WaypointTo = CoordinateTo:WaypointAir(
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
"RADIO",
|
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, 50, true)
|
||||||
50,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
@@ -379,7 +406,7 @@ function AI_CARGO_HELICOPTER:onafterOrbit( Helicopter, From, Event, To, Coordina
|
|||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
-- Now route the helicopter
|
-- Now route the helicopter
|
||||||
Helicopter:Route( Route, 0 )
|
Helicopter:Route(Route, 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -395,7 +422,7 @@ end
|
|||||||
-- @param #boolean Deployed Cargo is deployed.
|
-- @param #boolean Deployed Cargo is deployed.
|
||||||
-- @return #boolean True if all cargo has been unloaded.
|
-- @return #boolean True if all cargo has been unloaded.
|
||||||
function AI_CARGO_HELICOPTER:onafterDeployed( Helicopter, From, Event, To, DeployZone )
|
function AI_CARGO_HELICOPTER:onafterDeployed( Helicopter, From, Event, To, DeployZone )
|
||||||
self:F( { Helicopter, From, Event, To, DeployZone = DeployZone } )
|
self:F( { From, Event, To, DeployZone = DeployZone } )
|
||||||
|
|
||||||
self:Orbit( Helicopter:GetCoordinate(), 50 )
|
self:Orbit( Helicopter:GetCoordinate(), 50 )
|
||||||
|
|
||||||
@@ -408,7 +435,6 @@ function AI_CARGO_HELICOPTER:onafterDeployed( Helicopter, From, Event, To, Deplo
|
|||||||
|
|
||||||
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterDeployed( self, Helicopter, From, Event, To, DeployZone )
|
self:GetParent( self, AI_CARGO_HELICOPTER ).onafterDeployed( self, Helicopter, From, Event, To, DeployZone )
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after Pickup event.
|
--- On after Pickup event.
|
||||||
@@ -418,10 +444,11 @@ end
|
|||||||
-- @param Event
|
-- @param Event
|
||||||
-- @param To
|
-- @param To
|
||||||
-- @param Core.Point#COORDINATE Coordinate Pickup place.
|
-- @param Core.Point#COORDINATE Coordinate Pickup place.
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
-- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs.
|
-- @param #number Height Height in meters to move to the pickup coordinate. This parameter is ignored for APCs.
|
||||||
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
self:F({Coordinate, Speed, Height, PickupZone })
|
||||||
|
|
||||||
if Helicopter and Helicopter:IsAlive() ~= nil then
|
if Helicopter and Helicopter:IsAlive() ~= nil then
|
||||||
|
|
||||||
@@ -436,25 +463,16 @@ function AI_CARGO_HELICOPTER:onafterPickup( Helicopter, From, Event, To, Coordin
|
|||||||
|
|
||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
|
|
||||||
|
--- Create a route point of type air.
|
||||||
|
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
||||||
|
|
||||||
|
--- Create a route point of type air.
|
||||||
local CoordinateTo = Coordinate
|
local CoordinateTo = Coordinate
|
||||||
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
|
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||||
|
|
||||||
--- Create a route point of type air.
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,_speed, true)
|
||||||
local WaypointFrom = CoordinateFrom:WaypointAir(
|
|
||||||
"RADIO",
|
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
|
||||||
_speed,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
--- Create a route point of type air.
|
|
||||||
local WaypointTo = CoordinateTo:WaypointAir(
|
|
||||||
"RADIO",
|
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
|
||||||
_speed,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
@@ -495,10 +513,10 @@ end
|
|||||||
-- @param Event
|
-- @param Event
|
||||||
-- @param To
|
-- @param To
|
||||||
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
-- @param #number Height Height in meters to move to the deploy coordinate.
|
-- @param #number Height Height in meters to move to the deploy coordinate.
|
||||||
function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
self:F({From, Event, To, Coordinate, Speed, Height, DeployZone})
|
||||||
if Helicopter and Helicopter:IsAlive() ~= nil then
|
if Helicopter and Helicopter:IsAlive() ~= nil then
|
||||||
|
|
||||||
self.RouteDeploy = true
|
self.RouteDeploy = true
|
||||||
@@ -514,25 +532,17 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
|||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
local WaypointFrom = CoordinateFrom:WaypointAir(
|
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
||||||
"RADIO",
|
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
|
||||||
_speed,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
|
|
||||||
local CoordinateTo = Coordinate
|
local CoordinateTo = Coordinate
|
||||||
local WaypointTo = CoordinateTo:WaypointAir(
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
"RADIO",
|
CoordinateTo.y = landheight + 50 -- flight height should be 50m above ground
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, _speed, true)
|
||||||
_speed,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
@@ -542,7 +552,9 @@ function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordin
|
|||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
|
|
||||||
|
-- The _Deploy function does not exist.
|
||||||
Tasks[#Tasks+1] = Helicopter:TaskFunction( "AI_CARGO_HELICOPTER._Deploy", self, Coordinate, DeployZone )
|
Tasks[#Tasks+1] = Helicopter:TaskFunction( "AI_CARGO_HELICOPTER._Deploy", self, Coordinate, DeployZone )
|
||||||
|
|
||||||
Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), _speed, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) )
|
Tasks[#Tasks+1] = Helicopter:TaskOrbitCircle( math.random( 30, 100 ), _speed, CoordinateTo:GetRandomCoordinateInRadius( 800, 500 ) )
|
||||||
|
|
||||||
--Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
|
--Tasks[#Tasks+1] = Helicopter:TaskLandAtVec2( CoordinateTo:GetVec2() )
|
||||||
@@ -566,10 +578,11 @@ end
|
|||||||
-- @param Event
|
-- @param Event
|
||||||
-- @param To
|
-- @param To
|
||||||
-- @param Core.Point#COORDINATE Coordinate Home place.
|
-- @param Core.Point#COORDINATE Coordinate Home place.
|
||||||
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
-- @param #number Speed Speed in km/h to fly to the pickup coordinate. Default is 50% of max possible speed the unit can go.
|
||||||
-- @param #number Height Height in meters to move to the home coordinate.
|
-- @param #number Height Height in meters to move to the home coordinate.
|
||||||
-- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
-- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate, Speed, Height, HomeZone )
|
function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinate, Speed, Height, HomeZone )
|
||||||
|
self:F({From, Event, To, Coordinate, Speed, Height})
|
||||||
|
|
||||||
if Helicopter and Helicopter:IsAlive() ~= nil then
|
if Helicopter and Helicopter:IsAlive() ~= nil then
|
||||||
|
|
||||||
@@ -579,30 +592,23 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
|||||||
|
|
||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
|
|
||||||
Coordinate.y = Height
|
--Coordinate.y = Height
|
||||||
|
Height = Height or 50
|
||||||
|
|
||||||
Speed = Speed or Helicopter:GetSpeedMax()*0.5
|
Speed = Speed or Helicopter:GetSpeedMax()*0.5
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local CoordinateFrom = Helicopter:GetCoordinate()
|
local CoordinateFrom = Helicopter:GetCoordinate()
|
||||||
local WaypointFrom = CoordinateFrom:WaypointAir(
|
|
||||||
"RADIO",
|
local WaypointFrom = CoordinateFrom:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true)
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
|
||||||
Speed ,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
Route[#Route+1] = WaypointFrom
|
Route[#Route+1] = WaypointFrom
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local CoordinateTo = Coordinate
|
local CoordinateTo = Coordinate
|
||||||
local WaypointTo = CoordinateTo:WaypointAir(
|
local landheight = CoordinateTo:GetLandHeight() -- get target height
|
||||||
"RADIO",
|
CoordinateTo.y = landheight + Height -- flight height should be 50m above ground
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
local WaypointTo = CoordinateTo:WaypointAir("RADIO", POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, Speed, true)
|
||||||
Speed ,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
@@ -617,8 +623,7 @@ function AI_CARGO_HELICOPTER:onafterHome( Helicopter, From, Event, To, Coordinat
|
|||||||
Route[#Route+1] = WaypointTo
|
Route[#Route+1] = WaypointTo
|
||||||
|
|
||||||
-- Now route the helicopter
|
-- Now route the helicopter
|
||||||
Helicopter:Route( Route, 0 )
|
Helicopter:Route(Route, 0)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
397
Moose Development/Moose/AI/AI_Cargo_Ship.lua
Normal file
397
Moose Development/Moose/AI/AI_Cargo_Ship.lua
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
--- **AI** -- (R2.5.1) - Models the intelligent transportation of infantry and other cargo.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **acrojason** (derived from AI_Cargo_APC by FlightControl)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module AI.AI_Cargo_Ship
|
||||||
|
-- @image AI_Cargo_Dispatching_For_Ship.JPG
|
||||||
|
|
||||||
|
--- @type AI_CARGO_SHIP
|
||||||
|
-- @extends AI.AI_Cargo#AI_CARGO
|
||||||
|
|
||||||
|
--- Brings a dynamic cargo handling capability for an AI naval group.
|
||||||
|
--
|
||||||
|
-- Naval ships can be utilized to transport cargo around the map following naval shipping lanes.
|
||||||
|
-- The AI_CARGO_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
|
-- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo.
|
||||||
|
-- Please consult the @{Cargo.Cargo} module for more information.
|
||||||
|
--
|
||||||
|
-- ## Cargo loading.
|
||||||
|
--
|
||||||
|
-- The module will automatically load cargo when the Ship is within boarding or loading radius.
|
||||||
|
-- The boarding or loading radius is specified when the cargo is created in the simulation and depends on the type of
|
||||||
|
-- cargo and the specified boarding radius.
|
||||||
|
--
|
||||||
|
-- ## Defending the Ship when enemies are nearby
|
||||||
|
-- This is not supported for naval cargo because most tanks don't float. Protect your transports...
|
||||||
|
--
|
||||||
|
-- ## Infantry or cargo **health**.
|
||||||
|
-- When cargo is unboarded from the Ship, the cargo is actually respawned into the battlefield.
|
||||||
|
-- As a result, the unboarding cargo is very _healthy_ every time it unboards.
|
||||||
|
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of newly spawned units as a parameter.
|
||||||
|
-- However, cargo that was destroyed when unboarded and following the Ship won't be respawned again (this is likely not a thing for
|
||||||
|
-- naval cargo due to the lack of support for defending the Ship mentioned above). Destroyed is destroyed.
|
||||||
|
-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance
|
||||||
|
-- this has marginal impact on the overall battlefield simulation. Given the relatively short duration of DCS missions and the somewhat
|
||||||
|
-- lengthy naval transport times, most units entering the Ship as cargo will be freshly en route to an amphibious landing or transporting
|
||||||
|
-- between warehouses.
|
||||||
|
--
|
||||||
|
-- ## Control the Ships on the map.
|
||||||
|
--
|
||||||
|
-- Currently, naval transports can only be controlled via scripts due to their reliance upon predefined Shipping Lanes created in the Mission
|
||||||
|
-- Editor. An interesting future enhancement could leverage new pathfinding functionality for ships in the Ops module.
|
||||||
|
--
|
||||||
|
-- ## Cargo deployment.
|
||||||
|
--
|
||||||
|
-- Using the @{AI_CARGO_SHIP.Deploy}() method, you are able to direct the Ship towards a Deploy zone to unboard/unload the cargo at the
|
||||||
|
-- specified coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
||||||
|
--
|
||||||
|
-- ## Cargo pickup.
|
||||||
|
--
|
||||||
|
-- Using the @{AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
|
||||||
|
-- coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #AI_CARGO_SHIP
|
||||||
|
AI_CARGO_SHIP = {
|
||||||
|
ClassName = "AI_CARGO_SHIP",
|
||||||
|
Coordinate = nil -- Core.Point#COORDINATE
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new AI_CARGO_SHIP object.
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
-- @param Wrapper.Group#GROUP Ship The carrier Ship group
|
||||||
|
-- @param Core.Set#SET_CARGO CargoSet The set of cargo to be transported
|
||||||
|
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby. When CombatRadius is 0, no defense will occur.
|
||||||
|
-- @param #table ShippingLane Table containing list of Shipping Lanes to be used
|
||||||
|
-- @return #AI_CARGO_SHIP
|
||||||
|
function AI_CARGO_SHIP:New( Ship, CargoSet, CombatRadius, ShippingLane )
|
||||||
|
|
||||||
|
local self = BASE:Inherit( self, AI_CARGO:New( Ship, CargoSet ) ) -- #AI_CARGO_SHIP
|
||||||
|
|
||||||
|
self:AddTransition( "*", "Monitor", "*" )
|
||||||
|
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||||
|
self:AddTransition( "*", "Home", "*" )
|
||||||
|
|
||||||
|
self:SetCombatRadius( 0 ) -- Don't want to deploy cargo in middle of water to defend Ship, so set CombatRadius to 0
|
||||||
|
self:SetShippingLane ( ShippingLane )
|
||||||
|
|
||||||
|
self:SetCarrier( Ship )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the Carrier
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||||
|
-- @return #AI_CARGO_SHIP
|
||||||
|
function AI_CARGO_SHIP:SetCarrier( CargoCarrier )
|
||||||
|
self.CargoCarrier = CargoCarrier -- Wrapper.Group#GROUIP
|
||||||
|
self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_SHIP", self )
|
||||||
|
|
||||||
|
CargoCarrier:HandleEvent( EVENTS.Dead )
|
||||||
|
|
||||||
|
function CargoCarrier:OnEventDead( EventData )
|
||||||
|
self:F({"dead"})
|
||||||
|
local AICargoTroops = self:GetState( self, "AI_CARGO_SHIP" )
|
||||||
|
self:F({AICargoTroops=AICargoTroops})
|
||||||
|
if AICargoTroops then
|
||||||
|
self:F({})
|
||||||
|
if not AICargoTroops:Is( "Loaded" ) then
|
||||||
|
-- Better hope they can swim!
|
||||||
|
AICargoTroops:Destroyed()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius )
|
||||||
|
self.Coalition = self.CargoCarrier:GetCoalition()
|
||||||
|
|
||||||
|
self:SetControllable( CargoCarrier )
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- FInd a free Carrier within a radius
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
|
-- @param #number Radius
|
||||||
|
-- @return Wrapper.Group#GROUP NewCarrier
|
||||||
|
function AI_CARGO_SHIP:FindCarrier( Coordinate, Radius )
|
||||||
|
|
||||||
|
local CoordinateZone = ZONE_RADIUS:New( "Zone", Coordinate:GetVec2(), Radius )
|
||||||
|
CoordinateZone:Scan( { Object.Category.UNIT } )
|
||||||
|
for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do
|
||||||
|
local NearUnit = UNIT:Find( DCSUnit )
|
||||||
|
self:F({NearUnit=NearUnit})
|
||||||
|
if not NearUnit:GetState( NearUnit, "AI_CARGO_SHIP" ) then
|
||||||
|
local Attributes = NearUnit:GetDesc()
|
||||||
|
self:F({Desc=Attributes})
|
||||||
|
if NearUnit:HasAttributes( "Trucks" ) then
|
||||||
|
return NearUnit:GetGroup()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO_SHIP:SetShippingLane( ShippingLane )
|
||||||
|
self.ShippingLane = ShippingLane
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO_SHIP:SetCombatRadius( CombatRadius )
|
||||||
|
self.CombatRadius = CombatRadius or 0
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Follow Infantry to the Carrier
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
-- @param #AI_CARGO_SHIP Me
|
||||||
|
-- @param Wrapper.Unit#UNIT ShipUnit
|
||||||
|
-- @param Cargo.CargoGroup#CARGO_GROUP Cargo
|
||||||
|
-- @return #AI_CARGO_SHIP
|
||||||
|
function AI_CARGO_SHIP:FollowToCarrier( Me, ShipUnit, CargoGroup )
|
||||||
|
|
||||||
|
local InfantryGroup = CargoGroup:GetGroup()
|
||||||
|
|
||||||
|
self:F( { self=self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } )
|
||||||
|
|
||||||
|
if ShipUnit:IsAlive() then
|
||||||
|
-- Check if the Cargo is near the CargoCarrier
|
||||||
|
if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", ShipUnit, 1000 ) ) then
|
||||||
|
|
||||||
|
-- Cargo does not need to navigate to Carrier
|
||||||
|
Me:Guard()
|
||||||
|
else
|
||||||
|
|
||||||
|
self:F( { InfantryGroup = InfantryGroup:GetName() } )
|
||||||
|
if InfantryGroup:IsAlive() then
|
||||||
|
|
||||||
|
self:F( { InfantryGroup = InfantryGroup:GetName() } )
|
||||||
|
local Waypoints = {}
|
||||||
|
|
||||||
|
-- Calculate new route
|
||||||
|
local FromCoord = InfantryGroup:GetCoordinate()
|
||||||
|
local FromGround = FromCoord:WaypointGround( 10, "Diamond" )
|
||||||
|
self:F({FromGround=FromGround})
|
||||||
|
table.insert( Waypoints, FromGround )
|
||||||
|
|
||||||
|
local ToCoord = ShipUnit:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 )
|
||||||
|
local ToGround = ToCoord:WaypointGround( 10, "Diamond" )
|
||||||
|
self:F({ToGround=ToGround})
|
||||||
|
table.insert( Waypoints, ToGround )
|
||||||
|
|
||||||
|
local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_SHIP.FollowToCarrier", Me, ShipUnit, CargoGroup )
|
||||||
|
|
||||||
|
self:F({Waypoints=Waypoints})
|
||||||
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
|
InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone
|
||||||
|
|
||||||
|
InfantryGroup:Route( Waypoints, 1 ) -- Move after a random number of seconds to the Route. See Route method for details
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function AI_CARGO_SHIP:onafterMonitor( Ship, From, Event, To )
|
||||||
|
self:F( { Ship, From, Event, To, IsTransporting = self:IsTransporting() } )
|
||||||
|
|
||||||
|
if self.CombatRadius > 0 then
|
||||||
|
-- We really shouldn't find ourselves in here for Ships since the CombatRadius should always be 0.
|
||||||
|
-- This is to avoid Unloading the Ship in the middle of the sea.
|
||||||
|
if Ship and Ship:IsAlive() then
|
||||||
|
if self.CarrierCoordinate then
|
||||||
|
if self:IsTransporting() == true then
|
||||||
|
local Coordinate = Ship:GetCoordinate()
|
||||||
|
if self:Is( "Unloaded" ) or self:Is( "Loaded" ) then
|
||||||
|
self.Zone:Scan( { Object.Category.UNIT } )
|
||||||
|
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||||
|
if self:Is( "Unloaded" ) then
|
||||||
|
-- There are no enemies within combat radius. Reload the CargoCarrier.
|
||||||
|
self:Reload()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if self:Is( "Loaded" ) then
|
||||||
|
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||||
|
self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy!
|
||||||
|
else
|
||||||
|
if self:Is( "Unloaded" ) then
|
||||||
|
--self:Follow()
|
||||||
|
end
|
||||||
|
self:F( "I am here" .. self:GetCurrentState() )
|
||||||
|
if self:Is( "Following" ) then
|
||||||
|
for Cargo, ShipUnit in pairs( self.Carrier_Cargo ) do
|
||||||
|
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||||
|
local ShipUnit = ShipUnit -- Wrapper.Unit#UNIT
|
||||||
|
if Cargo:IsAlive() then
|
||||||
|
if not Cargo:IsNear( ShipUnit, 40 ) then
|
||||||
|
ShipUnit:RouteStop()
|
||||||
|
self.CarrierStopped = true
|
||||||
|
else
|
||||||
|
if self.CarrierStopped then
|
||||||
|
if Cargo:IsNear( ShipUnit, 25 ) then
|
||||||
|
ShipUnit:RouteResume()
|
||||||
|
self.CarrierStopped = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.CarrierCoordinate = Ship:GetCoordinate()
|
||||||
|
end
|
||||||
|
self:__Monitor( -5 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if cargo ship is alive and trigger Load event
|
||||||
|
-- @param Wrapper.Group#Group Ship
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
function AI_CARGO_SHIP._Pickup( Ship, self, Coordinate, Speed, PickupZone )
|
||||||
|
|
||||||
|
Ship:F( { "AI_CARGO_Ship._Pickup:", Ship:GetName() } )
|
||||||
|
|
||||||
|
if Ship:IsAlive() then
|
||||||
|
self:Load( PickupZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if cargo ship is alive and trigger Unload event. Good time to remind people that Lua is case sensitive and Unload != UnLoad
|
||||||
|
-- @param Wrapper.Group#GROUP Ship
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
function AI_CARGO_SHIP._Deploy( Ship, self, Coordinate, DeployZone )
|
||||||
|
Ship:F( { "AI_CARGO_Ship._Deploy:", Ship } )
|
||||||
|
|
||||||
|
if Ship:IsAlive() then
|
||||||
|
self:Unload( DeployZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- on after Pickup event.
|
||||||
|
-- @param AI_CARGO_SHIP Ship
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate of the pickup point
|
||||||
|
-- @param #number Speed Speed in km/h to sail to the pickup coordinate. Default is 50% of max speed for the unit
|
||||||
|
-- @param #number Height Altitude in meters to move to the pickup coordinate. This parameter is ignored for Ships
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil if there was no PickupZoneSet provided
|
||||||
|
function AI_CARGO_SHIP:onafterPickup( Ship, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
|
||||||
|
if Ship and Ship:IsAlive() then
|
||||||
|
AI_CARGO_SHIP._Pickup( Ship, self, Coordinate, Speed, PickupZone )
|
||||||
|
self:GetParent( self, AI_CARGO_SHIP ).onafterPickup( self, Ship, From, Event, To, Coordinate, Speed, Height, PickupZone )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Deploy event.
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
-- @param Wrapper.Group#GROUP SHIP
|
||||||
|
-- @param From
|
||||||
|
-- @param Event
|
||||||
|
-- @param To
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Coordinate of the deploy point
|
||||||
|
-- @param #number Speed Speed in km/h to sail to the deploy coordinate. Default is 50% of max speed for the unit
|
||||||
|
-- @param #number Height Altitude in meters to move to the deploy coordinate. This parameter is ignored for Ships
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone where the cargo will be deployed.
|
||||||
|
function AI_CARGO_SHIP:onafterDeploy( Ship, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
|
||||||
|
if Ship and Ship:IsAlive() then
|
||||||
|
|
||||||
|
Speed = Speed or Ship:GetSpeedMax()*0.8
|
||||||
|
local lane = self.ShippingLane
|
||||||
|
|
||||||
|
if lane then
|
||||||
|
local Waypoints = {}
|
||||||
|
|
||||||
|
for i=1, #lane do
|
||||||
|
local coord = lane[i]
|
||||||
|
local Waypoint = coord:WaypointGround(_speed)
|
||||||
|
table.insert(Waypoints, Waypoint)
|
||||||
|
end
|
||||||
|
|
||||||
|
local TaskFunction = Ship:TaskFunction( "AI_CARGO_SHIP._Deploy", self, Coordinate, DeployZone )
|
||||||
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
|
Ship:SetTaskWaypoint( Waypoint, TaskFunction )
|
||||||
|
Ship:Route(Waypoints, 1)
|
||||||
|
self:GetParent( self, AI_CARGO_SHIP ).onafterDeploy( self, Ship, From, Event, To, Coordinate, Speed, Height, DeployZone )
|
||||||
|
else
|
||||||
|
self:E(self.lid.."ERROR: No shipping lane defined for Naval Transport!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after Unload event.
|
||||||
|
-- @param #AI_CARGO_SHIP self
|
||||||
|
-- @param Wrapper.Group#GROUP Ship
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO_SHIP:onafterUnload( Ship, From, Event, To, DeployZone, Defend )
|
||||||
|
self:F( { Ship, From, Event, To, DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
|
local UnboardInterval = 5
|
||||||
|
local UnboardDelay = 5
|
||||||
|
|
||||||
|
if Ship and Ship:IsAlive() then
|
||||||
|
for _, ShipUnit in pairs( Ship:GetUnits() ) do
|
||||||
|
local ShipUnit = ShipUnit -- Wrapper.Unit#UNIT
|
||||||
|
Ship:RouteStop()
|
||||||
|
for _, Cargo in pairs( ShipUnit:GetCargo() ) do
|
||||||
|
self:F( { Cargo = Cargo:GetName(), Isloaded = Cargo:IsLoaded() } )
|
||||||
|
if Cargo:IsLoaded() then
|
||||||
|
local unboardCoord = DeployZone:GetRandomPointVec2()
|
||||||
|
Cargo:__UnBoard( UnboardDelay, unboardCoord, 1000)
|
||||||
|
UnboardDelay = UnboardDelay + Cargo:GetCount() * UnboardInterval
|
||||||
|
self:__Unboard( UnboardDelay, Cargo, ShipUnit, DeployZone, Defend )
|
||||||
|
if not Defend == true then
|
||||||
|
Cargo:SetDeployed( true )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function AI_CARGO_SHIP:onafterHome( Ship, From, Event, To, Coordinate, Speed, Height, HomeZone )
|
||||||
|
if Ship and Ship:IsAlive() then
|
||||||
|
|
||||||
|
self.RouteHome = true
|
||||||
|
Speed = Speed or Ship:GetSpeedMax()*0.8
|
||||||
|
local lane = self.ShippingLane
|
||||||
|
|
||||||
|
if lane then
|
||||||
|
local Waypoints = {}
|
||||||
|
|
||||||
|
-- Need to find a more generalized way to do this instead of reversing the shipping lane.
|
||||||
|
-- This only works if the Source/Dest route waypoints are numbered 1..n and not n..1
|
||||||
|
for i=#lane, 1, -1 do
|
||||||
|
local coord = lane[i]
|
||||||
|
local Waypoint = coord:WaypointGround(_speed)
|
||||||
|
table.insert(Waypoints, Waypoint)
|
||||||
|
end
|
||||||
|
|
||||||
|
local Waypoint = Waypoints[#Waypoints]
|
||||||
|
Ship:Route(Waypoints, 1)
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E(self.lid.."ERROR: No shipping lane defined for Naval Transport!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -164,7 +164,7 @@ AI_FORMATION.__Enum.ReportType = {
|
|||||||
--- MENUPARAM type
|
--- MENUPARAM type
|
||||||
-- @type MENUPARAM
|
-- @type MENUPARAM
|
||||||
-- @field #AI_FORMATION ParamSelf
|
-- @field #AI_FORMATION ParamSelf
|
||||||
-- @field #Distance ParamDistance
|
-- @field #number ParamDistance
|
||||||
-- @field #function ParamFunction
|
-- @field #function ParamFunction
|
||||||
-- @field #string ParamMessage
|
-- @field #string ParamMessage
|
||||||
|
|
||||||
@@ -184,11 +184,13 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
|
|
||||||
self.FollowGroupSet:ForEachGroup(
|
self.FollowGroupSet:ForEachGroup(
|
||||||
function( FollowGroup )
|
function( FollowGroup )
|
||||||
self:E("Following")
|
--self:E("Following")
|
||||||
FollowGroup:SetState( self, "Mode", self.__Enum.Mode.Formation )
|
FollowGroup:SetState( self, "Mode", self.__Enum.Mode.Formation )
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self:SetFlightModeFormation()
|
||||||
|
|
||||||
self:SetFlightRandomization( 2 )
|
self:SetFlightRandomization( 2 )
|
||||||
|
|
||||||
self:SetStartState( "None" )
|
self:SetStartState( "None" )
|
||||||
@@ -207,9 +209,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -222,9 +224,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationLine Trigger for AI_FORMATION
|
--- FormationLine Trigger for AI_FORMATION
|
||||||
@@ -232,9 +234,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationLine Asynchronous Trigger for AI_FORMATION
|
--- FormationLine Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -243,9 +245,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationTrail", "*" )
|
self:AddTransition( "*", "FormationTrail", "*" )
|
||||||
@@ -257,7 +259,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
--- FormationTrail Handler OnAfter for AI_FORMATION
|
--- FormationTrail Handler OnAfter for AI_FORMATION
|
||||||
@@ -268,14 +270,14 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
|
|
||||||
--- FormationTrail Trigger for AI_FORMATION
|
--- FormationTrail Trigger for AI_FORMATION
|
||||||
-- @function [parent=#AI_FORMATION] FormationTrail
|
-- @function [parent=#AI_FORMATION] FormationTrail
|
||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
|
|
||||||
--- FormationTrail Asynchronous Trigger for AI_FORMATION
|
--- FormationTrail Asynchronous Trigger for AI_FORMATION
|
||||||
-- @function [parent=#AI_FORMATION] __FormationTrail
|
-- @function [parent=#AI_FORMATION] __FormationTrail
|
||||||
@@ -283,7 +285,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationStack", "*" )
|
self:AddTransition( "*", "FormationStack", "*" )
|
||||||
--- FormationStack Handler OnBefore for AI_FORMATION
|
--- FormationStack Handler OnBefore for AI_FORMATION
|
||||||
@@ -294,7 +296,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -306,7 +308,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationStack Trigger for AI_FORMATION
|
--- FormationStack Trigger for AI_FORMATION
|
||||||
@@ -314,7 +316,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationStack Asynchronous Trigger for AI_FORMATION
|
--- FormationStack Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -323,7 +325,7 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationLeftLine", "*" )
|
self:AddTransition( "*", "FormationLeftLine", "*" )
|
||||||
@@ -335,8 +337,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -348,16 +350,16 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationLeftLine Trigger for AI_FORMATION
|
--- FormationLeftLine Trigger for AI_FORMATION
|
||||||
-- @function [parent=#AI_FORMATION] FormationLeftLine
|
-- @function [parent=#AI_FORMATION] FormationLeftLine
|
||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationLeftLine Asynchronous Trigger for AI_FORMATION
|
--- FormationLeftLine Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -365,8 +367,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationRightLine", "*" )
|
self:AddTransition( "*", "FormationRightLine", "*" )
|
||||||
@@ -378,8 +380,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -391,16 +393,16 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationRightLine Trigger for AI_FORMATION
|
--- FormationRightLine Trigger for AI_FORMATION
|
||||||
-- @function [parent=#AI_FORMATION] FormationRightLine
|
-- @function [parent=#AI_FORMATION] FormationRightLine
|
||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationRightLine Asynchronous Trigger for AI_FORMATION
|
--- FormationRightLine Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -408,8 +410,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationLeftWing", "*" )
|
self:AddTransition( "*", "FormationLeftWing", "*" )
|
||||||
@@ -422,8 +424,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -436,8 +438,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationLeftWing Trigger for AI_FORMATION
|
--- FormationLeftWing Trigger for AI_FORMATION
|
||||||
@@ -445,8 +447,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationLeftWing Asynchronous Trigger for AI_FORMATION
|
--- FormationLeftWing Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -455,8 +457,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationRightWing", "*" )
|
self:AddTransition( "*", "FormationRightWing", "*" )
|
||||||
@@ -469,8 +471,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -483,8 +485,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationRightWing Trigger for AI_FORMATION
|
--- FormationRightWing Trigger for AI_FORMATION
|
||||||
@@ -492,8 +494,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationRightWing Asynchronous Trigger for AI_FORMATION
|
--- FormationRightWing Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -502,8 +504,8 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationCenterWing", "*" )
|
self:AddTransition( "*", "FormationCenterWing", "*" )
|
||||||
@@ -516,9 +518,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -531,9 +533,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationCenterWing Trigger for AI_FORMATION
|
--- FormationCenterWing Trigger for AI_FORMATION
|
||||||
@@ -541,9 +543,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationCenterWing Asynchronous Trigger for AI_FORMATION
|
--- FormationCenterWing Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -552,9 +554,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationVic", "*" )
|
self:AddTransition( "*", "FormationVic", "*" )
|
||||||
@@ -566,9 +568,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
@@ -580,9 +582,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationVic Trigger for AI_FORMATION
|
--- FormationVic Trigger for AI_FORMATION
|
||||||
@@ -590,9 +592,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
--- FormationVic Asynchronous Trigger for AI_FORMATION
|
--- FormationVic Asynchronous Trigger for AI_FORMATION
|
||||||
@@ -601,9 +603,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
|
|
||||||
self:AddTransition( "*", "FormationBox", "*" )
|
self:AddTransition( "*", "FormationBox", "*" )
|
||||||
@@ -615,9 +617,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
@@ -630,9 +632,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||||
|
|
||||||
@@ -641,9 +643,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #AI_FORMATION self
|
-- @param #AI_FORMATION self
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||||
|
|
||||||
@@ -653,9 +655,9 @@ function AI_FORMATION:New( FollowUnit, FollowGroupSet, FollowName, FollowBriefin
|
|||||||
-- @param #number Delay
|
-- @param #number Delay
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||||
|
|
||||||
@@ -704,9 +706,9 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation ) --R2.1
|
function AI_FORMATION:onafterFormationLine( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace, Formation ) --R2.1
|
||||||
@@ -751,7 +753,7 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
function AI_FORMATION:onafterFormationTrail( FollowGroupSet, From , Event , To, XStart, XSpace, YStart ) --R2.1
|
function AI_FORMATION:onafterFormationTrail( FollowGroupSet, From , Event , To, XStart, XSpace, YStart ) --R2.1
|
||||||
|
|
||||||
@@ -769,7 +771,7 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
function AI_FORMATION:onafterFormationStack( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace ) --R2.1
|
function AI_FORMATION:onafterFormationStack( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace ) --R2.1
|
||||||
@@ -789,8 +791,8 @@ end
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1
|
function AI_FORMATION:onafterFormationLeftLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1
|
||||||
@@ -808,8 +810,8 @@ end
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1
|
function AI_FORMATION:onafterFormationRightLine( FollowGroupSet, From , Event , To, XStart, YStart, ZStart, ZSpace ) --R2.1
|
||||||
@@ -828,8 +830,8 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1
|
function AI_FORMATION:onafterFormationLeftWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1
|
||||||
|
|
||||||
@@ -848,8 +850,8 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1
|
function AI_FORMATION:onafterFormationRightWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, ZStart, ZSpace ) --R2.1
|
||||||
|
|
||||||
@@ -867,9 +869,9 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
|
function AI_FORMATION:onafterFormationCenterWing( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
|
||||||
|
|
||||||
@@ -905,9 +907,9 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
function AI_FORMATION:onafterFormationVic( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
|
function AI_FORMATION:onafterFormationVic( FollowGroupSet, From , Event , To, XStart, XSpace, YStart, YSpace, ZStart, ZSpace ) --R2.1
|
||||||
@@ -924,9 +926,9 @@ end
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
-- @param #number XStart The start position on the X-axis in meters for the first group.
|
||||||
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
-- @param #number XSpace The space between groups on the X-axis in meters for each sequent group.
|
||||||
-- @param #nubmer YStart The start position on the Y-axis in meters for the first group.
|
-- @param #number YStart The start position on the Y-axis in meters for the first group.
|
||||||
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
-- @param #number YSpace The space between groups on the Y-axis in meters for each sequent group.
|
||||||
-- @param #nubmer ZStart The start position on the Z-axis in meters for the first group.
|
-- @param #number ZStart The start position on the Z-axis in meters for the first group.
|
||||||
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
-- @param #number ZSpace The space between groups on the Z-axis in meters for each sequent group.
|
||||||
-- @param #number ZLevels The amount of levels on the Z-axis.
|
-- @param #number ZLevels The amount of levels on the Z-axis.
|
||||||
-- @return #AI_FORMATION
|
-- @return #AI_FORMATION
|
||||||
@@ -997,7 +999,7 @@ function AI_FORMATION:SetFlightModeMission( FollowGroup )
|
|||||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
|
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Mission )
|
||||||
else
|
else
|
||||||
self.EscortGroupSet:ForSomeGroupAlive(
|
self.FollowGroupSet:ForSomeGroupAlive(
|
||||||
--- @param Core.Group#GROUP EscortGroup
|
--- @param Core.Group#GROUP EscortGroup
|
||||||
function( FollowGroup )
|
function( FollowGroup )
|
||||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||||
@@ -1021,7 +1023,7 @@ function AI_FORMATION:SetFlightModeAttack( FollowGroup )
|
|||||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
|
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Attack )
|
||||||
else
|
else
|
||||||
self.EscortGroupSet:ForSomeGroupAlive(
|
self.FollowGroupSet:ForSomeGroupAlive(
|
||||||
--- @param Core.Group#GROUP EscortGroup
|
--- @param Core.Group#GROUP EscortGroup
|
||||||
function( FollowGroup )
|
function( FollowGroup )
|
||||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||||
@@ -1045,7 +1047,7 @@ function AI_FORMATION:SetFlightModeFormation( FollowGroup )
|
|||||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||||
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
FollowGroup:SetState( FollowGroup, "Mode", self.__Enum.Mode.Formation )
|
||||||
else
|
else
|
||||||
self.EscortGroupSet:ForSomeGroupAlive(
|
self.FollowGroupSet:ForSomeGroupAlive(
|
||||||
--- @param Core.Group#GROUP EscortGroup
|
--- @param Core.Group#GROUP EscortGroup
|
||||||
function( FollowGroup )
|
function( FollowGroup )
|
||||||
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
FollowGroup:SetState( FollowGroup, "PreviousMode", FollowGroup:GetState( FollowGroup, "Mode" ) )
|
||||||
@@ -1065,7 +1067,7 @@ end
|
|||||||
-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups.
|
-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups.
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @pram #string To The to state.
|
-- @param #string To The to state.
|
||||||
function AI_FORMATION:onafterStop(FollowGroupSet, From, Event, To) --R2.1
|
function AI_FORMATION:onafterStop(FollowGroupSet, From, Event, To) --R2.1
|
||||||
self:E("Stopping formation.")
|
self:E("Stopping formation.")
|
||||||
end
|
end
|
||||||
@@ -1075,7 +1077,7 @@ end
|
|||||||
-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups.
|
-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups.
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @pram #string To The to state.
|
-- @param #string To The to state.
|
||||||
function AI_FORMATION:onbeforeFollow( FollowGroupSet, From, Event, To ) --R2.1
|
function AI_FORMATION:onbeforeFollow( FollowGroupSet, From, Event, To ) --R2.1
|
||||||
if From=="Stopped" then
|
if From=="Stopped" then
|
||||||
return false -- Deny transition.
|
return false -- Deny transition.
|
||||||
@@ -1083,7 +1085,12 @@ function AI_FORMATION:onbeforeFollow( FollowGroupSet, From, Event, To ) --R2.1
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_FORMATION self
|
--- Enter following state.
|
||||||
|
-- @param #AI_FORMATION self
|
||||||
|
-- @param Core.Set#SET_GROUP FollowGroupSet The following set of groups.
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To The to state.
|
||||||
function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
||||||
|
|
||||||
if self.FollowUnit:IsAlive() then
|
if self.FollowUnit:IsAlive() then
|
||||||
@@ -1093,23 +1100,45 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
local CT1, CT2, CV1, CV2
|
local CT1, CT2, CV1, CV2
|
||||||
CT1 = ClientUnit:GetState( self, "CT1" )
|
CT1 = ClientUnit:GetState( self, "CT1" )
|
||||||
|
|
||||||
|
local CuVec3=ClientUnit:GetVec3()
|
||||||
|
|
||||||
if CT1 == nil or CT1 == 0 then
|
if CT1 == nil or CT1 == 0 then
|
||||||
ClientUnit:SetState( self, "CV1", ClientUnit:GetPointVec3() )
|
ClientUnit:SetState( self, "CV1", CuVec3)
|
||||||
ClientUnit:SetState( self, "CT1", timer.getTime() )
|
ClientUnit:SetState( self, "CT1", timer.getTime() )
|
||||||
else
|
else
|
||||||
CT1 = ClientUnit:GetState( self, "CT1" )
|
CT1 = ClientUnit:GetState( self, "CT1" )
|
||||||
CT2 = timer.getTime()
|
CT2 = timer.getTime()
|
||||||
CV1 = ClientUnit:GetState( self, "CV1" )
|
CV1 = ClientUnit:GetState( self, "CV1" )
|
||||||
CV2 = ClientUnit:GetPointVec3()
|
CV2 = CuVec3
|
||||||
|
|
||||||
ClientUnit:SetState( self, "CT1", CT2 )
|
ClientUnit:SetState( self, "CT1", CT2 )
|
||||||
ClientUnit:SetState( self, "CV1", CV2 )
|
ClientUnit:SetState( self, "CV1", CV2 )
|
||||||
end
|
end
|
||||||
|
|
||||||
FollowGroupSet:ForEachGroupAlive(
|
--FollowGroupSet:ForEachGroupAlive( bla, self, ClientUnit, CT1, CV1, CT2, CV2)
|
||||||
--- @param Wrapper.Group#GROUP FollowGroup
|
|
||||||
-- @param Wrapper.Unit#UNIT ClientUnit
|
for _,_group in pairs(FollowGroupSet:GetSet()) do
|
||||||
function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 )
|
local group=_group --Wrapper.Group#GROUP
|
||||||
|
if group and group:IsAlive() then
|
||||||
|
self:FollowMe(group, ClientUnit, CT1, CV1, CT2, CV2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:__Follow( -self.dtFollow )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Follow me.
|
||||||
|
-- @param #AI_FORMATION self
|
||||||
|
-- @param Wrapper.Group#GROUP FollowGroup Follow group.
|
||||||
|
-- @param Wrapper.Unit#UNIT ClientUnit Client Unit.
|
||||||
|
-- @param DCS#Time CT1 Time
|
||||||
|
-- @param DCS#Vec3 CV1 Vec3
|
||||||
|
-- @param DCS#Time CT2 Time
|
||||||
|
-- @param DCS#Vec3 CV2 Vec3
|
||||||
|
function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
|
||||||
|
|
||||||
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then
|
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then
|
||||||
|
|
||||||
@@ -1119,14 +1148,18 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
FollowGroup:OptionROEReturnFire()
|
FollowGroup:OptionROEReturnFire()
|
||||||
|
|
||||||
local GroupUnit = FollowGroup:GetUnit( 1 )
|
local GroupUnit = FollowGroup:GetUnit( 1 )
|
||||||
|
|
||||||
|
local GuVec3=GroupUnit:GetVec3()
|
||||||
|
|
||||||
local FollowFormation = FollowGroup:GetState( self, "FormationVec3" )
|
local FollowFormation = FollowGroup:GetState( self, "FormationVec3" )
|
||||||
|
|
||||||
if FollowFormation then
|
if FollowFormation then
|
||||||
local FollowDistance = FollowFormation.x
|
local FollowDistance = FollowFormation.x
|
||||||
|
|
||||||
local GT1 = GroupUnit:GetState( self, "GT1" )
|
local GT1 = GroupUnit:GetState( self, "GT1" )
|
||||||
|
|
||||||
if CT1 == nil or CT1 == 0 or GT1 == nil or GT1 == 0 then
|
if CT1 == nil or CT1 == 0 or GT1 == nil or GT1 == 0 then
|
||||||
GroupUnit:SetState( self, "GV1", GroupUnit:GetPointVec3() )
|
GroupUnit:SetState( self, "GV1", GuVec3)
|
||||||
GroupUnit:SetState( self, "GT1", timer.getTime() )
|
GroupUnit:SetState( self, "GT1", timer.getTime() )
|
||||||
else
|
else
|
||||||
local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5
|
local CD = ( ( CV2.x - CV1.x )^2 + ( CV2.y - CV1.y )^2 + ( CV2.z - CV1.z )^2 ) ^ 0.5
|
||||||
@@ -1139,11 +1172,21 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
|
|
||||||
local GT1 = GroupUnit:GetState( self, "GT1" )
|
local GT1 = GroupUnit:GetState( self, "GT1" )
|
||||||
local GT2 = timer.getTime()
|
local GT2 = timer.getTime()
|
||||||
|
|
||||||
local GV1 = GroupUnit:GetState( self, "GV1" )
|
local GV1 = GroupUnit:GetState( self, "GV1" )
|
||||||
local GV2 = GroupUnit:GetPointVec3()
|
local GV2 = GuVec3
|
||||||
|
|
||||||
|
--[[
|
||||||
GV2:AddX( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
|
GV2:AddX( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
|
||||||
GV2:AddY( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
|
GV2:AddY( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
|
||||||
GV2:AddZ( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
|
GV2:AddZ( math.random( -Formation.FlightRandomization / 2, Formation.FlightRandomization / 2 ) )
|
||||||
|
]]
|
||||||
|
|
||||||
|
GV2.x=GV2.x+math.random( -self.FlightRandomization / 2, self.FlightRandomization / 2 )
|
||||||
|
GV2.y=GV2.y+math.random( -self.FlightRandomization / 2, self.FlightRandomization / 2 )
|
||||||
|
GV2.z=GV2.z+math.random( -self.FlightRandomization / 2, self.FlightRandomization / 2 )
|
||||||
|
|
||||||
|
|
||||||
GroupUnit:SetState( self, "GT1", GT2 )
|
GroupUnit:SetState( self, "GT1", GT2 )
|
||||||
GroupUnit:SetState( self, "GV1", GV2 )
|
GroupUnit:SetState( self, "GV1", GV2 )
|
||||||
|
|
||||||
@@ -1179,7 +1222,9 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
if Inclination < -30 then
|
if Inclination < -30 then
|
||||||
Inclination = - 30
|
Inclination = - 30
|
||||||
end
|
end
|
||||||
local CVI = { x = CV2.x + CS * 10 * math.sin(Ca),
|
|
||||||
|
local CVI = {
|
||||||
|
x = CV2.x + CS * 10 * math.sin(Ca),
|
||||||
y = GH2.y + Inclination, -- + FollowFormation.y,
|
y = GH2.y + Inclination, -- + FollowFormation.y,
|
||||||
y = GH2.y,
|
y = GH2.y,
|
||||||
z = CV2.z + CS * 10 * math.cos(Ca),
|
z = CV2.z + CS * 10 * math.cos(Ca),
|
||||||
@@ -1205,6 +1250,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
z = GDV.z - GVz
|
z = GDV.z - GVz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Debug smoke.
|
||||||
if self.SmokeDirectionVector == true then
|
if self.SmokeDirectionVector == true then
|
||||||
trigger.action.smoke( GDV, trigger.smokeColor.Green )
|
trigger.action.smoke( GDV, trigger.smokeColor.Green )
|
||||||
trigger.action.smoke( GDV_Formation, trigger.smokeColor.White )
|
trigger.action.smoke( GDV_Formation, trigger.smokeColor.White )
|
||||||
@@ -1226,20 +1272,12 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
|||||||
|
|
||||||
local GS = Speed + CS
|
local GS = Speed + CS
|
||||||
|
|
||||||
self:F( { Distance = Distance, Speed = Speed, CS = CS, GS = GS } )
|
--self:F( { Distance = Distance, Speed = Speed, CS = CS, GS = GS } )
|
||||||
|
|
||||||
|
|
||||||
-- Now route the escort to the desired point with the desired speed.
|
-- Now route the escort to the desired point with the desired speed.
|
||||||
FollowGroup:RouteToVec3( GDV_Formation, GS ) -- DCS models speed in Mps (Miles per second)
|
FollowGroup:RouteToVec3( GDV_Formation, GS ) -- DCS models speed in Mps (Miles per second)
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
self, ClientUnit, CT1, CV1, CT2, CV2
|
|
||||||
)
|
|
||||||
|
|
||||||
self:__Follow( -self.dtFollow )
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ do -- ACT_ROUTE
|
|||||||
self:F( { ZoneName = ZoneName } )
|
self:F( { ZoneName = ZoneName } )
|
||||||
local Zone = Zone -- Core.Zone#ZONE
|
local Zone = Zone -- Core.Zone#ZONE
|
||||||
local ZoneCoord = Zone:GetCoordinate()
|
local ZoneCoord = Zone:GetCoordinate()
|
||||||
local ZoneDistance = ZoneCoord:Get2DDistance( self.Coordinate )
|
local ZoneDistance = ZoneCoord:Get2DDistance( Coordinate )
|
||||||
self:F( { ShortestDistance, ShortestReferenceName } )
|
self:F( { ShortestDistance, ShortestReferenceName } )
|
||||||
if ShortestDistance == 0 or ZoneDistance < ShortestDistance then
|
if ShortestDistance == 0 or ZoneDistance < ShortestDistance then
|
||||||
ShortestDistance = ZoneDistance
|
ShortestDistance = ZoneDistance
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Core** -- Management of CARGO logistics, that can be transported from and to transportation carriers.
|
--- **Cargo** - Management of CARGO logistics, that can be transported from and to transportation carriers.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -1066,18 +1066,26 @@ do -- CARGO_REPRESENTABLE
|
|||||||
|
|
||||||
--- CARGO_REPRESENTABLE Constructor.
|
--- CARGO_REPRESENTABLE Constructor.
|
||||||
-- @param #CARGO_REPRESENTABLE self
|
-- @param #CARGO_REPRESENTABLE self
|
||||||
-- @param #string Type
|
-- @param Wrapper.Positionable#POSITIONABLE CargoObject The cargo object.
|
||||||
-- @param #string Name
|
-- @param #string Type Type name
|
||||||
-- @param #number LoadRadius (optional)
|
-- @param #string Name Name.
|
||||||
-- @param #number NearRadius (optional)
|
-- @param #number LoadRadius (optional) Radius in meters.
|
||||||
|
-- @param #number NearRadius (optional) Radius in meters when the cargo is loaded into the carrier.
|
||||||
-- @return #CARGO_REPRESENTABLE
|
-- @return #CARGO_REPRESENTABLE
|
||||||
function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius )
|
function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius )
|
||||||
|
|
||||||
|
-- Inherit CARGO.
|
||||||
local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
|
local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
|
||||||
self:F( { Type, Name, LoadRadius, NearRadius } )
|
self:F( { Type, Name, LoadRadius, NearRadius } )
|
||||||
|
|
||||||
local Desc = CargoObject:GetDesc()
|
-- Descriptors.
|
||||||
self:I( { Desc = Desc } )
|
local Desc=CargoObject:GetDesc()
|
||||||
|
self:T({Desc=Desc})
|
||||||
|
|
||||||
|
-- Weight.
|
||||||
local Weight = math.random( 80, 120 )
|
local Weight = math.random( 80, 120 )
|
||||||
|
|
||||||
|
-- Adjust weight..
|
||||||
if Desc then
|
if Desc then
|
||||||
if Desc.typeName == "2B11 mortar" then
|
if Desc.typeName == "2B11 mortar" then
|
||||||
Weight = 210
|
Weight = 210
|
||||||
@@ -1086,14 +1094,9 @@ do -- CARGO_REPRESENTABLE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Set weight.
|
||||||
self:SetWeight( Weight )
|
self:SetWeight( Weight )
|
||||||
|
|
||||||
-- local Box = CargoUnit:GetBoundingBox()
|
|
||||||
-- local VolumeUnit = ( Box.max.x - Box.min.x ) * ( Box.max.y - Box.min.y ) * ( Box.max.z - Box.min.z )
|
|
||||||
-- self:I( { VolumeUnit = VolumeUnit, WeightUnit = WeightUnit } )
|
|
||||||
--self:SetVolume( VolumeUnit )
|
|
||||||
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Cargo** -- Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object.
|
--- **Cargo** - Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -56,6 +56,8 @@ do -- CARGO_GROUP
|
|||||||
-- @param #number NearRadius (optional) Once the units are within this radius of the carrier, they are actually loaded, i.e. disappear from the scene.
|
-- @param #number NearRadius (optional) Once the units are within this radius of the carrier, they are actually loaded, i.e. disappear from the scene.
|
||||||
-- @return #CARGO_GROUP Cargo group object.
|
-- @return #CARGO_GROUP Cargo group object.
|
||||||
function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
|
function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
|
||||||
|
|
||||||
|
-- Inherit CAROG_REPORTABLE
|
||||||
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP
|
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP
|
||||||
self:F( { Type, Name, LoadRadius } )
|
self:F( { Type, Name, LoadRadius } )
|
||||||
|
|
||||||
@@ -77,6 +79,9 @@ do -- CARGO_GROUP
|
|||||||
self.CargoName = Name
|
self.CargoName = Name
|
||||||
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
|
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
|
||||||
|
|
||||||
|
-- Deactivate late activation.
|
||||||
|
self.CargoTemplate.lateActivation=false
|
||||||
|
|
||||||
self.GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
self.GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||||
self.GroupTemplate.name = self.CargoName .. "#CARGO"
|
self.GroupTemplate.name = self.CargoName .. "#CARGO"
|
||||||
self.GroupTemplate.groupId = nil
|
self.GroupTemplate.groupId = nil
|
||||||
@@ -481,7 +486,7 @@ do -- CARGO_GROUP
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
|
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
|
||||||
--self:F( { From, Event, To, ToPointVec2 } )
|
--self:F( { From, Event, To, ToPointVec2 } )
|
||||||
|
|
||||||
@@ -491,7 +496,10 @@ do -- CARGO_GROUP
|
|||||||
self.CargoSet:ForEach(
|
self.CargoSet:ForEach(
|
||||||
function( Cargo )
|
function( Cargo )
|
||||||
--Cargo:UnLoad( ToPointVec2 )
|
--Cargo:UnLoad( ToPointVec2 )
|
||||||
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
|
local RandomVec2=nil
|
||||||
|
if ToPointVec2 then
|
||||||
|
RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
|
||||||
|
end
|
||||||
Cargo:UnBoard( RandomVec2 )
|
Cargo:UnBoard( RandomVec2 )
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Cargo** -- Management of single cargo logistics, which are based on a @{Wrapper.Unit} object.
|
--- **Cargo** - Management of single cargo logistics, which are based on a @{Wrapper.Unit} object.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -46,14 +46,17 @@ do -- CARGO_UNIT
|
|||||||
-- @param #number NearRadius (optional)
|
-- @param #number NearRadius (optional)
|
||||||
-- @return #CARGO_UNIT
|
-- @return #CARGO_UNIT
|
||||||
function CARGO_UNIT:New( CargoUnit, Type, Name, LoadRadius, NearRadius )
|
function CARGO_UNIT:New( CargoUnit, Type, Name, LoadRadius, NearRadius )
|
||||||
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) ) -- #CARGO_UNIT
|
|
||||||
self:I( { Type, Name, LoadRadius, NearRadius } )
|
|
||||||
|
|
||||||
self:T( CargoUnit )
|
-- Inherit CARGO_REPRESENTABLE.
|
||||||
|
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) ) -- #CARGO_UNIT
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T({Type=Type, Name=Name, LoadRadius=LoadRadius, NearRadius=NearRadius})
|
||||||
|
|
||||||
|
-- Set cargo object.
|
||||||
self.CargoObject = CargoUnit
|
self.CargoObject = CargoUnit
|
||||||
|
|
||||||
self:T( self.ClassName )
|
-- Set event prio.
|
||||||
|
|
||||||
self:SetEventPriority( 5 )
|
self:SetEventPriority( 5 )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -100,7 +103,12 @@ do -- CARGO_UNIT
|
|||||||
|
|
||||||
-- Respawn the group...
|
-- Respawn the group...
|
||||||
if self.CargoObject then
|
if self.CargoObject then
|
||||||
|
if CargoCarrier:IsShip() then
|
||||||
|
-- If CargoCarrier is a ship, we don't want to spawn the units in the water next to the boat. Use destination coord instead.
|
||||||
|
self.CargoObject:ReSpawnAt( ToPointVec2, CargoDeployHeading )
|
||||||
|
else
|
||||||
self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading )
|
self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading )
|
||||||
|
end
|
||||||
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
|
self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } )
|
||||||
self.CargoCarrier = nil
|
self.CargoCarrier = nil
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,6 @@
|
|||||||
-- @module Core.Base
|
-- @module Core.Base
|
||||||
-- @image Core_Base.JPG
|
-- @image Core_Base.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local _TraceOnOff = true
|
local _TraceOnOff = true
|
||||||
local _TraceLevel = 1
|
local _TraceLevel = 1
|
||||||
local _TraceAll = false
|
local _TraceAll = false
|
||||||
@@ -256,6 +254,8 @@ end
|
|||||||
-- @param #BASE Parent is the Parent class that the Child inherits from.
|
-- @param #BASE Parent is the Parent class that the Child inherits from.
|
||||||
-- @return #BASE Child
|
-- @return #BASE Child
|
||||||
function BASE:Inherit( Child, Parent )
|
function BASE:Inherit( Child, Parent )
|
||||||
|
|
||||||
|
-- Create child.
|
||||||
local Child = routines.utils.deepCopy( Child )
|
local Child = routines.utils.deepCopy( Child )
|
||||||
|
|
||||||
if Child ~= nil then
|
if Child ~= nil then
|
||||||
@@ -271,6 +271,7 @@ function BASE:Inherit( Child, Parent )
|
|||||||
|
|
||||||
--Child:_SetDestructor()
|
--Child:_SetDestructor()
|
||||||
end
|
end
|
||||||
|
|
||||||
return Child
|
return Child
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -433,7 +434,7 @@ do -- Event Handling
|
|||||||
-- reflecting the order of the classes subscribed to the Event to be processed.
|
-- reflecting the order of the classes subscribed to the Event to be processed.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #number EventPriority The @{Event} processing Priority.
|
-- @param #number EventPriority The @{Event} processing Priority.
|
||||||
-- @return self
|
-- @return #BASE self
|
||||||
function BASE:SetEventPriority( EventPriority )
|
function BASE:SetEventPriority( EventPriority )
|
||||||
self._.EventPriority = EventPriority
|
self._.EventPriority = EventPriority
|
||||||
end
|
end
|
||||||
@@ -450,23 +451,23 @@ do -- Event Handling
|
|||||||
|
|
||||||
--- Subscribe to a DCS Event.
|
--- Subscribe to a DCS Event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTS Event
|
-- @param Core.Event#EVENTS EventID Event ID.
|
||||||
-- @param #function EventFunction (optional) The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction (optional) The function to be called when the event occurs for the unit.
|
||||||
-- @return #BASE
|
-- @return #BASE
|
||||||
function BASE:HandleEvent( Event, EventFunction )
|
function BASE:HandleEvent( EventID, EventFunction )
|
||||||
|
|
||||||
self:EventDispatcher():OnEventGeneric( EventFunction, self, Event )
|
self:EventDispatcher():OnEventGeneric( EventFunction, self, EventID )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- UnSubscribe to a DCS event.
|
--- UnSubscribe to a DCS event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTS Event
|
-- @param Core.Event#EVENTS EventID Event ID.
|
||||||
-- @return #BASE
|
-- @return #BASE
|
||||||
function BASE:UnHandleEvent( Event )
|
function BASE:UnHandleEvent( EventID )
|
||||||
|
|
||||||
self:EventDispatcher():RemoveEvent( self, Event )
|
self:EventDispatcher():RemoveEvent( self, EventID )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -675,6 +676,44 @@ do -- Event Handling
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
|
--- Paratrooper landing.
|
||||||
|
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
|
--- Discard chair after ejection.
|
||||||
|
-- @function [parent=#BASE] OnEventDiscardChairAfterEjection
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
|
--- Weapon add. Fires when entering a mission per pylon with the name of the weapon (double pylons not counted, infinite wep reload not counted.
|
||||||
|
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
|
--- Trigger zone.
|
||||||
|
-- @function [parent=#BASE] OnEventTriggerZone
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
|
--- Landing quality mark.
|
||||||
|
-- @function [parent=#BASE] OnEventLandingQualityMark
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
|
--- BDA.
|
||||||
|
-- @function [parent=#BASE] OnEventBDA
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
|
|
||||||
|
--- Occurs when a player enters a slot and takes control of an aircraft.
|
||||||
|
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
|
||||||
|
-- initiator : The unit that is being taken control of.
|
||||||
|
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -764,31 +803,48 @@ function BASE:CreateEventTakeoff( EventTime, Initiator )
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
||||||
|
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
|
||||||
|
self:F( { PlayerUnit } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = EVENTS.PlayerEnterAircraft,
|
||||||
|
time = timer.getTime(),
|
||||||
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent(Event)
|
||||||
|
end
|
||||||
|
|
||||||
-- TODO: Complete DCS#Event structure.
|
-- TODO: Complete DCS#Event structure.
|
||||||
--- The main event handling function... This function captures all events generated for the class.
|
--- The main event handling function... This function captures all events generated for the class.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param DCS#Event event
|
-- @param DCS#Event event
|
||||||
function BASE:onEvent(event)
|
function BASE:onEvent(event)
|
||||||
--self:F( { BaseEventCodes[event.id], event } )
|
|
||||||
|
|
||||||
if self then
|
if self then
|
||||||
for EventID, EventObject in pairs( self.Events ) do
|
|
||||||
|
for EventID, EventObject in pairs(self.Events) do
|
||||||
if EventObject.EventEnabled then
|
if EventObject.EventEnabled then
|
||||||
--env.info( 'onEvent Table EventObject.Self = ' .. tostring(EventObject.Self) )
|
|
||||||
--env.info( 'onEvent event.id = ' .. tostring(event.id) )
|
|
||||||
--env.info( 'onEvent EventObject.Event = ' .. tostring(EventObject.Event) )
|
|
||||||
if event.id == EventObject.Event then
|
if event.id == EventObject.Event then
|
||||||
|
|
||||||
if self == EventObject.Self then
|
if self == EventObject.Self then
|
||||||
|
|
||||||
if event.initiator and event.initiator:isExist() then
|
if event.initiator and event.initiator:isExist() then
|
||||||
event.IniUnitName = event.initiator:getName()
|
event.IniUnitName = event.initiator:getName()
|
||||||
end
|
end
|
||||||
|
|
||||||
if event.target and event.target:isExist() then
|
if event.target and event.target:isExist() then
|
||||||
event.TgtUnitName = event.target:getName()
|
event.TgtUnitName = event.target:getName()
|
||||||
end
|
end
|
||||||
--self:T( { BaseEventCodes[event.id], event } )
|
|
||||||
--EventObject.EventFunction( self, event )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions: **funkyfranky**
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -33,6 +33,9 @@
|
|||||||
|
|
||||||
|
|
||||||
--- @type DATABASE
|
--- @type DATABASE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #table Templates Templates: Units, Groups, Statics, ClientsByName, ClientsByID.
|
||||||
|
-- @field #table CLIENTS Clients.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
|
||||||
@@ -82,6 +85,9 @@ DATABASE = {
|
|||||||
DESTROYS = {},
|
DESTROYS = {},
|
||||||
ZONES = {},
|
ZONES = {},
|
||||||
ZONES_GOAL = {},
|
ZONES_GOAL = {},
|
||||||
|
WAREHOUSES = {},
|
||||||
|
FLIGHTGROUPS = {},
|
||||||
|
FLIGHTCONTROLS = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
local _DATABASECoalition =
|
local _DATABASECoalition =
|
||||||
@@ -123,8 +129,6 @@ function DATABASE:New()
|
|||||||
self:HandleEvent( EVENTS.DeleteCargo )
|
self:HandleEvent( EVENTS.DeleteCargo )
|
||||||
self:HandleEvent( EVENTS.NewZone )
|
self:HandleEvent( EVENTS.NewZone )
|
||||||
self:HandleEvent( EVENTS.DeleteZone )
|
self:HandleEvent( EVENTS.DeleteZone )
|
||||||
|
|
||||||
-- Follow alive players and clients
|
|
||||||
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
|
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
|
||||||
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
|
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
|
||||||
|
|
||||||
@@ -132,42 +136,11 @@ function DATABASE:New()
|
|||||||
self:_RegisterGroupsAndUnits()
|
self:_RegisterGroupsAndUnits()
|
||||||
self:_RegisterClients()
|
self:_RegisterClients()
|
||||||
self:_RegisterStatics()
|
self:_RegisterStatics()
|
||||||
--self:_RegisterPlayers()
|
|
||||||
self:_RegisterAirbases()
|
self:_RegisterAirbases()
|
||||||
|
--self:_RegisterPlayers()
|
||||||
|
|
||||||
self.UNITS_Position = 0
|
self.UNITS_Position = 0
|
||||||
|
|
||||||
--- @param #DATABASE self
|
|
||||||
local function CheckPlayers( self )
|
|
||||||
|
|
||||||
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ), AlivePlayersNeutral = coalition.getPlayers( coalition.side.NEUTRAL )}
|
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
|
||||||
--self:E( { "CoalitionData:", CoalitionData } )
|
|
||||||
for UnitId, UnitData in pairs( CoalitionData ) do
|
|
||||||
if UnitData and UnitData:isExist() then
|
|
||||||
|
|
||||||
local UnitName = UnitData:getName()
|
|
||||||
local PlayerName = UnitData:getPlayerName()
|
|
||||||
local PlayerUnit = UNIT:Find( UnitData )
|
|
||||||
--self:T( { "UnitData:", UnitData, UnitName, PlayerName, PlayerUnit } )
|
|
||||||
|
|
||||||
if PlayerName and PlayerName ~= "" then
|
|
||||||
if self.PLAYERS[PlayerName] == nil or self.PLAYERS[PlayerName] ~= UnitName then
|
|
||||||
--self:E( { "Add player for unit:", UnitName, PlayerName } )
|
|
||||||
self:AddPlayer( UnitName, PlayerName )
|
|
||||||
--_EVENTDISPATCHER:CreateEventPlayerEnterUnit( PlayerUnit )
|
|
||||||
local Settings = SETTINGS:Set( PlayerName )
|
|
||||||
Settings:SetPlayerMenu( PlayerUnit )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--self:E( "Scheduling" )
|
|
||||||
--PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -184,14 +157,22 @@ end
|
|||||||
|
|
||||||
--- Adds a Unit based on the Unit Name in the DATABASE.
|
--- Adds a Unit based on the Unit Name in the DATABASE.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
|
-- @param #string DCSUnitName Unit name.
|
||||||
|
-- @return Wrapper.Unit#UNIT The added unit.
|
||||||
function DATABASE:AddUnit( DCSUnitName )
|
function DATABASE:AddUnit( DCSUnitName )
|
||||||
|
|
||||||
if not self.UNITS[DCSUnitName] then
|
if not self.UNITS[DCSUnitName] then
|
||||||
self:T( { "Add UNIT:", DCSUnitName } )
|
|
||||||
local UnitRegister = UNIT:Register( DCSUnitName )
|
|
||||||
self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
|
|
||||||
|
|
||||||
table.insert( self.UNITS_Index, DCSUnitName )
|
-- Debug info.
|
||||||
|
self:T( { "Add UNIT:", DCSUnitName } )
|
||||||
|
|
||||||
|
--local UnitRegister = UNIT:Register( DCSUnitName )
|
||||||
|
|
||||||
|
-- Register unit
|
||||||
|
self.UNITS[DCSUnitName]=UNIT:Register(DCSUnitName)
|
||||||
|
|
||||||
|
-- This is not used anywhere in MOOSE as far as I can see so I remove it until there comes an error somewhere.
|
||||||
|
--table.insert(self.UNITS_Index, DCSUnitName )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self.UNITS[DCSUnitName]
|
return self.UNITS[DCSUnitName]
|
||||||
@@ -207,6 +188,8 @@ end
|
|||||||
|
|
||||||
--- Adds a Static based on the Static Name in the DATABASE.
|
--- Adds a Static based on the Static Name in the DATABASE.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
|
-- @param #string DCSStaticName Name of the static.
|
||||||
|
-- @return Wrapper.Static#STATIC The static object.
|
||||||
function DATABASE:AddStatic( DCSStaticName )
|
function DATABASE:AddStatic( DCSStaticName )
|
||||||
|
|
||||||
if not self.STATICS[DCSStaticName] then
|
if not self.STATICS[DCSStaticName] then
|
||||||
@@ -221,8 +204,7 @@ end
|
|||||||
--- Deletes a Static from the DATABASE based on the Static Name.
|
--- Deletes a Static from the DATABASE based on the Static Name.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
function DATABASE:DeleteStatic( DCSStaticName )
|
function DATABASE:DeleteStatic( DCSStaticName )
|
||||||
|
self.STATICS[DCSStaticName] = nil
|
||||||
--self.STATICS[DCSStaticName] = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Finds a STATIC based on the StaticName.
|
--- Finds a STATIC based on the StaticName.
|
||||||
@@ -429,7 +411,6 @@ do -- cargo
|
|||||||
local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug!
|
local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug!
|
||||||
|
|
||||||
for CargoGroupName, CargoGroup in pairs( Groups ) do
|
for CargoGroupName, CargoGroup in pairs( Groups ) do
|
||||||
self:I( { Cargo = CargoGroupName } )
|
|
||||||
if self:IsCargo( CargoGroupName ) then
|
if self:IsCargo( CargoGroupName ) then
|
||||||
local CargoInfo = CargoGroupName:match("#CARGO(.*)")
|
local CargoInfo = CargoGroupName:match("#CARGO(.*)")
|
||||||
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
|
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
|
||||||
@@ -486,6 +467,8 @@ end
|
|||||||
|
|
||||||
--- Adds a CLIENT based on the ClientName in the DATABASE.
|
--- Adds a CLIENT based on the ClientName in the DATABASE.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ClientName Name of the Client unit.
|
||||||
|
-- @return Wrapper.Client#CLIENT The client object.
|
||||||
function DATABASE:AddClient( ClientName )
|
function DATABASE:AddClient( ClientName )
|
||||||
|
|
||||||
if not self.CLIENTS[ClientName] then
|
if not self.CLIENTS[ClientName] then
|
||||||
@@ -623,6 +606,9 @@ function DATABASE:Spawn( SpawnTemplate )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Set a status to a Group within the Database, this to check crossing events for example.
|
--- Set a status to a Group within the Database, this to check crossing events for example.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string GroupName Group name.
|
||||||
|
-- @param #string Status Status.
|
||||||
function DATABASE:SetStatusGroup( GroupName, Status )
|
function DATABASE:SetStatusGroup( GroupName, Status )
|
||||||
self:F2( Status )
|
self:F2( Status )
|
||||||
|
|
||||||
@@ -630,8 +616,11 @@ function DATABASE:SetStatusGroup( GroupName, Status )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Get a status to a Group within the Database, this to check crossing events for example.
|
--- Get a status to a Group within the Database, this to check crossing events for example.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string GroupName Group name.
|
||||||
|
-- @return #string Status or an empty string "".
|
||||||
function DATABASE:GetStatusGroup( GroupName )
|
function DATABASE:GetStatusGroup( GroupName )
|
||||||
self:F2( Status )
|
self:F2( GroupName )
|
||||||
|
|
||||||
if self.Templates.Groups[GroupName] then
|
if self.Templates.Groups[GroupName] then
|
||||||
return self.Templates.Groups[GroupName].Status
|
return self.Templates.Groups[GroupName].Status
|
||||||
@@ -645,7 +634,8 @@ end
|
|||||||
-- @param #table GroupTemplate
|
-- @param #table GroupTemplate
|
||||||
-- @param DCS#coalition.side CoalitionSide The coalition.side of the object.
|
-- @param DCS#coalition.side CoalitionSide The coalition.side of the object.
|
||||||
-- @param DCS#Object.Category CategoryID The Object.category of the object.
|
-- @param DCS#Object.Category CategoryID The Object.category of the object.
|
||||||
-- @param DCS#country.id CountryID the country.id of the object
|
-- @param DCS#country.id CountryID the country ID of the object.
|
||||||
|
-- @param #string GroupName (Optional) The name of the group. Default is `GroupTemplate.name`.
|
||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
|
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
|
||||||
|
|
||||||
@@ -701,6 +691,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
self:T( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
|
||||||
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
|
Coalition = self.Templates.Groups[GroupTemplateName].CoalitionID,
|
||||||
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
|
Category = self.Templates.Groups[GroupTemplateName].CategoryID,
|
||||||
@@ -710,6 +701,10 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get group template.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string GroupName Group name.
|
||||||
|
-- @return #table Group template table.
|
||||||
function DATABASE:GetGroupTemplate( GroupName )
|
function DATABASE:GetGroupTemplate( GroupName )
|
||||||
local GroupTemplate = self.Templates.Groups[GroupName].Template
|
local GroupTemplate = self.Templates.Groups[GroupName].Template
|
||||||
GroupTemplate.SpawnCoalitionID = self.Templates.Groups[GroupName].CoalitionID
|
GroupTemplate.SpawnCoalitionID = self.Templates.Groups[GroupName].CoalitionID
|
||||||
@@ -720,7 +715,10 @@ end
|
|||||||
|
|
||||||
--- Private method that registers new Static Templates within the DATABASE Object.
|
--- Private method that registers new Static Templates within the DATABASE Object.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param #table StaticTemplate
|
-- @param #table StaticTemplate Template table.
|
||||||
|
-- @param #number CoalitionID Coalition ID.
|
||||||
|
-- @param #number CategoryID Category ID.
|
||||||
|
-- @param #number CountryID Country ID.
|
||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
|
function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
|
||||||
|
|
||||||
@@ -741,7 +739,8 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
|||||||
self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID
|
self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID
|
||||||
self.Templates.Statics[StaticTemplateName].CountryID = CountryID
|
self.Templates.Statics[StaticTemplateName].CountryID = CountryID
|
||||||
|
|
||||||
self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName,
|
-- Debug info.
|
||||||
|
self:T( { Static = self.Templates.Statics[StaticTemplateName].StaticName,
|
||||||
Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID,
|
Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID,
|
||||||
Category = self.Templates.Statics[StaticTemplateName].CategoryID,
|
Category = self.Templates.Statics[StaticTemplateName].CategoryID,
|
||||||
Country = self.Templates.Statics[StaticTemplateName].CountryID
|
Country = self.Templates.Statics[StaticTemplateName].CountryID
|
||||||
@@ -750,48 +749,101 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
|||||||
|
|
||||||
self:AddStatic( StaticTemplateName )
|
self:AddStatic( StaticTemplateName )
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get static group template.
|
||||||
--- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
|
-- @param #string StaticName Name of the static.
|
||||||
|
-- @return #table Static template table.
|
||||||
function DATABASE:GetStaticGroupTemplate( StaticName )
|
function DATABASE:GetStaticGroupTemplate( StaticName )
|
||||||
|
if self.Templates.Statics[StaticName] then
|
||||||
local StaticTemplate = self.Templates.Statics[StaticName].GroupTemplate
|
local StaticTemplate = self.Templates.Statics[StaticName].GroupTemplate
|
||||||
return StaticTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
|
return StaticTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
|
||||||
|
else
|
||||||
|
self:E("ERROR: Static group template does NOT exist for static "..tostring(StaticName))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #DATABASE self
|
--- Get static unit template.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string StaticName Name of the static.
|
||||||
|
-- @return #table Static template table.
|
||||||
function DATABASE:GetStaticUnitTemplate( StaticName )
|
function DATABASE:GetStaticUnitTemplate( StaticName )
|
||||||
|
if self.Templates.Statics[StaticName] then
|
||||||
local UnitTemplate = self.Templates.Statics[StaticName].UnitTemplate
|
local UnitTemplate = self.Templates.Statics[StaticName].UnitTemplate
|
||||||
return UnitTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
|
return UnitTemplate, self.Templates.Statics[StaticName].CoalitionID, self.Templates.Statics[StaticName].CategoryID, self.Templates.Statics[StaticName].CountryID
|
||||||
|
else
|
||||||
|
self:E("ERROR: Static unit template does NOT exist for static "..tostring(StaticName))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get group name from unit name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string UnitName Name of the unit.
|
||||||
|
-- @return #string Group name.
|
||||||
function DATABASE:GetGroupNameFromUnitName( UnitName )
|
function DATABASE:GetGroupNameFromUnitName( UnitName )
|
||||||
|
if self.Templates.Units[UnitName] then
|
||||||
return self.Templates.Units[UnitName].GroupName
|
return self.Templates.Units[UnitName].GroupName
|
||||||
|
else
|
||||||
|
self:E("ERROR: Unit template does not exist for unit "..tostring(UnitName))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get group template from unit name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string UnitName Name of the unit.
|
||||||
|
-- @return #table Group template.
|
||||||
function DATABASE:GetGroupTemplateFromUnitName( UnitName )
|
function DATABASE:GetGroupTemplateFromUnitName( UnitName )
|
||||||
|
if self.Templates.Units[UnitName] then
|
||||||
return self.Templates.Units[UnitName].GroupTemplate
|
return self.Templates.Units[UnitName].GroupTemplate
|
||||||
|
else
|
||||||
|
self:E("ERROR: Unit template does not exist for unit "..tostring(UnitName))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get coalition ID from client name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ClientName Name of the Client.
|
||||||
|
-- @return #number Coalition ID.
|
||||||
function DATABASE:GetCoalitionFromClientTemplate( ClientName )
|
function DATABASE:GetCoalitionFromClientTemplate( ClientName )
|
||||||
return self.Templates.ClientsByName[ClientName].CoalitionID
|
return self.Templates.ClientsByName[ClientName].CoalitionID
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get category ID from client name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ClientName Name of the Client.
|
||||||
|
-- @return #number Category ID.
|
||||||
function DATABASE:GetCategoryFromClientTemplate( ClientName )
|
function DATABASE:GetCategoryFromClientTemplate( ClientName )
|
||||||
return self.Templates.ClientsByName[ClientName].CategoryID
|
return self.Templates.ClientsByName[ClientName].CategoryID
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get country ID from client name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string ClientName Name of the Client.
|
||||||
|
-- @return #number Country ID.
|
||||||
function DATABASE:GetCountryFromClientTemplate( ClientName )
|
function DATABASE:GetCountryFromClientTemplate( ClientName )
|
||||||
return self.Templates.ClientsByName[ClientName].CountryID
|
return self.Templates.ClientsByName[ClientName].CountryID
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Airbase
|
--- Airbase
|
||||||
|
|
||||||
|
--- Get coalition ID from airbase name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string AirbaseName Name of the airbase.
|
||||||
|
-- @return #number Coalition ID.
|
||||||
function DATABASE:GetCoalitionFromAirbase( AirbaseName )
|
function DATABASE:GetCoalitionFromAirbase( AirbaseName )
|
||||||
return self.AIRBASES[AirbaseName]:GetCoalition()
|
return self.AIRBASES[AirbaseName]:GetCoalition()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get category from airbase name.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string AirbaseName Name of the airbase.
|
||||||
|
-- @return #number Category.
|
||||||
function DATABASE:GetCategoryFromAirbase( AirbaseName )
|
function DATABASE:GetCategoryFromAirbase( AirbaseName )
|
||||||
return self.AIRBASES[AirbaseName]:GetCategory()
|
return self.AIRBASES[AirbaseName]:GetCategory()
|
||||||
end
|
end
|
||||||
@@ -828,33 +880,38 @@ end
|
|||||||
function DATABASE:_RegisterGroupsAndUnits()
|
function DATABASE:_RegisterGroupsAndUnits()
|
||||||
|
|
||||||
local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ), GroupsNeutral = coalition.getGroups( coalition.side.NEUTRAL ) }
|
local CoalitionsData = { GroupsRed = coalition.getGroups( coalition.side.RED ), GroupsBlue = coalition.getGroups( coalition.side.BLUE ), GroupsNeutral = coalition.getGroups( coalition.side.NEUTRAL ) }
|
||||||
|
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||||
|
|
||||||
for DCSGroupId, DCSGroup in pairs( CoalitionData ) do
|
for DCSGroupId, DCSGroup in pairs( CoalitionData ) do
|
||||||
|
|
||||||
if DCSGroup:isExist() then
|
if DCSGroup:isExist() then
|
||||||
|
|
||||||
|
-- Group name.
|
||||||
local DCSGroupName = DCSGroup:getName()
|
local DCSGroupName = DCSGroup:getName()
|
||||||
|
|
||||||
self:I( { "Register Group:", DCSGroupName } )
|
-- Add group.
|
||||||
|
self:I(string.format("Register Group: %s", tostring(DCSGroupName)))
|
||||||
self:AddGroup( DCSGroupName )
|
self:AddGroup( DCSGroupName )
|
||||||
|
|
||||||
|
-- Loop over units in group.
|
||||||
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
|
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
|
||||||
|
|
||||||
|
-- Get unit name.
|
||||||
local DCSUnitName = DCSUnit:getName()
|
local DCSUnitName = DCSUnit:getName()
|
||||||
self:I( { "Register Unit:", DCSUnitName } )
|
|
||||||
|
-- Add unit.
|
||||||
|
self:I(string.format("Register Unit: %s", tostring(DCSUnitName)))
|
||||||
self:AddUnit( DCSUnitName )
|
self:AddUnit( DCSUnitName )
|
||||||
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E( { "Group does not exist: ", DCSGroup } )
|
self:E({"Group does not exist: ", DCSGroup})
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T("Groups:")
|
|
||||||
for GroupName, Group in pairs( self.GROUPS ) do
|
|
||||||
self:T( { "Group:", GroupName } )
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -864,7 +921,7 @@ end
|
|||||||
function DATABASE:_RegisterClients()
|
function DATABASE:_RegisterClients()
|
||||||
|
|
||||||
for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do
|
for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do
|
||||||
self:T( { "Register Client:", ClientName } )
|
self:I(string.format("Register Client: %s", tostring(ClientName)))
|
||||||
self:AddClient( ClientName )
|
self:AddClient( ClientName )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -874,15 +931,15 @@ end
|
|||||||
--- @param #DATABASE self
|
--- @param #DATABASE self
|
||||||
function DATABASE:_RegisterStatics()
|
function DATABASE:_RegisterStatics()
|
||||||
|
|
||||||
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) }
|
local CoalitionsData={GroupsRed=coalition.getStaticObjects(coalition.side.RED), GroupsBlue=coalition.getStaticObjects(coalition.side.BLUE), GroupsNeutral=coalition.getStaticObjects(coalition.side.NEUTRAL)}
|
||||||
self:I( { Statics = CoalitionsData } )
|
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||||
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
|
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
|
||||||
|
|
||||||
if DCSStatic:isExist() then
|
if DCSStatic:isExist() then
|
||||||
local DCSStaticName = DCSStatic:getName()
|
local DCSStaticName = DCSStatic:getName()
|
||||||
|
|
||||||
self:T( { "Register Static:", DCSStaticName } )
|
self:I(string.format("Register Static: %s", tostring(DCSStaticName)))
|
||||||
self:AddStatic( DCSStaticName )
|
self:AddStatic( DCSStaticName )
|
||||||
else
|
else
|
||||||
self:E( { "Static does not exist: ", DCSStatic } )
|
self:E( { "Static does not exist: ", DCSStatic } )
|
||||||
@@ -893,31 +950,40 @@ function DATABASE:_RegisterStatics()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #DATABASE self
|
--- Register all world airbases.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterAirbases()
|
function DATABASE:_RegisterAirbases()
|
||||||
|
|
||||||
--[[
|
|
||||||
local CoalitionsData = { AirbasesRed = coalition.getAirbases( coalition.side.RED ), AirbasesBlue = coalition.getAirbases( coalition.side.BLUE ), AirbasesNeutral = coalition.getAirbases( coalition.side.NEUTRAL ) }
|
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
|
||||||
for DCSAirbaseId, DCSAirbase in pairs( CoalitionData ) do
|
|
||||||
|
|
||||||
local DCSAirbaseName = DCSAirbase:getName()
|
|
||||||
|
|
||||||
self:T( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
|
|
||||||
self:AddAirbase( DCSAirbaseName )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
]]
|
|
||||||
|
|
||||||
for DCSAirbaseId, DCSAirbase in pairs(world.getAirbases()) do
|
for DCSAirbaseId, DCSAirbase in pairs(world.getAirbases()) do
|
||||||
|
|
||||||
|
-- Get the airbase name.
|
||||||
local DCSAirbaseName = DCSAirbase:getName()
|
local DCSAirbaseName = DCSAirbase:getName()
|
||||||
|
|
||||||
-- This gives the incorrect value to be inserted into the airdromeID for DCS 2.5.6!
|
-- This gave the incorrect value to be inserted into the airdromeID for DCS 2.5.6. Is fixed now.
|
||||||
local airbaseID=DCSAirbase:getID()
|
local airbaseID=DCSAirbase:getID()
|
||||||
|
|
||||||
|
-- Add and register airbase.
|
||||||
local airbase=self:AddAirbase( DCSAirbaseName )
|
local airbase=self:AddAirbase( DCSAirbaseName )
|
||||||
|
|
||||||
self:I(string.format("Register Airbase: %s, getID=%d, GetID=%d (unique=%d)", DCSAirbaseName, DCSAirbase:getID(), airbase:GetID(), airbase:GetID(true)))
|
-- Unique ID.
|
||||||
|
local airbaseUID=airbase:GetID(true)
|
||||||
|
|
||||||
|
-- Debug output.
|
||||||
|
local text=string.format("Register %s: %s (ID=%d UID=%d), parking=%d [", AIRBASE.CategoryName[airbase.category], tostring(DCSAirbaseName), airbaseID, airbaseUID, airbase.NparkingTotal)
|
||||||
|
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
||||||
|
if airbase.NparkingTerminal and airbase.NparkingTerminal[terminalType] then
|
||||||
|
text=text..string.format("%d=%d ", terminalType, airbase.NparkingTerminal[terminalType])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
text=text.."]"
|
||||||
|
self:I(text)
|
||||||
|
|
||||||
|
-- Check for DCS bug IDs.
|
||||||
|
if airbaseID~=airbase:GetID() then
|
||||||
|
--self:E("WARNING: :getID does NOT match :GetID!")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -933,36 +999,74 @@ function DATABASE:_EventOnBirth( Event )
|
|||||||
self:F( { Event } )
|
self:F( { Event } )
|
||||||
|
|
||||||
if Event.IniDCSUnit then
|
if Event.IniDCSUnit then
|
||||||
|
|
||||||
if Event.IniObjectCategory == 3 then
|
if Event.IniObjectCategory == 3 then
|
||||||
|
|
||||||
self:AddStatic( Event.IniDCSUnitName )
|
self:AddStatic( Event.IniDCSUnitName )
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
|
|
||||||
self:AddUnit( Event.IniDCSUnitName )
|
self:AddUnit( Event.IniDCSUnitName )
|
||||||
self:AddGroup( Event.IniDCSGroupName )
|
self:AddGroup( Event.IniDCSGroupName )
|
||||||
|
|
||||||
-- Add airbase if it was spawned later in the mission.
|
-- Add airbase if it was spawned later in the mission.
|
||||||
local DCSAirbase = Airbase.getByName(Event.IniDCSUnitName)
|
local DCSAirbase = Airbase.getByName(Event.IniDCSUnitName)
|
||||||
if DCSAirbase then
|
if DCSAirbase then
|
||||||
self:I(string.format("Adding airbase %s", tostring(Event.IniDCSUnitName)))
|
self:I(string.format("Adding airbase %s", tostring(Event.IniDCSUnitName)))
|
||||||
self:AddAirbase(Event.IniDCSUnitName)
|
self:AddAirbase(Event.IniDCSUnitName)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
|
|
||||||
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
|
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
|
||||||
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
|
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
|
||||||
|
|
||||||
|
-- Client
|
||||||
|
local client=self.CLIENTS[Event.IniDCSUnitName] --Wrapper.Client#CLIENT
|
||||||
|
|
||||||
|
if client then
|
||||||
|
-- TODO: create event ClientAlive
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get player name.
|
||||||
local PlayerName = Event.IniUnit:GetPlayerName()
|
local PlayerName = Event.IniUnit:GetPlayerName()
|
||||||
|
|
||||||
if PlayerName then
|
if PlayerName then
|
||||||
self:I( { "Player Joined:", PlayerName } )
|
|
||||||
self:AddClient( Event.IniDCSUnitName )
|
-- Debug info.
|
||||||
|
self:I(string.format("Player '%s' joint unit '%s' of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName)))
|
||||||
|
|
||||||
|
-- Add client in case it does not exist already.
|
||||||
|
if not client then
|
||||||
|
client=self:AddClient(Event.IniDCSUnitName)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add player.
|
||||||
|
client:AddPlayer(PlayerName)
|
||||||
|
|
||||||
|
-- Add player.
|
||||||
if not self.PLAYERS[PlayerName] then
|
if not self.PLAYERS[PlayerName] then
|
||||||
self:AddPlayer( Event.IniUnitName, PlayerName )
|
self:AddPlayer( Event.IniUnitName, PlayerName )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Player settings.
|
||||||
local Settings = SETTINGS:Set( PlayerName )
|
local Settings = SETTINGS:Set( PlayerName )
|
||||||
Settings:SetPlayerMenu( Event.IniUnit )
|
Settings:SetPlayerMenu(Event.IniUnit)
|
||||||
--MENU_INDEX:Refresh( Event.IniGroup )
|
|
||||||
|
-- Create an event.
|
||||||
|
self:CreateEventPlayerEnterAircraft(Event.IniUnit)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -970,22 +1074,53 @@ end
|
|||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
function DATABASE:_EventOnDeadOrCrash( Event )
|
function DATABASE:_EventOnDeadOrCrash( Event )
|
||||||
self:F2( { Event } )
|
|
||||||
|
|
||||||
if Event.IniDCSUnit then
|
if Event.IniDCSUnit then
|
||||||
|
|
||||||
|
local name=Event.IniDCSUnitName
|
||||||
|
|
||||||
if Event.IniObjectCategory == 3 then
|
if Event.IniObjectCategory == 3 then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- STATICS
|
||||||
|
---
|
||||||
|
|
||||||
if self.STATICS[Event.IniDCSUnitName] then
|
if self.STATICS[Event.IniDCSUnitName] then
|
||||||
self:DeleteStatic( Event.IniDCSUnitName )
|
self:DeleteStatic( Event.IniDCSUnitName )
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- UNITS
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Delete unit.
|
||||||
if self.UNITS[Event.IniDCSUnitName] then
|
if self.UNITS[Event.IniDCSUnitName] then
|
||||||
self:DeleteUnit( Event.IniDCSUnitName )
|
self:DeleteUnit(Event.IniDCSUnitName)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Remove client players.
|
||||||
|
local client=self.CLIENTS[name] --Wrapper.Client#CLIENT
|
||||||
|
|
||||||
|
if client then
|
||||||
|
client:RemovePlayers()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Add airbase if it was spawned later in the mission.
|
||||||
|
local airbase=self.AIRBASES[Event.IniDCSUnitName] --Wrapper.Airbase#AIRBASE
|
||||||
|
if airbase and (airbase:IsHelipad() or airbase:IsShip()) then
|
||||||
|
self:DeleteAirbase(Event.IniDCSUnitName)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Account destroys.
|
||||||
self:AccountDestroys( Event )
|
self:AccountDestroys( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -998,15 +1133,31 @@ function DATABASE:_EventOnPlayerEnterUnit( Event )
|
|||||||
|
|
||||||
if Event.IniDCSUnit then
|
if Event.IniDCSUnit then
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
|
|
||||||
|
-- Add unit.
|
||||||
self:AddUnit( Event.IniDCSUnitName )
|
self:AddUnit( Event.IniDCSUnitName )
|
||||||
|
|
||||||
|
-- Ini unit.
|
||||||
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
|
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
|
||||||
|
|
||||||
|
-- Add group.
|
||||||
self:AddGroup( Event.IniDCSGroupName )
|
self:AddGroup( Event.IniDCSGroupName )
|
||||||
|
|
||||||
|
-- Get player unit.
|
||||||
local PlayerName = Event.IniDCSUnit:getPlayerName()
|
local PlayerName = Event.IniDCSUnit:getPlayerName()
|
||||||
|
|
||||||
|
if PlayerName then
|
||||||
|
|
||||||
if not self.PLAYERS[PlayerName] then
|
if not self.PLAYERS[PlayerName] then
|
||||||
self:AddPlayer( Event.IniDCSUnitName, PlayerName )
|
self:AddPlayer( Event.IniDCSUnitName, PlayerName )
|
||||||
end
|
end
|
||||||
|
|
||||||
local Settings = SETTINGS:Set( PlayerName )
|
local Settings = SETTINGS:Set( PlayerName )
|
||||||
Settings:SetPlayerMenu( Event.IniUnit )
|
Settings:SetPlayerMenu( Event.IniUnit )
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E("ERROR: getPlayerName() returned nil for event PlayerEnterUnit")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1019,13 +1170,30 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event )
|
|||||||
self:F2( { Event } )
|
self:F2( { Event } )
|
||||||
|
|
||||||
if Event.IniUnit then
|
if Event.IniUnit then
|
||||||
|
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory == 1 then
|
||||||
|
|
||||||
|
-- Try to get the player name. This can be buggy for multicrew aircraft!
|
||||||
local PlayerName = Event.IniUnit:GetPlayerName()
|
local PlayerName = Event.IniUnit:GetPlayerName()
|
||||||
if PlayerName and self.PLAYERS[PlayerName] then
|
|
||||||
self:I( { "Player Left:", PlayerName } )
|
if PlayerName then --and self.PLAYERS[PlayerName] then
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:I(string.format("Player '%s' left unit %s", tostring(PlayerName), tostring(Event.IniUnitName)))
|
||||||
|
|
||||||
|
-- Remove player menu.
|
||||||
local Settings = SETTINGS:Set( PlayerName )
|
local Settings = SETTINGS:Set( PlayerName )
|
||||||
Settings:RemovePlayerMenu( Event.IniUnit )
|
Settings:RemovePlayerMenu(Event.IniUnit)
|
||||||
self:DeletePlayer( Event.IniUnit, PlayerName )
|
|
||||||
|
-- Delete player.
|
||||||
|
self:DeletePlayer(Event.IniUnit, PlayerName)
|
||||||
|
|
||||||
|
-- Client stuff.
|
||||||
|
local client=self.CLIENTS[Event.IniDCSUnitName] --Wrapper.Client#CLIENT
|
||||||
|
if client then
|
||||||
|
client:RemovePlayer(PlayerName)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1252,8 +1420,44 @@ function DATABASE:SetPlayerSettings( PlayerName, Settings )
|
|||||||
self.PLAYERSETTINGS[PlayerName] = Settings
|
self.PLAYERSETTINGS[PlayerName] = Settings
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add a flight group to the data base.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param Ops.FlightGroup#FLIGHTGROUP flightgroup
|
||||||
|
function DATABASE:AddFlightGroup(flightgroup)
|
||||||
|
self:I({NewFlightGroup=flightgroup.groupname})
|
||||||
|
self.FLIGHTGROUPS[flightgroup.groupname]=flightgroup
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a flight group from the data base.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string groupname Group name of the flight group. Can also be passed as GROUP object.
|
||||||
|
-- @return Ops.FlightGroup#FLIGHTGROUP Flight group object.
|
||||||
|
function DATABASE:GetFlightGroup(groupname)
|
||||||
|
|
||||||
|
-- Get group and group name.
|
||||||
|
if type(groupname)=="string" then
|
||||||
|
else
|
||||||
|
groupname=groupname:GetName()
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.FLIGHTGROUPS[groupname]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a flight control to the data base.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param Ops.FlightControl#FLIGHTCONTROL flightcontrol
|
||||||
|
function DATABASE:AddFlightControl(flightcontrol)
|
||||||
|
self:F2( { flightcontrol } )
|
||||||
|
self.FLIGHTCONTROLS[flightcontrol.airbasename]=flightcontrol
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a flight control object from the data base.
|
||||||
|
-- @param #DATABASE self
|
||||||
|
-- @param #string airbasename Name of the associated airbase.
|
||||||
|
-- @return Ops.FlightControl#FLIGHTCONTROL The FLIGHTCONTROL object.s
|
||||||
|
function DATABASE:GetFlightControl(airbasename)
|
||||||
|
return self.FLIGHTCONTROLS[airbasename]
|
||||||
|
end
|
||||||
|
|
||||||
--- @param #DATABASE self
|
--- @param #DATABASE self
|
||||||
function DATABASE:_RegisterTemplates()
|
function DATABASE:_RegisterTemplates()
|
||||||
@@ -1322,19 +1526,13 @@ function DATABASE:_RegisterTemplates()
|
|||||||
for group_num, Template in pairs(obj_type_data.group) do
|
for group_num, Template in pairs(obj_type_data.group) do
|
||||||
|
|
||||||
if obj_type_name ~= "static" and Template and Template.units and type(Template.units) == 'table' then --making sure again- this is a valid group
|
if obj_type_name ~= "static" and Template and Template.units and type(Template.units) == 'table' then --making sure again- this is a valid group
|
||||||
self:_RegisterGroupTemplate(
|
|
||||||
Template,
|
self:_RegisterGroupTemplate(Template, CoalitionSide, _DATABASECategory[string.lower(CategoryName)], CountryID)
|
||||||
CoalitionSide,
|
|
||||||
_DATABASECategory[string.lower(CategoryName)],
|
|
||||||
CountryID
|
|
||||||
)
|
|
||||||
else
|
else
|
||||||
self:_RegisterStaticTemplate(
|
|
||||||
Template,
|
self:_RegisterStaticTemplate(Template, CoalitionSide, _DATABASECategory[string.lower(CategoryName)], CountryID)
|
||||||
CoalitionSide,
|
|
||||||
_DATABASECategory[string.lower(CategoryName)],
|
|
||||||
CountryID
|
|
||||||
)
|
|
||||||
end --if GroupTemplate and GroupTemplate.units then
|
end --if GroupTemplate and GroupTemplate.units then
|
||||||
end --for group_num, GroupTemplate in pairs(obj_type_data.group) do
|
end --for group_num, GroupTemplate in pairs(obj_type_data.group) do
|
||||||
end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then
|
end --if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then
|
||||||
@@ -1436,8 +1634,3 @@ end
|
|||||||
self.DESTROYS[Event.IniUnitName] = true
|
self.DESTROYS[Event.IniUnitName] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003
|
|||||||
world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
|
world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
|
||||||
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
||||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
||||||
|
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
|
||||||
|
|
||||||
|
|
||||||
--- The different types of events supported by MOOSE.
|
--- The different types of events supported by MOOSE.
|
||||||
@@ -233,19 +234,27 @@ EVENTS = {
|
|||||||
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
||||||
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
||||||
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
||||||
|
PlayerEnterAircraft = world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT,
|
||||||
-- Added with DCS 2.5.6
|
-- Added with DCS 2.5.6
|
||||||
DetailedFailure = world.event.S_EVENT_DETAILED_FAILURE or -1, --We set this to -1 for backward compatibility to DCS 2.5.5 and earlier
|
DetailedFailure = world.event.S_EVENT_DETAILED_FAILURE or -1, --We set this to -1 for backward compatibility to DCS 2.5.5 and earlier
|
||||||
Kill = world.event.S_EVENT_KILL or -1,
|
Kill = world.event.S_EVENT_KILL or -1,
|
||||||
Score = world.event.S_EVENT_SCORE or -1,
|
Score = world.event.S_EVENT_SCORE or -1,
|
||||||
UnitLost = world.event.S_EVENT_UNIT_LOST or -1,
|
UnitLost = world.event.S_EVENT_UNIT_LOST or -1,
|
||||||
LandingAfterEjection = world.event.S_EVENT_LANDING_AFTER_EJECTION or -1,
|
LandingAfterEjection = world.event.S_EVENT_LANDING_AFTER_EJECTION or -1,
|
||||||
|
-- Added with DCS 2.7.0
|
||||||
|
ParatrooperLanding = world.event.S_EVENT_PARATROOPER_LENDING or -1,
|
||||||
|
DiscardChairAfterEjection = world.event.S_EVENT_DISCARD_CHAIR_AFTER_EJECTION or -1,
|
||||||
|
WeaponAdd = world.event.S_EVENT_WEAPON_ADD or -1,
|
||||||
|
TriggerZone = world.event.S_EVENT_TRIGGER_ZONE or -1,
|
||||||
|
LandingQualityMark = world.event.S_EVENT_LANDING_QUALITY_MARK or -1,
|
||||||
|
BDA = world.event.S_EVENT_BDA or -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The Event structure
|
--- The Event structure
|
||||||
-- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event:
|
-- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event:
|
||||||
--
|
--
|
||||||
-- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event.
|
-- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event.
|
||||||
-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ
|
-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.
|
||||||
--
|
--
|
||||||
-- @type EVENTDATA
|
-- @type EVENTDATA
|
||||||
-- @field #number id The identifier of the event.
|
-- @field #number id The identifier of the event.
|
||||||
@@ -489,6 +498,11 @@ local _EVENTMETA = {
|
|||||||
Event = "OnEventRemoveUnit",
|
Event = "OnEventRemoveUnit",
|
||||||
Text = "S_EVENT_REMOVE_UNIT"
|
Text = "S_EVENT_REMOVE_UNIT"
|
||||||
},
|
},
|
||||||
|
[EVENTS.PlayerEnterAircraft] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventPlayerEnterAircraft",
|
||||||
|
Text = "S_EVENT_PLAYER_ENTER_AIRCRAFT"
|
||||||
|
},
|
||||||
-- Added with DCS 2.5.6
|
-- Added with DCS 2.5.6
|
||||||
[EVENTS.DetailedFailure] = {
|
[EVENTS.DetailedFailure] = {
|
||||||
Order = 1,
|
Order = 1,
|
||||||
@@ -515,6 +529,37 @@ local _EVENTMETA = {
|
|||||||
Event = "OnEventLandingAfterEjection",
|
Event = "OnEventLandingAfterEjection",
|
||||||
Text = "S_EVENT_LANDING_AFTER_EJECTION"
|
Text = "S_EVENT_LANDING_AFTER_EJECTION"
|
||||||
},
|
},
|
||||||
|
-- Added with DCS 2.7.0
|
||||||
|
[EVENTS.ParatrooperLanding] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventParatrooperLanding",
|
||||||
|
Text = "S_EVENT_PARATROOPER_LENDING"
|
||||||
|
},
|
||||||
|
[EVENTS.DiscardChairAfterEjection] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventDiscardChairAfterEjection",
|
||||||
|
Text = "S_EVENT_DISCARD_CHAIR_AFTER_EJECTION"
|
||||||
|
},
|
||||||
|
[EVENTS.WeaponAdd] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventWeaponAdd",
|
||||||
|
Text = "S_EVENT_WEAPON_ADD"
|
||||||
|
},
|
||||||
|
[EVENTS.TriggerZone] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventTriggerZone",
|
||||||
|
Text = "S_EVENT_TRIGGER_ZONE"
|
||||||
|
},
|
||||||
|
[EVENTS.LandingQualityMark] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventLandingQualityMark",
|
||||||
|
Text = "S_EVENT_LANDING_QUALITYMARK"
|
||||||
|
},
|
||||||
|
[EVENTS.BDA] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventBDA",
|
||||||
|
Text = "S_EVENT_BDA"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -526,17 +571,21 @@ local _EVENTMETA = {
|
|||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @return #EVENT self
|
-- @return #EVENT self
|
||||||
function EVENT:New()
|
function EVENT:New()
|
||||||
|
|
||||||
|
-- Inherit base.
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
self:F2()
|
|
||||||
self.EventHandler = world.addEventHandler( self )
|
-- Add world event handler.
|
||||||
|
self.EventHandler = world.addEventHandler(self)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Initializes the Events structure for the event
|
--- Initializes the Events structure for the event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param DCS#world.event EventID
|
-- @param DCS#world.event EventID Event ID.
|
||||||
-- @param Core.Base#BASE EventClass
|
-- @param Core.Base#BASE EventClass The class object for which events are handled.
|
||||||
-- @return #EVENT.Events
|
-- @return #EVENT.Events
|
||||||
function EVENT:Init( EventID, EventClass )
|
function EVENT:Init( EventID, EventClass )
|
||||||
self:F3( { _EVENTMETA[EventID].Text, EventClass } )
|
self:F3( { _EVENTMETA[EventID].Text, EventClass } )
|
||||||
@@ -548,6 +597,7 @@ function EVENT:Init( EventID, EventClass )
|
|||||||
|
|
||||||
-- Each event has a subtable of EventClasses, ordered by EventPriority.
|
-- Each event has a subtable of EventClasses, ordered by EventPriority.
|
||||||
local EventPriority = EventClass:GetEventPriority()
|
local EventPriority = EventClass:GetEventPriority()
|
||||||
|
|
||||||
if not self.Events[EventID][EventPriority] then
|
if not self.Events[EventID][EventPriority] then
|
||||||
self.Events[EventID][EventPriority] = setmetatable( {}, { __mode = "k" } )
|
self.Events[EventID][EventPriority] = setmetatable( {}, { __mode = "k" } )
|
||||||
end
|
end
|
||||||
@@ -556,39 +606,44 @@ function EVENT:Init( EventID, EventClass )
|
|||||||
self.Events[EventID][EventPriority][EventClass] = {}
|
self.Events[EventID][EventPriority][EventClass] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return self.Events[EventID][EventPriority][EventClass]
|
return self.Events[EventID][EventPriority][EventClass]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a subscription
|
--- Removes a subscription
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param DCS#world.event EventID
|
-- @param DCS#world.event EventID Event ID.
|
||||||
-- @return #EVENT.Events
|
-- @return #EVENT self
|
||||||
function EVENT:RemoveEvent( EventClass, EventID )
|
function EVENT:RemoveEvent( EventClass, EventID )
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
|
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
|
||||||
|
|
||||||
|
-- Get event prio.
|
||||||
local EventPriority = EventClass:GetEventPriority()
|
local EventPriority = EventClass:GetEventPriority()
|
||||||
|
|
||||||
|
-- Events.
|
||||||
self.Events = self.Events or {}
|
self.Events = self.Events or {}
|
||||||
self.Events[EventID] = self.Events[EventID] or {}
|
self.Events[EventID] = self.Events[EventID] or {}
|
||||||
self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {}
|
self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {}
|
||||||
|
|
||||||
|
-- Remove
|
||||||
self.Events[EventID][EventPriority][EventClass] = nil
|
self.Events[EventID][EventPriority][EventClass] = nil
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Resets subscriptions
|
--- Resets subscriptions.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param DCS#world.event EventID
|
-- @param DCS#world.event EventID Event ID.
|
||||||
-- @return #EVENT.Events
|
-- @return #EVENT.Events
|
||||||
function EVENT:Reset( EventObject ) --R2.1
|
function EVENT:Reset( EventObject ) --R2.1
|
||||||
|
|
||||||
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
|
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
|
||||||
|
|
||||||
local EventPriority = EventObject:GetEventPriority()
|
local EventPriority = EventObject:GetEventPriority()
|
||||||
|
|
||||||
for EventID, EventData in pairs( self.Events ) do
|
for EventID, EventData in pairs( self.Events ) do
|
||||||
if self.EventsDead then
|
if self.EventsDead then
|
||||||
if self.EventsDead[EventID] then
|
if self.EventsDead[EventID] then
|
||||||
@@ -603,19 +658,22 @@ function EVENT:Reset( EventObject ) --R2.1
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventObject
|
-- @param Core.Base#BASE EventClass The self class object for which the events are removed.
|
||||||
function EVENT:RemoveAll( EventObject )
|
-- @return #EVENT self
|
||||||
self:F3( { EventObject:GetClassNameAndID() } )
|
function EVENT:RemoveAll(EventClass)
|
||||||
|
|
||||||
local EventClass = EventObject:GetClassNameAndID()
|
local EventClassName = EventClass:GetClassNameAndID()
|
||||||
|
|
||||||
|
-- Get Event prio.
|
||||||
local EventPriority = EventClass:GetEventPriority()
|
local EventPriority = EventClass:GetEventPriority()
|
||||||
|
|
||||||
for EventID, EventData in pairs( self.Events ) do
|
for EventID, EventData in pairs( self.Events ) do
|
||||||
self.Events[EventID][EventPriority][EventClass] = nil
|
self.Events[EventID][EventPriority][EventClass] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -626,7 +684,7 @@ end
|
|||||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||||
-- @param EventClass The instance of the class for which the event is.
|
-- @param EventClass The instance of the class for which the event is.
|
||||||
-- @param #function OnEventFunction
|
-- @param #function OnEventFunction
|
||||||
-- @return #EVENT
|
-- @return #EVENT self
|
||||||
function EVENT:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EventID )
|
function EVENT:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EventID )
|
||||||
self:F2( EventTemplate.name )
|
self:F2( EventTemplate.name )
|
||||||
|
|
||||||
@@ -636,7 +694,7 @@ function EVENT:OnEventForTemplate( EventTemplate, EventFunction, EventClass, Eve
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set a new listener for an S_EVENT_X event independent from a unit or a weapon.
|
--- Set a new listener for an `S_EVENT_X` event independent from a unit or a weapon.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is captured. When the event happens, the event process will be called in this class provided.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is captured. When the event happens, the event process will be called in this class provided.
|
||||||
@@ -652,13 +710,13 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set a new listener for an S_EVENT_X event for a UNIT.
|
--- Set a new listener for an `S_EVENT_X` event for a UNIT.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #string UnitName The name of the UNIT.
|
-- @param #string UnitName The name of the UNIT.
|
||||||
-- @param #function EventFunction The function to be called when the event occurs for the GROUP.
|
-- @param #function EventFunction The function to be called when the event occurs for the GROUP.
|
||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param EventID
|
-- @param EventID
|
||||||
-- @return #EVENT
|
-- @return #EVENT self
|
||||||
function EVENT:OnEventForUnit( UnitName, EventFunction, EventClass, EventID )
|
function EVENT:OnEventForUnit( UnitName, EventFunction, EventClass, EventID )
|
||||||
self:F2( UnitName )
|
self:F2( UnitName )
|
||||||
|
|
||||||
@@ -673,8 +731,9 @@ end
|
|||||||
-- @param #string GroupName The name of the GROUP.
|
-- @param #string GroupName The name of the GROUP.
|
||||||
-- @param #function EventFunction The function to be called when the event occurs for the GROUP.
|
-- @param #function EventFunction The function to be called when the event occurs for the GROUP.
|
||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param EventID
|
-- @param #number EventID Event ID.
|
||||||
-- @return #EVENT
|
-- @param ... Optional arguments passed to the event function.
|
||||||
|
-- @return #EVENT self
|
||||||
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... )
|
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... )
|
||||||
|
|
||||||
local Event = self:Init( EventID, EventClass )
|
local Event = self:Init( EventID, EventClass )
|
||||||
@@ -691,7 +750,7 @@ do -- OnBirth
|
|||||||
-- @param Wrapper.Group#GROUP EventGroup
|
-- @param Wrapper.Group#GROUP EventGroup
|
||||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||||
-- @param EventClass The self instance of the class for which the event is.
|
-- @param EventClass The self instance of the class for which the event is.
|
||||||
-- @return #EVENT
|
-- @return #EVENT self
|
||||||
function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventClass )
|
function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventClass )
|
||||||
self:F2( EventTemplate.name )
|
self:F2( EventTemplate.name )
|
||||||
|
|
||||||
@@ -724,10 +783,10 @@ do -- OnDead
|
|||||||
|
|
||||||
--- Create an OnDead event handler for a group
|
--- Create an OnDead event handler for a group
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Wrapper.Group#GROUP EventGroup
|
-- @param Wrapper.Group#GROUP EventGroup The GROUP object.
|
||||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||||
-- @param EventClass The self instance of the class for which the event is.
|
-- @param #table EventClass The self instance of the class for which the event is.
|
||||||
-- @return #EVENT
|
-- @return #EVENT self
|
||||||
function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventClass )
|
function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventClass )
|
||||||
self:F2( EventTemplate.name )
|
self:F2( EventTemplate.name )
|
||||||
|
|
||||||
@@ -740,12 +799,13 @@ end
|
|||||||
|
|
||||||
|
|
||||||
do -- OnLand
|
do -- OnLand
|
||||||
|
|
||||||
--- Create an OnLand event handler for a group
|
--- Create an OnLand event handler for a group
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #table EventTemplate
|
-- @param #table EventTemplate
|
||||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||||
-- @param EventClass The self instance of the class for which the event is.
|
-- @param #table EventClass The self instance of the class for which the event is.
|
||||||
-- @return #EVENT
|
-- @return #EVENT self
|
||||||
function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventClass )
|
function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventClass )
|
||||||
self:F2( EventTemplate.name )
|
self:F2( EventTemplate.name )
|
||||||
|
|
||||||
@@ -757,12 +817,13 @@ do -- OnLand
|
|||||||
end
|
end
|
||||||
|
|
||||||
do -- OnTakeOff
|
do -- OnTakeOff
|
||||||
|
|
||||||
--- Create an OnTakeOff event handler for a group
|
--- Create an OnTakeOff event handler for a group
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #table EventTemplate
|
-- @param #table EventTemplate Template table.
|
||||||
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction The function to be called when the event occurs for the unit.
|
||||||
-- @param EventClass The self instance of the class for which the event is.
|
-- @param #table EventClass The self instance of the class for which the event is.
|
||||||
-- @return #EVENT
|
-- @return #EVENT self
|
||||||
function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventClass )
|
function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventClass )
|
||||||
self:F2( EventTemplate.name )
|
self:F2( EventTemplate.name )
|
||||||
|
|
||||||
@@ -797,7 +858,7 @@ do -- Event Creation
|
|||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
|
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
|
||||||
function EVENT:CreateEventNewCargo( Cargo )
|
function EVENT:CreateEventNewCargo( Cargo )
|
||||||
self:I( { Cargo } )
|
self:F( { Cargo } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.NewCargo,
|
id = EVENTS.NewCargo,
|
||||||
@@ -900,10 +961,26 @@ do -- Event Creation
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Creation of a S_EVENT_PLAYER_ENTER_AIRCRAFT event.
|
||||||
|
-- @param #EVENT self
|
||||||
|
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
||||||
|
function EVENT:CreateEventPlayerEnterAircraft( PlayerUnit )
|
||||||
|
self:F( { PlayerUnit } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = EVENTS.PlayerEnterAircraft,
|
||||||
|
time = timer.getTime(),
|
||||||
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent( Event )
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #EVENT self
|
--- Main event function.
|
||||||
-- @param #EVENTDATA Event
|
-- @param #EVENT self
|
||||||
|
-- @param #EVENTDATA Event Event data table.
|
||||||
function EVENT:onEvent( Event )
|
function EVENT:onEvent( Event )
|
||||||
|
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
@@ -1001,6 +1078,16 @@ function EVENT:onEvent( Event )
|
|||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY" -- TODO: Bug fix for 2.1!
|
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY" -- TODO: Bug fix for 2.1!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Event.IniObjectCategory == Object.Category.BASE then
|
||||||
|
Event.IniDCSUnit = Event.initiator
|
||||||
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
|
Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName)
|
||||||
|
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||||
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.target then
|
if Event.target then
|
||||||
@@ -1028,6 +1115,8 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Event.TgtObjectCategory == Object.Category.STATIC then
|
if Event.TgtObjectCategory == Object.Category.STATIC then
|
||||||
|
BASE:T({Event = Event})
|
||||||
|
--[[
|
||||||
Event.TgtDCSUnit = Event.target
|
Event.TgtDCSUnit = Event.target
|
||||||
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
Event.TgtDCSUnitName = Event.TgtDCSUnit:getName()
|
||||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
@@ -1035,6 +1124,16 @@ function EVENT:onEvent( Event )
|
|||||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||||
|
--]]
|
||||||
|
-- Same as for Event Initiator above 2.7 issue
|
||||||
|
Event.TgtDCSUnit = Event.target
|
||||||
|
local ID=Event.initiator.id_
|
||||||
|
Event.TgtDCSUnitName = string.format("Ejected Pilot ID %s", tostring(ID))
|
||||||
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
|
--Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false )
|
||||||
|
Event.TgtCoalition = Event.IniCoalition
|
||||||
|
Event.TgtCategory = Event.IniCategory
|
||||||
|
Event.TgtTypeName = "Ejected Pilot"
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.TgtObjectCategory == Object.Category.SCENERY then
|
if Event.TgtObjectCategory == Object.Category.SCENERY then
|
||||||
@@ -1277,7 +1376,7 @@ function EVENT:onEvent( Event )
|
|||||||
Event = nil
|
Event = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- The EVENTHANDLER structure
|
--- The EVENTHANDLER structure.
|
||||||
-- @type EVENTHANDLER
|
-- @type EVENTHANDLER
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
EVENTHANDLER = {
|
EVENTHANDLER = {
|
||||||
@@ -1285,7 +1384,7 @@ EVENTHANDLER = {
|
|||||||
ClassID = 0,
|
ClassID = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The EVENTHANDLER constructor
|
--- The EVENTHANDLER constructor.
|
||||||
-- @param #EVENTHANDLER self
|
-- @param #EVENTHANDLER self
|
||||||
-- @return #EVENTHANDLER self
|
-- @return #EVENTHANDLER self
|
||||||
function EVENTHANDLER:New()
|
function EVENTHANDLER:New()
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions: **funkyfranky**
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -81,6 +81,12 @@
|
|||||||
do -- FSM
|
do -- FSM
|
||||||
|
|
||||||
--- @type FSM
|
--- @type FSM
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field Core.Scheduler#SCHEDULER CallScheduler Call scheduler.
|
||||||
|
-- @field #table options Options.
|
||||||
|
-- @field #table subs Subs.
|
||||||
|
-- @field #table Scores Scores.
|
||||||
|
-- @field #string current Current state name.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -370,7 +376,6 @@ do -- FSM
|
|||||||
|
|
||||||
self.CallScheduler = SCHEDULER:New( self )
|
self.CallScheduler = SCHEDULER:New( self )
|
||||||
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -379,7 +384,6 @@ do -- FSM
|
|||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @param #string State A string defining the start state.
|
-- @param #string State A string defining the start state.
|
||||||
function FSM:SetStartState( State )
|
function FSM:SetStartState( State )
|
||||||
|
|
||||||
self._StartState = State
|
self._StartState = State
|
||||||
self.current = State
|
self.current = State
|
||||||
end
|
end
|
||||||
@@ -389,7 +393,6 @@ do -- FSM
|
|||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @return #string A string containing the start state.
|
-- @return #string A string containing the start state.
|
||||||
function FSM:GetStartState()
|
function FSM:GetStartState()
|
||||||
|
|
||||||
return self._StartState or {}
|
return self._StartState or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -406,6 +409,7 @@ do -- FSM
|
|||||||
Transition.Event = Event
|
Transition.Event = Event
|
||||||
Transition.To = To
|
Transition.To = To
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
self:T2( Transition )
|
self:T2( Transition )
|
||||||
|
|
||||||
self._Transitions[Transition] = Transition
|
self._Transitions[Transition] = Transition
|
||||||
@@ -414,9 +418,9 @@ do -- FSM
|
|||||||
|
|
||||||
|
|
||||||
--- Returns a table of the transition rules defined within the FSM.
|
--- Returns a table of the transition rules defined within the FSM.
|
||||||
-- @return #table
|
-- @param #FSM self
|
||||||
|
-- @return #table Transitions.
|
||||||
function FSM:GetTransitions()
|
function FSM:GetTransitions()
|
||||||
|
|
||||||
return self._Transitions or {}
|
return self._Transitions or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -448,7 +452,8 @@ do -- FSM
|
|||||||
|
|
||||||
|
|
||||||
--- Returns a table of the SubFSM rules defined within the FSM.
|
--- Returns a table of the SubFSM rules defined within the FSM.
|
||||||
-- @return #table
|
-- @param #FSM self
|
||||||
|
-- @return #table Sub processes.
|
||||||
function FSM:GetProcesses()
|
function FSM:GetProcesses()
|
||||||
|
|
||||||
self:F( { Processes = self._Processes } )
|
self:F( { Processes = self._Processes } )
|
||||||
@@ -480,15 +485,17 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Adds an End state.
|
--- Adds an End state.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string State The FSM state.
|
||||||
function FSM:AddEndState( State )
|
function FSM:AddEndState( State )
|
||||||
|
|
||||||
self._EndStates[State] = State
|
self._EndStates[State] = State
|
||||||
self.endstates[State] = State
|
self.endstates[State] = State
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the End states.
|
--- Returns the End states.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @return #table End states.
|
||||||
function FSM:GetEndStates()
|
function FSM:GetEndStates()
|
||||||
|
|
||||||
return self._EndStates or {}
|
return self._EndStates or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -532,18 +539,22 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a table with the scores defined.
|
--- Returns a table with the scores defined.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #table Scores.
|
||||||
function FSM:GetScores()
|
function FSM:GetScores()
|
||||||
|
|
||||||
return self._Scores or {}
|
return self._Scores or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a table with the Subs defined.
|
--- Returns a table with the Subs defined.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @return #table Sub processes.
|
||||||
function FSM:GetSubs()
|
function FSM:GetSubs()
|
||||||
|
|
||||||
return self.options.subs
|
return self.options.subs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Load call backs.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #table CallBackTable Table of call backs.
|
||||||
function FSM:LoadCallBacks( CallBackTable )
|
function FSM:LoadCallBacks( CallBackTable )
|
||||||
|
|
||||||
for name, callback in pairs( CallBackTable or {} ) do
|
for name, callback in pairs( CallBackTable or {} ) do
|
||||||
@@ -552,20 +563,33 @@ do -- FSM
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Event map.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #table Events Events.
|
||||||
|
-- @param #table EventStructure Event structure.
|
||||||
function FSM:_eventmap( Events, EventStructure )
|
function FSM:_eventmap( Events, EventStructure )
|
||||||
|
|
||||||
local Event = EventStructure.Event
|
local Event = EventStructure.Event
|
||||||
local __Event = "__" .. EventStructure.Event
|
local __Event = "__" .. EventStructure.Event
|
||||||
|
|
||||||
self[Event] = self[Event] or self:_create_transition(Event)
|
self[Event] = self[Event] or self:_create_transition(Event)
|
||||||
self[__Event] = self[__Event] or self:_delayed_transition(Event)
|
self[__Event] = self[__Event] or self:_delayed_transition(Event)
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
self:T2( "Added methods: " .. Event .. ", " .. __Event )
|
self:T2( "Added methods: " .. Event .. ", " .. __Event )
|
||||||
|
|
||||||
Events[Event] = self.Events[Event] or { map = {} }
|
Events[Event] = self.Events[Event] or { map = {} }
|
||||||
self:_add_to_map( Events[Event].map, EventStructure )
|
self:_add_to_map( Events[Event].map, EventStructure )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sub maps.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #table subs Subs.
|
||||||
|
-- @param #table sub Sub.
|
||||||
|
-- @param #string name Name.
|
||||||
function FSM:_submap( subs, sub, name )
|
function FSM:_submap( subs, sub, name )
|
||||||
--self:F( { sub = sub, name = name } )
|
|
||||||
subs[sub.From] = subs[sub.From] or {}
|
subs[sub.From] = subs[sub.From] or {}
|
||||||
subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {}
|
subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {}
|
||||||
|
|
||||||
@@ -578,22 +602,24 @@ do -- FSM
|
|||||||
subs[sub.From][sub.Event][sub].ReturnEvents = sub.ReturnEvents or {} -- these events need to be given to find the correct continue event ... if none given, the processing will stop.
|
subs[sub.From][sub.Event][sub].ReturnEvents = sub.ReturnEvents or {} -- these events need to be given to find the correct continue event ... if none given, the processing will stop.
|
||||||
subs[sub.From][sub.Event][sub].name = name
|
subs[sub.From][sub.Event][sub].name = name
|
||||||
subs[sub.From][sub.Event][sub].fsmparent = self
|
subs[sub.From][sub.Event][sub].fsmparent = self
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Call handler.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string step Step "onafter", "onbefore", "onenter", "onleave".
|
||||||
|
-- @param #string trigger Trigger.
|
||||||
|
-- @param #table params Parameters.
|
||||||
|
-- @param #string EventName Event name.
|
||||||
|
-- @return Value.
|
||||||
function FSM:_call_handler( step, trigger, params, EventName )
|
function FSM:_call_handler( step, trigger, params, EventName )
|
||||||
|
--env.info(string.format("FF T=%.3f _call_handler step=%s, trigger=%s, event=%s", timer.getTime(), step, trigger, EventName))
|
||||||
|
|
||||||
local handler = step .. trigger
|
local handler = step .. trigger
|
||||||
local ErrorHandler = function( errmsg )
|
|
||||||
|
|
||||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
|
||||||
if BASE.Debug ~= nil then
|
|
||||||
env.info( BASE.Debug.traceback() )
|
|
||||||
end
|
|
||||||
|
|
||||||
return errmsg
|
|
||||||
end
|
|
||||||
if self[handler] then
|
if self[handler] then
|
||||||
|
|
||||||
|
--[[
|
||||||
if step == "onafter" or step == "OnAfter" then
|
if step == "onafter" or step == "OnAfter" then
|
||||||
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. params[2] .. ">" .. step .. params[2] .. "()" .. " >> " .. params[3] )
|
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. params[2] .. ">" .. step .. params[2] .. "()" .. " >> " .. params[3] )
|
||||||
elseif step == "onbefore" or step == "OnBefore" then
|
elseif step == "onbefore" or step == "OnBefore" then
|
||||||
@@ -605,13 +631,32 @@ do -- FSM
|
|||||||
else
|
else
|
||||||
self:T( ":::>" .. step .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. params[3] )
|
self:T( ":::>" .. step .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. params[3] )
|
||||||
end
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
self._EventSchedules[EventName] = nil
|
self._EventSchedules[EventName] = nil
|
||||||
|
|
||||||
|
-- Error handler.
|
||||||
|
local ErrorHandler = function( errmsg )
|
||||||
|
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||||
|
if BASE.Debug ~= nil then
|
||||||
|
env.info( BASE.Debug.traceback() )
|
||||||
|
end
|
||||||
|
return errmsg
|
||||||
|
end
|
||||||
|
|
||||||
|
--return self[handler](self, unpack( params ))
|
||||||
|
|
||||||
|
-- Protected call.
|
||||||
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||||
return Value
|
return Value
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #FSM self
|
--- Handler.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string EventName Event name.
|
||||||
|
-- @param ... Arguments.
|
||||||
function FSM._handler( self, EventName, ... )
|
function FSM._handler( self, EventName, ... )
|
||||||
|
|
||||||
local Can, To = self:can( EventName )
|
local Can, To = self:can( EventName )
|
||||||
@@ -621,7 +666,11 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Can then
|
if Can then
|
||||||
|
|
||||||
|
-- From state.
|
||||||
local From = self.current
|
local From = self.current
|
||||||
|
|
||||||
|
-- Parameters.
|
||||||
local Params = { From, EventName, To, ... }
|
local Params = { From, EventName, To, ... }
|
||||||
|
|
||||||
|
|
||||||
@@ -632,8 +681,8 @@ do -- FSM
|
|||||||
self["onafter".. EventName] or
|
self["onafter".. EventName] or
|
||||||
self["OnAfter".. EventName] or
|
self["OnAfter".. EventName] or
|
||||||
self["onenter".. To] or
|
self["onenter".. To] or
|
||||||
self["OnEnter".. To]
|
self["OnEnter".. To] then
|
||||||
then
|
|
||||||
if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then
|
if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then
|
||||||
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName )
|
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName )
|
||||||
return false
|
return false
|
||||||
@@ -653,8 +702,11 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
local ClassName = self:GetClassName()
|
local ClassName = self:GetClassName()
|
||||||
|
|
||||||
if ClassName == "FSM" then
|
if ClassName == "FSM" then
|
||||||
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To )
|
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To )
|
||||||
end
|
end
|
||||||
@@ -672,46 +724,56 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- New current state.
|
||||||
self.current = To
|
self.current = To
|
||||||
|
|
||||||
local execute = true
|
local execute = true
|
||||||
|
|
||||||
local subtable = self:_gosub( From, EventName )
|
local subtable = self:_gosub( From, EventName )
|
||||||
|
|
||||||
for _, sub in pairs( subtable ) do
|
for _, sub in pairs( subtable ) do
|
||||||
|
|
||||||
--if sub.nextevent then
|
--if sub.nextevent then
|
||||||
-- self:F2( "nextevent = " .. sub.nextevent )
|
-- self:F2( "nextevent = " .. sub.nextevent )
|
||||||
-- self[sub.nextevent]( self )
|
-- self[sub.nextevent]( self )
|
||||||
--end
|
--end
|
||||||
|
|
||||||
self:T( "*** FSM *** Sub *** " .. sub.StartEvent )
|
self:T( "*** FSM *** Sub *** " .. sub.StartEvent )
|
||||||
|
|
||||||
sub.fsm.fsmparent = self
|
sub.fsm.fsmparent = self
|
||||||
sub.fsm.ReturnEvents = sub.ReturnEvents
|
sub.fsm.ReturnEvents = sub.ReturnEvents
|
||||||
sub.fsm[sub.StartEvent]( sub.fsm )
|
sub.fsm[sub.StartEvent]( sub.fsm )
|
||||||
|
|
||||||
execute = false
|
execute = false
|
||||||
end
|
end
|
||||||
|
|
||||||
local fsmparent, Event = self:_isendstate( To )
|
local fsmparent, Event = self:_isendstate( To )
|
||||||
|
|
||||||
if fsmparent and Event then
|
if fsmparent and Event then
|
||||||
|
|
||||||
self:T( "*** FSM *** End *** " .. Event )
|
self:T( "*** FSM *** End *** " .. Event )
|
||||||
|
|
||||||
self:_call_handler("onenter", To, Params, EventName )
|
self:_call_handler("onenter", To, Params, EventName )
|
||||||
self:_call_handler("OnEnter", To, Params, EventName )
|
self:_call_handler("OnEnter", To, Params, EventName )
|
||||||
self:_call_handler("onafter", EventName, Params, EventName )
|
self:_call_handler("onafter", EventName, Params, EventName )
|
||||||
self:_call_handler("OnAfter", EventName, Params, EventName )
|
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||||
self:_call_handler("onstate", "change", Params, EventName )
|
self:_call_handler("onstate", "change", Params, EventName )
|
||||||
|
|
||||||
fsmparent[Event]( fsmparent )
|
fsmparent[Event]( fsmparent )
|
||||||
|
|
||||||
execute = false
|
execute = false
|
||||||
end
|
end
|
||||||
|
|
||||||
if execute then
|
if execute then
|
||||||
|
|
||||||
self:_call_handler("onafter", EventName, Params, EventName )
|
self:_call_handler("onafter", EventName, Params, EventName )
|
||||||
self:_call_handler("OnAfter", EventName, Params, EventName )
|
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||||
|
|
||||||
-- only execute the call if the From state is not equal to the To state! Otherwise this function should never execute!
|
|
||||||
--if from ~= to then
|
|
||||||
self:_call_handler("onenter", To, Params, EventName )
|
self:_call_handler("onenter", To, Params, EventName )
|
||||||
self:_call_handler("OnEnter", To, Params, EventName )
|
self:_call_handler("OnEnter", To, Params, EventName )
|
||||||
--end
|
|
||||||
|
|
||||||
self:_call_handler("onstate", "change", Params, EventName )
|
self:_call_handler("onstate", "change", Params, EventName )
|
||||||
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:T( "*** FSM *** NO Transition *** " .. self.current .. " --> " .. EventName .. " --> ? " )
|
self:T( "*** FSM *** NO Transition *** " .. self.current .. " --> " .. EventName .. " --> ? " )
|
||||||
@@ -720,36 +782,67 @@ do -- FSM
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Delayed transition.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string EventName Event name.
|
||||||
|
-- @return #function Function.
|
||||||
function FSM:_delayed_transition( EventName )
|
function FSM:_delayed_transition( EventName )
|
||||||
|
|
||||||
return function( self, DelaySeconds, ... )
|
return function( self, DelaySeconds, ... )
|
||||||
|
|
||||||
|
-- Debug.
|
||||||
self:T2( "Delayed Event: " .. EventName )
|
self:T2( "Delayed Event: " .. EventName )
|
||||||
|
|
||||||
local CallID = 0
|
local CallID = 0
|
||||||
if DelaySeconds ~= nil then
|
if DelaySeconds ~= nil then
|
||||||
|
|
||||||
if DelaySeconds < 0 then -- Only call the event ONCE!
|
if DelaySeconds < 0 then -- Only call the event ONCE!
|
||||||
|
|
||||||
DelaySeconds = math.abs( DelaySeconds )
|
DelaySeconds = math.abs( DelaySeconds )
|
||||||
|
|
||||||
if not self._EventSchedules[EventName] then
|
if not self._EventSchedules[EventName] then
|
||||||
|
|
||||||
|
-- Call _handler.
|
||||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||||
|
|
||||||
|
-- Set call ID.
|
||||||
self._EventSchedules[EventName] = CallID
|
self._EventSchedules[EventName] = CallID
|
||||||
|
|
||||||
|
-- Debug output.
|
||||||
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||||
else
|
else
|
||||||
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds))
|
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds))
|
||||||
-- reschedule
|
-- reschedule
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
||||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||||
|
|
||||||
self:T2(string.format("Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
self:T2(string.format("Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Debug.
|
||||||
self:T2( { CallID = CallID } )
|
self:T2( { CallID = CallID } )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Create transition.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string EventName Event name.
|
||||||
|
-- @return #function Function.
|
||||||
function FSM:_create_transition( EventName )
|
function FSM:_create_transition( EventName )
|
||||||
return function( self, ... ) return self._handler( self, EventName , ... ) end
|
return function( self, ... ) return self._handler( self, EventName , ... ) end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Go sub.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string ParentFrom Parent from state.
|
||||||
|
-- @param #string ParentEvent Parent event name.
|
||||||
|
-- @return #table Subs.
|
||||||
function FSM:_gosub( ParentFrom, ParentEvent )
|
function FSM:_gosub( ParentFrom, ParentEvent )
|
||||||
local fsmtable = {}
|
local fsmtable = {}
|
||||||
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
|
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
|
||||||
@@ -760,8 +853,14 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Is end state.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string Current Current state name.
|
||||||
|
-- @return #table FSM parent.
|
||||||
|
-- @return #string Event name.
|
||||||
function FSM:_isendstate( Current )
|
function FSM:_isendstate( Current )
|
||||||
local FSMParent = self.fsmparent
|
local FSMParent = self.fsmparent
|
||||||
|
|
||||||
if FSMParent and self.endstates[Current] then
|
if FSMParent and self.endstates[Current] then
|
||||||
--self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
|
--self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
|
||||||
FSMParent.current = Current
|
FSMParent.current = Current
|
||||||
@@ -779,8 +878,13 @@ do -- FSM
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add to map.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #table Map Map.
|
||||||
|
-- @param #table Event Event table.
|
||||||
function FSM:_add_to_map( Map, Event )
|
function FSM:_add_to_map( Map, Event )
|
||||||
self:F3( { Map, Event } )
|
self:F3( { Map, Event } )
|
||||||
|
|
||||||
if type(Event.From) == 'string' then
|
if type(Event.From) == 'string' then
|
||||||
Map[Event.From] = Event.To
|
Map[Event.From] = Event.To
|
||||||
else
|
else
|
||||||
@@ -788,33 +892,60 @@ do -- FSM
|
|||||||
Map[From] = Event.To
|
Map[From] = Event.To
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T3( { Map, Event } )
|
self:T3( { Map, Event } )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get current state.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @return #string Current FSM state.
|
||||||
function FSM:GetState()
|
function FSM:GetState()
|
||||||
return self.current
|
return self.current
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get current state.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @return #string Current FSM state.
|
||||||
function FSM:GetCurrentState()
|
function FSM:GetCurrentState()
|
||||||
return self.current
|
return self.current
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if FSM is in state.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string State State name.
|
||||||
|
-- @param #boolean If true, FSM is in this state.
|
||||||
function FSM:Is( State )
|
function FSM:Is( State )
|
||||||
return self.current == State
|
return self.current == State
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if FSM is in state.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string State State name.
|
||||||
|
-- @param #boolean If true, FSM is in this state.
|
||||||
function FSM:is(state)
|
function FSM:is(state)
|
||||||
return self.current == state
|
return self.current == state
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if can do an event.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string e Event name.
|
||||||
|
-- @return #boolean If true, FSM can do the event.
|
||||||
|
-- @return #string To state.
|
||||||
function FSM:can(e)
|
function FSM:can(e)
|
||||||
|
|
||||||
local Event = self.Events[e]
|
local Event = self.Events[e]
|
||||||
self:F3( { self.current, Event } )
|
|
||||||
|
--self:F3( { self.current, Event } )
|
||||||
|
|
||||||
local To = Event and Event.map[self.current] or Event.map['*']
|
local To = Event and Event.map[self.current] or Event.map['*']
|
||||||
|
|
||||||
return To ~= nil, To
|
return To ~= nil, To
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if cannot do an event.
|
||||||
|
-- @param #FSM self
|
||||||
|
-- @param #string e Event name.
|
||||||
|
-- @return #boolean If true, FSM cannot do the event.
|
||||||
function FSM:cannot(e)
|
function FSM:cannot(e)
|
||||||
return not self:can(e)
|
return not self:can(e)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -175,10 +175,6 @@ do -- COORDINATE
|
|||||||
-- In order to use the most optimal road system to transport vehicles, the method @{#COORDINATE.GetPathOnRoad}() will calculate
|
-- In order to use the most optimal road system to transport vehicles, the method @{#COORDINATE.GetPathOnRoad}() will calculate
|
||||||
-- the most optimal path following the road between two coordinates.
|
-- the most optimal path following the road between two coordinates.
|
||||||
--
|
--
|
||||||
--
|
|
||||||
--
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- ## 8) Metric or imperial system
|
-- ## 8) Metric or imperial system
|
||||||
--
|
--
|
||||||
-- * @{#COORDINATE.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles.
|
-- * @{#COORDINATE.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles.
|
||||||
@@ -232,6 +228,7 @@ do -- COORDINATE
|
|||||||
-- @return #COORDINATE
|
-- @return #COORDINATE
|
||||||
function COORDINATE:New( x, y, z )
|
function COORDINATE:New( x, y, z )
|
||||||
|
|
||||||
|
--env.info("FF COORDINATE New")
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE
|
local self = BASE:Inherit( self, BASE:New() ) -- #COORDINATE
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
@@ -303,6 +300,45 @@ do -- COORDINATE
|
|||||||
return { x = self.x, y = self.z }
|
return { x = self.x, y = self.z }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Update x,y,z coordinates from a given 3D vector.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param DCS#Vec3 Vec3 The 3D vector with x,y,z components.
|
||||||
|
-- @return #COORDINATE The modified COORDINATE itself.
|
||||||
|
function COORDINATE:UpdateFromVec3(Vec3)
|
||||||
|
|
||||||
|
self.x=Vec3.x
|
||||||
|
self.y=Vec3.y
|
||||||
|
self.z=Vec3.z
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update x,y,z coordinates from another given COORDINATE.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #COORDINATE Coordinate The coordinate with the new x,y,z positions.
|
||||||
|
-- @return #COORDINATE The modified COORDINATE itself.
|
||||||
|
function COORDINATE:UpdateFromCoordinate(Coordinate)
|
||||||
|
|
||||||
|
self.x=Coordinate.x
|
||||||
|
self.y=Coordinate.y
|
||||||
|
self.z=Coordinate.z
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update x and z coordinates from a given 2D vector.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param DCS#Vec2 Vec2 The 2D vector with x,y components. x is overwriting COORDINATE.x while y is overwriting COORDINATE.z.
|
||||||
|
-- @return #COORDINATE The modified COORDINATE itself.
|
||||||
|
function COORDINATE:UpdateFromVec2(Vec2)
|
||||||
|
|
||||||
|
self.x=Vec2.x
|
||||||
|
self.z=Vec2.y
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the coordinate from the latitude and longitude given in decimal degrees.
|
--- Returns the coordinate from the latitude and longitude given in decimal degrees.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number latitude Latitude in decimal degrees.
|
-- @param #number latitude Latitude in decimal degrees.
|
||||||
@@ -319,9 +355,9 @@ do -- COORDINATE
|
|||||||
|
|
||||||
-- Adjust height
|
-- Adjust height
|
||||||
if altitude==nil then
|
if altitude==nil then
|
||||||
_coord.y=altitude
|
|
||||||
else
|
|
||||||
_coord.y=self:GetLandHeight()
|
_coord.y=self:GetLandHeight()
|
||||||
|
else
|
||||||
|
_coord.y=altitude
|
||||||
end
|
end
|
||||||
|
|
||||||
return _coord
|
return _coord
|
||||||
@@ -506,19 +542,29 @@ do -- COORDINATE
|
|||||||
-- @param DCS#Distance Distance The Distance to be added in meters.
|
-- @param DCS#Distance Distance The Distance to be added in meters.
|
||||||
-- @param DCS#Angle Angle The Angle in degrees. Defaults to 0 if not specified (nil).
|
-- @param DCS#Angle Angle The Angle in degrees. Defaults to 0 if not specified (nil).
|
||||||
-- @param #boolean Keepalt If true, keep altitude of original coordinate. Default is that the new coordinate is created at the translated land height.
|
-- @param #boolean Keepalt If true, keep altitude of original coordinate. Default is that the new coordinate is created at the translated land height.
|
||||||
-- @return Core.Point#COORDINATE The new calculated COORDINATE.
|
-- @param #boolean Overwrite If true, overwrite the original COORDINATE with the translated one. Otherwise, create a new COODINATE.
|
||||||
function COORDINATE:Translate( Distance, Angle, Keepalt )
|
-- @return #COORDINATE The new calculated COORDINATE.
|
||||||
local SX = self.x
|
function COORDINATE:Translate( Distance, Angle, Keepalt, Overwrite )
|
||||||
local SY = self.z
|
|
||||||
local Radians = (Angle or 0) / 180 * math.pi
|
|
||||||
local TX = Distance * math.cos( Radians ) + SX
|
|
||||||
local TY = Distance * math.sin( Radians ) + SY
|
|
||||||
|
|
||||||
if Keepalt then
|
-- Angle in rad.
|
||||||
return COORDINATE:NewFromVec3( { x = TX, y=self.y, z = TY } )
|
local alpha = math.rad((Angle or 0))
|
||||||
|
|
||||||
|
local x = Distance * math.cos(alpha) + self.x -- New x
|
||||||
|
local z = Distance * math.sin(alpha) + self.z -- New z
|
||||||
|
|
||||||
|
local y=Keepalt and self.y or land.getHeight({x=x, y=z})
|
||||||
|
|
||||||
|
if Overwrite then
|
||||||
|
self.x=x
|
||||||
|
self.y=y
|
||||||
|
self.z=z
|
||||||
|
return self
|
||||||
else
|
else
|
||||||
return COORDINATE:NewFromVec2( { x = TX, y = TY } )
|
--env.info("FF translate with NEW coordinate T="..timer.getTime())
|
||||||
|
local coord=COORDINATE:New(x, y, z)
|
||||||
|
return coord
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Rotate coordinate in 2D (x,z) space.
|
--- Rotate coordinate in 2D (x,z) space.
|
||||||
@@ -716,17 +762,22 @@ do -- COORDINATE
|
|||||||
-- Move the vector to start at the end of A.
|
-- Move the vector to start at the end of A.
|
||||||
vec=UTILS.VecAdd(self, vec)
|
vec=UTILS.VecAdd(self, vec)
|
||||||
|
|
||||||
return self:New(vec.x,vec.y,vec.z)
|
local coord=COORDINATE:New(vec.x,vec.y,vec.z)
|
||||||
|
return coord
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return the 2D distance in meters between the target COORDINATE and the COORDINATE.
|
--- Return the 2D distance in meters between the target COORDINATE and the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
-- @param #COORDINATE TargetCoordinate The target COORDINATE. Can also be a DCS#Vec3.
|
||||||
-- @return DCS#Distance Distance The distance in meters.
|
-- @return DCS#Distance Distance The distance in meters.
|
||||||
function COORDINATE:Get2DDistance( TargetCoordinate )
|
function COORDINATE:Get2DDistance(TargetCoordinate)
|
||||||
local TargetVec3 = TargetCoordinate:GetVec3()
|
|
||||||
local SourceVec3 = self:GetVec3()
|
local a={x=TargetCoordinate.x-self.x, y=0, z=TargetCoordinate.z-self.z}
|
||||||
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
|
|
||||||
|
local d=UTILS.VecNorm(a)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the temperature in Degrees Celsius.
|
--- Returns the temperature in Degrees Celsius.
|
||||||
@@ -1086,23 +1137,6 @@ do -- COORDINATE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a Distance in meters from the COORDINATE horizontal plane, with the given angle, and calculate the new COORDINATE.
|
|
||||||
-- @param #COORDINATE self
|
|
||||||
-- @param DCS#Distance Distance The Distance to be added in meters.
|
|
||||||
-- @param DCS#Angle Angle The Angle in degrees.
|
|
||||||
-- @return #COORDINATE The new calculated COORDINATE.
|
|
||||||
function COORDINATE:Translate( Distance, Angle )
|
|
||||||
local SX = self.x
|
|
||||||
local SZ = self.z
|
|
||||||
local Radians = Angle / 180 * math.pi
|
|
||||||
local TX = Distance * math.cos( Radians ) + SX
|
|
||||||
local TZ = Distance * math.sin( Radians ) + SZ
|
|
||||||
|
|
||||||
return COORDINATE:New( TX, self.y, TZ )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Build an air type route point.
|
--- Build an air type route point.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||||
@@ -1290,9 +1324,11 @@ do -- COORDINATE
|
|||||||
RoutePoint.x = self.x
|
RoutePoint.x = self.x
|
||||||
RoutePoint.y = self.z
|
RoutePoint.y = self.z
|
||||||
|
|
||||||
RoutePoint.alt = self:GetLandHeight()+1 -- self.y
|
RoutePoint.alt = self:GetLandHeight()+1
|
||||||
RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO
|
RoutePoint.alt_type = COORDINATE.WaypointAltType.BARO
|
||||||
|
|
||||||
|
RoutePoint.type = "Turning Point"
|
||||||
|
|
||||||
RoutePoint.action = Formation or "Off Road"
|
RoutePoint.action = Formation or "Off Road"
|
||||||
RoutePoint.formation_template=""
|
RoutePoint.formation_template=""
|
||||||
|
|
||||||
@@ -1351,7 +1387,7 @@ do -- COORDINATE
|
|||||||
-- @param #number Coalition (Optional) Coalition of the airbase.
|
-- @param #number Coalition (Optional) Coalition of the airbase.
|
||||||
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
||||||
-- @return #number Distance to the closest airbase in meters.
|
-- @return #number Distance to the closest airbase in meters.
|
||||||
function COORDINATE:GetClosestAirbase(Category, Coalition)
|
function COORDINATE:GetClosestAirbase2(Category, Coalition)
|
||||||
|
|
||||||
-- Get all airbases of the map.
|
-- Get all airbases of the map.
|
||||||
local airbases=AIRBASE.GetAllAirbases(Coalition)
|
local airbases=AIRBASE.GetAllAirbases(Coalition)
|
||||||
@@ -1385,6 +1421,36 @@ do -- COORDINATE
|
|||||||
return closest,distmin
|
return closest,distmin
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Gets the nearest airbase with respect to the current coordinates.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #number Category (Optional) Category of the airbase. Enumerator of @{Wrapper.Airbase#AIRBASE.Category}.
|
||||||
|
-- @param #number Coalition (Optional) Coalition of the airbase.
|
||||||
|
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
||||||
|
-- @return #number Distance to the closest airbase in meters.
|
||||||
|
function COORDINATE:GetClosestAirbase(Category, Coalition)
|
||||||
|
|
||||||
|
local a=self:GetVec3()
|
||||||
|
|
||||||
|
local distmin=math.huge
|
||||||
|
local airbase=nil
|
||||||
|
for DCSairbaseID, DCSairbase in pairs(world.getAirbases(Coalition)) do
|
||||||
|
local b=DCSairbase:getPoint()
|
||||||
|
|
||||||
|
local c=UTILS.VecSubstract(a,b)
|
||||||
|
local dist=UTILS.VecNorm(c)
|
||||||
|
|
||||||
|
--env.info(string.format("Airbase %s dist=%d category=%d", DCSairbase:getName(), dist, DCSairbase:getCategory()))
|
||||||
|
|
||||||
|
if dist<distmin and (Category==nil or Category==DCSairbase:getDesc().category) then
|
||||||
|
distmin=dist
|
||||||
|
airbase=DCSairbase
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return AIRBASE:Find(airbase)
|
||||||
|
end
|
||||||
|
|
||||||
--- Gets the nearest parking spot.
|
--- Gets the nearest parking spot.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at this airbase.
|
-- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at this airbase.
|
||||||
@@ -1526,25 +1592,6 @@ do -- COORDINATE
|
|||||||
local coord=COORDINATE:NewFromVec2(_vec2)
|
local coord=COORDINATE:NewFromVec2(_vec2)
|
||||||
|
|
||||||
Path[#Path+1]=coord
|
Path[#Path+1]=coord
|
||||||
|
|
||||||
if MarkPath then
|
|
||||||
coord:MarkToAll(string.format("Path segment %d.", _i))
|
|
||||||
end
|
|
||||||
if SmokePath then
|
|
||||||
coord:SmokeGreen()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Mark/smoke endpoints
|
|
||||||
if IncludeEndpoints then
|
|
||||||
if MarkPath then
|
|
||||||
COORDINATE:NewFromVec2(path[1]):MarkToAll("Path Initinal Point")
|
|
||||||
COORDINATE:NewFromVec2(path[1]):MarkToAll("Path Final Point")
|
|
||||||
end
|
|
||||||
if SmokePath then
|
|
||||||
COORDINATE:NewFromVec2(path[1]):SmokeBlue()
|
|
||||||
COORDINATE:NewFromVec2(path[#path]):SmokeBlue()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -1557,6 +1604,23 @@ do -- COORDINATE
|
|||||||
Path[#Path+1]=ToCoord
|
Path[#Path+1]=ToCoord
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Mark or smoke.
|
||||||
|
if MarkPath or SmokePath then
|
||||||
|
for i,c in pairs(Path) do
|
||||||
|
local coord=c --#COORDINATE
|
||||||
|
if MarkPath then
|
||||||
|
coord:MarkToAll(string.format("Path segment %d", i))
|
||||||
|
end
|
||||||
|
if SmokePath then
|
||||||
|
if i==1 or i==#Path then
|
||||||
|
coord:SmokeBlue()
|
||||||
|
else
|
||||||
|
coord:SmokeGreen()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Sum up distances.
|
-- Sum up distances.
|
||||||
if #Path>=2 then
|
if #Path>=2 then
|
||||||
for i=1,#Path-1 do
|
for i=1,#Path-1 do
|
||||||
@@ -1564,7 +1628,7 @@ do -- COORDINATE
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- There are cases where no path on road can be found.
|
-- There are cases where no path on road can be found.
|
||||||
return nil,nil
|
return nil,nil,false
|
||||||
end
|
end
|
||||||
|
|
||||||
return Path, Way, GotPath
|
return Path, Way, GotPath
|
||||||
@@ -1915,21 +1979,80 @@ do -- COORDINATE
|
|||||||
trigger.action.removeMark( MarkID )
|
trigger.action.removeMark( MarkID )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Line to all.
|
||||||
|
-- Creates a line on the F10 map from one point to another.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #COORDINATE Endpoint COORDIANTE to where the line is drawn.
|
||||||
|
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
||||||
|
-- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid.
|
||||||
|
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default).
|
||||||
|
-- @param #number Alpha Transparency [0,1]. Default 1.
|
||||||
|
-- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false.
|
||||||
|
-- @param #string Text (Optional) Text displayed when mark is added. Default none.
|
||||||
|
-- @return #number The resulting Mark ID which is a number.
|
||||||
|
function COORDINATE:LineToAll(Endpoint, Coalition, LineType, Color, Alpha, ReadOnly, Text)
|
||||||
|
local MarkID = UTILS.GetMarkID()
|
||||||
|
if ReadOnly==nil then
|
||||||
|
ReadOnly=false
|
||||||
|
end
|
||||||
|
local vec3=Endpoint:GetVec3()
|
||||||
|
Coalition=Coalition or -1
|
||||||
|
Color=Color or {1,0,0}
|
||||||
|
Color[4]=Alpha or 1.0
|
||||||
|
LineType=LineType or 1
|
||||||
|
trigger.action.lineToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, LineType, ReadOnly, Text or "")
|
||||||
|
return MarkID
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Circle to all.
|
||||||
|
-- Creates a circle on the map with a given radius, color, fill color, and outline.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #COORDINATE Center COORDIANTE of the center of the circle.
|
||||||
|
-- @param #numberr Radius Radius in meters. Default 1000 m.
|
||||||
|
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
||||||
|
-- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid.
|
||||||
|
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red (default).
|
||||||
|
-- @param #number Alpha Transparency [0,1]. Default 1.
|
||||||
|
-- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red (default).
|
||||||
|
-- @param #number FillAlpha Transparency [0,1]. Default 0.5.
|
||||||
|
-- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false.
|
||||||
|
-- @param #string Text (Optional) Text displayed when mark is added. Default none.
|
||||||
|
-- @return #number The resulting Mark ID which is a number.
|
||||||
|
function COORDINATE:CircleToAll(Radius, Coalition, LineType, Color, Alpha, FillColor, FillAlpha, ReadOnly, Text)
|
||||||
|
local MarkID = UTILS.GetMarkID()
|
||||||
|
if ReadOnly==nil then
|
||||||
|
ReadOnly=false
|
||||||
|
end
|
||||||
|
local vec3=self:GetVec3()
|
||||||
|
Radius=Radius or 1000
|
||||||
|
Coalition=Coalition or -1
|
||||||
|
Color=Color or {1,0,0}
|
||||||
|
Color[4]=Alpha or 1.0
|
||||||
|
LineType=LineType or 1
|
||||||
|
FillColor=FillColor or {1,0,0}
|
||||||
|
FillColor[4]=FillAlpha or 0.5
|
||||||
|
trigger.action.circleToAll(Coalition, MarkID, vec3, Radius, Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
return MarkID
|
||||||
|
end
|
||||||
|
|
||||||
end -- Markings
|
end -- Markings
|
||||||
|
|
||||||
|
|
||||||
--- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate.
|
--- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE ToCoordinate
|
-- @param #COORDINATE ToCoordinate
|
||||||
|
-- @param #number Offset Height offset in meters. Default 2 m.
|
||||||
-- @return #boolean true If the ToCoordinate has LOS with the Coordinate, otherwise false.
|
-- @return #boolean true If the ToCoordinate has LOS with the Coordinate, otherwise false.
|
||||||
function COORDINATE:IsLOS( ToCoordinate )
|
function COORDINATE:IsLOS( ToCoordinate, Offset )
|
||||||
|
|
||||||
|
Offset=Offset or 2
|
||||||
|
|
||||||
-- Measurement of visibility should not be from the ground, so Adding a hypotethical 2 meters to each Coordinate.
|
-- Measurement of visibility should not be from the ground, so Adding a hypotethical 2 meters to each Coordinate.
|
||||||
local FromVec3 = self:GetVec3()
|
local FromVec3 = self:GetVec3()
|
||||||
FromVec3.y = FromVec3.y + 2
|
FromVec3.y = FromVec3.y + Offset
|
||||||
|
|
||||||
local ToVec3 = ToCoordinate:GetVec3()
|
local ToVec3 = ToCoordinate:GetVec3()
|
||||||
ToVec3.y = ToVec3.y + 2
|
ToVec3.y = ToVec3.y + Offset
|
||||||
|
|
||||||
local IsLOS = land.isVisible( FromVec3, ToVec3 )
|
local IsLOS = land.isVisible( FromVec3, ToVec3 )
|
||||||
|
|
||||||
@@ -1969,6 +2092,296 @@ do -- COORDINATE
|
|||||||
return InSphere
|
return InSphere
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get sun rise time for a specific date at the coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #number Day The day.
|
||||||
|
-- @param #number Month The month.
|
||||||
|
-- @param #number Year The year.
|
||||||
|
-- @param #boolean InSeconds If true, return the sun rise time in seconds.
|
||||||
|
-- @return #string Sunrise time, e.g. "05:41".
|
||||||
|
function COORDINATE:GetSunriseAtDate(Day, Month, Year, InSeconds)
|
||||||
|
|
||||||
|
-- Day of the year.
|
||||||
|
local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day)
|
||||||
|
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||||
|
|
||||||
|
if InSeconds then
|
||||||
|
return sunrise
|
||||||
|
else
|
||||||
|
return UTILS.SecondsToClock(sunrise, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get sun rise time for a specific day of the year at the coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #number DayOfYear The day of the year.
|
||||||
|
-- @param #boolean InSeconds If true, return the sun rise time in seconds.
|
||||||
|
-- @return #string Sunrise time, e.g. "05:41".
|
||||||
|
function COORDINATE:GetSunriseAtDayOfYear(DayOfYear, InSeconds)
|
||||||
|
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||||
|
|
||||||
|
if InSeconds then
|
||||||
|
return sunrise
|
||||||
|
else
|
||||||
|
return UTILS.SecondsToClock(sunrise, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get todays sun rise time.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #boolean InSeconds If true, return the sun rise time in seconds.
|
||||||
|
-- @return #string Sunrise time, e.g. "05:41".
|
||||||
|
function COORDINATE:GetSunrise(InSeconds)
|
||||||
|
|
||||||
|
-- Get current day of the year.
|
||||||
|
local DayOfYear=UTILS.GetMissionDayOfYear()
|
||||||
|
|
||||||
|
-- Lat and long at this point.
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
-- GMT time diff.
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
-- Sunrise in seconds of the day.
|
||||||
|
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||||
|
|
||||||
|
local date=UTILS.GetDCSMissionDate()
|
||||||
|
|
||||||
|
-- Debug output.
|
||||||
|
--self:I(string.format("Sun rise at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff))
|
||||||
|
|
||||||
|
if InSeconds then
|
||||||
|
return sunrise
|
||||||
|
else
|
||||||
|
return UTILS.SecondsToClock(sunrise, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get minutes until the next sun rise at this coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param OnlyToday If true, only calculate the sun rise of today. If sun has already risen, the time in negative minutes since sunrise is reported.
|
||||||
|
-- @return #number Minutes to the next sunrise.
|
||||||
|
function COORDINATE:GetMinutesToSunrise(OnlyToday)
|
||||||
|
|
||||||
|
-- Seconds of today
|
||||||
|
local time=UTILS.SecondsOfToday()
|
||||||
|
|
||||||
|
-- Next Sunrise in seconds.
|
||||||
|
local sunrise=nil
|
||||||
|
|
||||||
|
-- Time to sunrise.
|
||||||
|
local delta=nil
|
||||||
|
|
||||||
|
if OnlyToday then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Sunrise of today
|
||||||
|
---
|
||||||
|
|
||||||
|
sunrise=self:GetSunrise(true)
|
||||||
|
|
||||||
|
delta=sunrise-time
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Sunrise of tomorrow
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Tomorrows day of the year.
|
||||||
|
local DayOfYear=UTILS.GetMissionDayOfYear()+1
|
||||||
|
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||||
|
|
||||||
|
delta=sunrise+UTILS.SecondsToMidnight()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return delta/60
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if it is day, i.e. if the sun has risen about the horizon at this coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #string Clock (Optional) Time in format "HH:MM:SS+D", e.g. "05:40:00+3" to check if is day at 5:40 at third day after mission start. Default is to check right now.
|
||||||
|
-- @return #boolean If true, it is day. If false, it is night time.
|
||||||
|
function COORDINATE:IsDay(Clock)
|
||||||
|
|
||||||
|
if Clock then
|
||||||
|
|
||||||
|
local Time=UTILS.ClockToSeconds(Clock)
|
||||||
|
|
||||||
|
local clock=UTILS.Split(Clock, "+")[1]
|
||||||
|
|
||||||
|
-- Tomorrows day of the year.
|
||||||
|
local DayOfYear=UTILS.GetMissionDayOfYear(Time)
|
||||||
|
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||||
|
local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
||||||
|
|
||||||
|
local time=UTILS.ClockToSeconds(clock)
|
||||||
|
|
||||||
|
-- Check if time is between sunrise and sunset.
|
||||||
|
if time>sunrise and time<=sunset then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Todays sun rise in sec.
|
||||||
|
local sunrise=self:GetSunrise(true)
|
||||||
|
|
||||||
|
-- Todays sun set in sec.
|
||||||
|
local sunset=self:GetSunset(true)
|
||||||
|
|
||||||
|
-- Seconds passed since midnight.
|
||||||
|
local time=UTILS.SecondsOfToday()
|
||||||
|
|
||||||
|
-- Check if time is between sunrise and sunset.
|
||||||
|
if time>sunrise and time<=sunset then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if it is night, i.e. if the sun has set below the horizon at this coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #string Clock (Optional) Time in format "HH:MM:SS+D", e.g. "05:40:00+3" to check if is night at 5:40 at third day after mission start. Default is to check right now.
|
||||||
|
-- @return #boolean If true, it is night. If false, it is day time.
|
||||||
|
function COORDINATE:IsNight(Clock)
|
||||||
|
return not self:IsDay(Clock)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get sun set time for a specific date at the coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #number Day The day.
|
||||||
|
-- @param #number Month The month.
|
||||||
|
-- @param #number Year The year.
|
||||||
|
-- @param #boolean InSeconds If true, return the sun rise time in seconds.
|
||||||
|
-- @return #string Sunset time, e.g. "20:41".
|
||||||
|
function COORDINATE:GetSunsetAtDate(Day, Month, Year, InSeconds)
|
||||||
|
|
||||||
|
-- Day of the year.
|
||||||
|
local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day)
|
||||||
|
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
||||||
|
|
||||||
|
if InSeconds then
|
||||||
|
return sunset
|
||||||
|
else
|
||||||
|
return UTILS.SecondsToClock(sunset, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get todays sun set time.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #boolean InSeconds If true, return the sun set time in seconds.
|
||||||
|
-- @return #string Sunrise time, e.g. "20:41".
|
||||||
|
function COORDINATE:GetSunset(InSeconds)
|
||||||
|
|
||||||
|
-- Get current day of the year.
|
||||||
|
local DayOfYear=UTILS.GetMissionDayOfYear()
|
||||||
|
|
||||||
|
-- Lat and long at this point.
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
-- GMT time diff.
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
-- Sunrise in seconds of the day.
|
||||||
|
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
||||||
|
|
||||||
|
local date=UTILS.GetDCSMissionDate()
|
||||||
|
|
||||||
|
-- Debug output.
|
||||||
|
--self:I(string.format("Sun set at lat=%.3f long=%.3f on %s (DayOfYear=%d): %s (%d sec of the day) (GMT %d)", Latitude, Longitude, date, DayOfYear, tostring(UTILS.SecondsToClock(sunrise)), sunrise, Tdiff))
|
||||||
|
|
||||||
|
if InSeconds then
|
||||||
|
return sunrise
|
||||||
|
else
|
||||||
|
return UTILS.SecondsToClock(sunrise, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get minutes until the next sun set at this coordinate.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param OnlyToday If true, only calculate the sun set of today. If sun has already set, the time in negative minutes since sunset is reported.
|
||||||
|
-- @return #number Minutes to the next sunrise.
|
||||||
|
function COORDINATE:GetMinutesToSunset(OnlyToday)
|
||||||
|
|
||||||
|
-- Seconds of today
|
||||||
|
local time=UTILS.SecondsOfToday()
|
||||||
|
|
||||||
|
-- Next Sunset in seconds.
|
||||||
|
local sunset=nil
|
||||||
|
|
||||||
|
-- Time to sunrise.
|
||||||
|
local delta=nil
|
||||||
|
|
||||||
|
if OnlyToday then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Sunset of today
|
||||||
|
---
|
||||||
|
|
||||||
|
sunset=self:GetSunset(true)
|
||||||
|
|
||||||
|
delta=sunset-time
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Sunset of tomorrow
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Tomorrows day of the year.
|
||||||
|
local DayOfYear=UTILS.GetMissionDayOfYear()+1
|
||||||
|
|
||||||
|
local Latitude, Longitude=self:GetLLDDM()
|
||||||
|
|
||||||
|
local Tdiff=UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
||||||
|
|
||||||
|
delta=sunset+UTILS.SecondsToMidnight()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return delta/60
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return a BR string from a COORDINATE to the COORDINATE.
|
--- Return a BR string from a COORDINATE to the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
@@ -2036,6 +2449,14 @@ do -- COORDINATE
|
|||||||
return ""
|
return ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get Latitude and Longitude in Degrees Decimal Minutes (DDM).
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @return #number Latitude in DDM.
|
||||||
|
-- @return #number Lontitude in DDM.
|
||||||
|
function COORDINATE:GetLLDDM()
|
||||||
|
return coord.LOtoLL( self:GetVec3() )
|
||||||
|
end
|
||||||
|
|
||||||
--- Provides a Lat Lon string in Degree Minute Second format.
|
--- Provides a Lat Lon string in Degree Minute Second format.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ BEACON = {
|
|||||||
-- @field #number VOR
|
-- @field #number VOR
|
||||||
-- @field #number DME
|
-- @field #number DME
|
||||||
-- @field #number VOR_DME
|
-- @field #number VOR_DME
|
||||||
-- @field #number TACAN
|
-- @field #number TACAN TACtical Air Navigation system.
|
||||||
-- @field #number VORTAC
|
-- @field #number VORTAC
|
||||||
-- @field #number RSBN
|
-- @field #number RSBN
|
||||||
-- @field #number BROADCAST_STATION
|
-- @field #number BROADCAST_STATION
|
||||||
@@ -440,8 +440,12 @@ BEACON = {
|
|||||||
-- @field #number ILS_NEAR_HOMER
|
-- @field #number ILS_NEAR_HOMER
|
||||||
-- @field #number ILS_LOCALIZER
|
-- @field #number ILS_LOCALIZER
|
||||||
-- @field #number ILS_GLIDESLOPE
|
-- @field #number ILS_GLIDESLOPE
|
||||||
|
-- @field #number PRMG_LOCALIZER
|
||||||
|
-- @field #number PRMG_GLIDESLOPE
|
||||||
|
-- @field #number ICLS Same as ICLS glideslope.
|
||||||
|
-- @field #number ICLS_LOCALIZER
|
||||||
|
-- @field #number ICLS_GLIDESLOPE
|
||||||
-- @field #number NAUTICAL_HOMER
|
-- @field #number NAUTICAL_HOMER
|
||||||
-- @field #number ICLS
|
|
||||||
BEACON.Type={
|
BEACON.Type={
|
||||||
NULL = 0,
|
NULL = 0,
|
||||||
VOR = 1,
|
VOR = 1,
|
||||||
@@ -449,36 +453,61 @@ BEACON.Type={
|
|||||||
VOR_DME = 3,
|
VOR_DME = 3,
|
||||||
TACAN = 4,
|
TACAN = 4,
|
||||||
VORTAC = 5,
|
VORTAC = 5,
|
||||||
RSBN = 32,
|
RSBN = 128,
|
||||||
BROADCAST_STATION = 1024,
|
BROADCAST_STATION = 1024,
|
||||||
HOMER = 8,
|
HOMER = 8,
|
||||||
AIRPORT_HOMER = 4104,
|
AIRPORT_HOMER = 4104,
|
||||||
AIRPORT_HOMER_WITH_MARKER = 4136,
|
AIRPORT_HOMER_WITH_MARKER = 4136,
|
||||||
ILS_FAR_HOMER = 16408,
|
ILS_FAR_HOMER = 16408,
|
||||||
ILS_NEAR_HOMER = 16456,
|
ILS_NEAR_HOMER = 16424,
|
||||||
ILS_LOCALIZER = 16640,
|
ILS_LOCALIZER = 16640,
|
||||||
ILS_GLIDESLOPE = 16896,
|
ILS_GLIDESLOPE = 16896,
|
||||||
NAUTICAL_HOMER = 32776,
|
PRMG_LOCALIZER = 33024,
|
||||||
ICLS = 131584,
|
PRMG_GLIDESLOPE = 33280,
|
||||||
|
ICLS = 131584, --leaving this in here but it is the same as ICLS_GLIDESLOPE
|
||||||
|
ICLS_LOCALIZER = 131328,
|
||||||
|
ICLS_GLIDESLOPE = 131584,
|
||||||
|
NAUTICAL_HOMER = 65536,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Beacon systems supported by DCS. https://wiki.hoggitworld.com/view/DCS_command_activateBeacon
|
--- Beacon systems supported by DCS. https://wiki.hoggitworld.com/view/DCS_command_activateBeacon
|
||||||
-- @type BEACON.System
|
-- @type BEACON.System
|
||||||
-- @field #number PAR_10
|
-- @field #number PAR_10 ?
|
||||||
-- @field #number RSBN_5
|
-- @field #number RSBN_5 Russian VOR/DME system.
|
||||||
-- @field #number TACAN
|
-- @field #number TACAN TACtical Air Navigation system on ground.
|
||||||
-- @field #number TACAN_TANKER
|
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
||||||
-- @field #number ILS_LOCALIZER (This is the one to be used for AA TACAN Tanker!)
|
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
||||||
-- @field #number ILS_GLIDESLOPE
|
-- @field #number VOR Very High Frequency Omni-Directional Range
|
||||||
-- @field #number BROADCAST_STATION
|
-- @field #number ILS_LOCALIZER ILS localizer
|
||||||
|
-- @field #number ILS_GLIDESLOPE ILS glideslope.
|
||||||
|
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
||||||
|
-- @field #number PRGM_GLIDESLOPE PRGM glideslope.
|
||||||
|
-- @field #number BROADCAST_STATION Broadcast station.
|
||||||
|
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
||||||
|
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
||||||
|
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
|
||||||
|
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
|
||||||
|
-- @field #number ICLS_LOCALIZER Carrier landing system.
|
||||||
|
-- @field #number ICLS_GLIDESLOPE Carrier landing system.
|
||||||
BEACON.System={
|
BEACON.System={
|
||||||
PAR_10 = 1,
|
PAR_10 = 1,
|
||||||
RSBN_5 = 2,
|
RSBN_5 = 2,
|
||||||
TACAN = 3,
|
TACAN = 3,
|
||||||
TACAN_TANKER = 4,
|
TACAN_TANKER_X = 4,
|
||||||
ILS_LOCALIZER = 5,
|
TACAN_TANKER_Y = 5,
|
||||||
ILS_GLIDESLOPE = 6,
|
VOR = 6,
|
||||||
BROADCAST_STATION = 7,
|
ILS_LOCALIZER = 7,
|
||||||
|
ILS_GLIDESLOPE = 8,
|
||||||
|
PRMG_LOCALIZER = 9,
|
||||||
|
PRMG_GLIDESLOPE = 10,
|
||||||
|
BROADCAST_STATION = 11,
|
||||||
|
VORTAC = 12,
|
||||||
|
TACAN_AA_MODE_X = 13,
|
||||||
|
TACAN_AA_MODE_Y = 14,
|
||||||
|
VORDME = 15,
|
||||||
|
ICLS_LOCALIZER = 16,
|
||||||
|
ICLS_GLIDESLOPE = 17,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.ActivateTACAN} etc.
|
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.ActivateTACAN} etc.
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
--
|
--
|
||||||
-- @type RADIOQUEUE
|
-- @type RADIOQUEUE
|
||||||
-- @field #string ClassName Name of the class "RADIOQUEUE".
|
-- @field #string ClassName Name of the class "RADIOQUEUE".
|
||||||
-- @field #boolean Debug Debug mode. More info.
|
-- @field #boolean Debugmode Debug mode. More info.
|
||||||
-- @field #string lid ID for dcs.log.
|
-- @field #string lid ID for dcs.log.
|
||||||
-- @field #number frequency The radio frequency in Hz.
|
-- @field #number frequency The radio frequency in Hz.
|
||||||
-- @field #number modulation The radio modulation. Either radio.modulation.AM or radio.modulation.FM.
|
-- @field #number modulation The radio modulation. Either radio.modulation.AM or radio.modulation.FM.
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
RADIOQUEUE = {
|
RADIOQUEUE = {
|
||||||
ClassName = "RADIOQUEUE",
|
ClassName = "RADIOQUEUE",
|
||||||
Debug = nil,
|
Debugmode = nil,
|
||||||
lid = nil,
|
lid = nil,
|
||||||
frequency = nil,
|
frequency = nil,
|
||||||
modulation = nil,
|
modulation = nil,
|
||||||
@@ -55,7 +55,7 @@ RADIOQUEUE = {
|
|||||||
power = nil,
|
power = nil,
|
||||||
numbers = {},
|
numbers = {},
|
||||||
checking = nil,
|
checking = nil,
|
||||||
schedonce = nil,
|
schedonce = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Radio queue transmission data.
|
--- Radio queue transmission data.
|
||||||
@@ -375,8 +375,10 @@ function RADIOQUEUE:Broadcast(transmission)
|
|||||||
sender:SetCommand(commandTransmit)
|
sender:SetCommand(commandTransmit)
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
|
if self.Debugmode then
|
||||||
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
||||||
MESSAGE:New(text, 2, "RADIOQUEUE "..self.alias):ToAllIf(self.Debug)
|
MESSAGE:New(text, 2, "RADIOQUEUE "..self.alias):ToAll()
|
||||||
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -388,10 +390,7 @@ function RADIOQUEUE:Broadcast(transmission)
|
|||||||
|
|
||||||
-- Try to get positon from sender unit/static.
|
-- Try to get positon from sender unit/static.
|
||||||
if self.sendername then
|
if self.sendername then
|
||||||
local coord=self:_GetRadioSenderCoord()
|
vec3=self:_GetRadioSenderCoord()
|
||||||
if coord then
|
|
||||||
vec3=coord:GetVec3()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Try to get fixed positon.
|
-- Try to get fixed positon.
|
||||||
@@ -408,8 +407,10 @@ function RADIOQUEUE:Broadcast(transmission)
|
|||||||
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
|
if self.Debugmode then
|
||||||
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
local text=string.format("file=%s, freq=%.2f MHz, duration=%.2f sec, subtitle=%s", filename, self.frequency/1000000, transmission.duration, transmission.subtitle or "")
|
||||||
MESSAGE:New(string.format(text, filename, transmission.duration, transmission.subtitle or ""), 5, "RADIOQUEUE "..self.alias):ToAllIf(self.Debug)
|
MESSAGE:New(string.format(text, filename, transmission.duration, transmission.subtitle or ""), 5, "RADIOQUEUE "..self.alias):ToAll()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -524,7 +525,7 @@ end
|
|||||||
|
|
||||||
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
|
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
|
||||||
-- @param #RADIOQUEUE self
|
-- @param #RADIOQUEUE self
|
||||||
-- @return Wrapper.Unit#UNIT Sending aircraft unit or nil if was not setup, is not an aircraft or is not alive.
|
-- @return Wrapper.Unit#UNIT Sending unit or nil if was not setup, is not an aircraft or ground unit or is not alive.
|
||||||
function RADIOQUEUE:_GetRadioSender()
|
function RADIOQUEUE:_GetRadioSender()
|
||||||
|
|
||||||
-- Check if we have a sending aircraft.
|
-- Check if we have a sending aircraft.
|
||||||
@@ -532,11 +533,12 @@ function RADIOQUEUE:_GetRadioSender()
|
|||||||
|
|
||||||
-- Try the general default.
|
-- Try the general default.
|
||||||
if self.sendername then
|
if self.sendername then
|
||||||
|
|
||||||
-- First try to find a unit
|
-- First try to find a unit
|
||||||
sender=UNIT:FindByName(self.sendername)
|
sender=UNIT:FindByName(self.sendername)
|
||||||
|
|
||||||
-- Check that sender is alive and an aircraft.
|
-- Check that sender is alive and an aircraft.
|
||||||
if sender and sender:IsAlive() and sender:IsAir() then
|
if sender and sender:IsAlive() and (sender:IsAir() or sender:IsGround()) then
|
||||||
return sender
|
return sender
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -547,7 +549,7 @@ end
|
|||||||
|
|
||||||
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
|
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
|
||||||
-- @param #RADIOQUEUE self
|
-- @param #RADIOQUEUE self
|
||||||
-- @return Core.Point#COORDINATE Coordinate of the sender unit.
|
-- @return DCS#Vec3 Vector 3D.
|
||||||
function RADIOQUEUE:_GetRadioSenderCoord()
|
function RADIOQUEUE:_GetRadioSenderCoord()
|
||||||
|
|
||||||
local vec3=nil
|
local vec3=nil
|
||||||
@@ -560,7 +562,7 @@ function RADIOQUEUE:_GetRadioSenderCoord()
|
|||||||
|
|
||||||
-- Check that sender is alive and an aircraft.
|
-- Check that sender is alive and an aircraft.
|
||||||
if sender and sender:IsAlive() then
|
if sender and sender:IsAlive() then
|
||||||
return sender:GetCoordinate()
|
return sender:GetVec3()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Now try a static.
|
-- Now try a static.
|
||||||
@@ -568,7 +570,7 @@ function RADIOQUEUE:_GetRadioSenderCoord()
|
|||||||
|
|
||||||
-- Check that sender is alive and an aircraft.
|
-- Check that sender is alive and an aircraft.
|
||||||
if sender then
|
if sender then
|
||||||
return sender:GetCoordinate()
|
return sender:GetVec3()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions: **funkyfranky**
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -48,9 +48,10 @@
|
|||||||
do -- SET_BASE
|
do -- SET_BASE
|
||||||
|
|
||||||
--- @type SET_BASE
|
--- @type SET_BASE
|
||||||
-- @field #table Filter
|
-- @field #table Filter Table of filters.
|
||||||
-- @field #table Set
|
-- @field #table Set Table of objects.
|
||||||
-- @field #table List
|
-- @field #table Index Table of indicies.
|
||||||
|
-- @field #table List Unused table.
|
||||||
-- @field Core.Scheduler#SCHEDULER CallScheduler
|
-- @field Core.Scheduler#SCHEDULER CallScheduler
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
@@ -77,6 +78,10 @@ do -- SET_BASE
|
|||||||
Set = {},
|
Set = {},
|
||||||
List = {},
|
List = {},
|
||||||
Index = {},
|
Index = {},
|
||||||
|
Database = nil,
|
||||||
|
CallScheduler=nil,
|
||||||
|
TimeInterval=nil,
|
||||||
|
YieldInterval=nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -224,8 +229,8 @@ do -- SET_BASE
|
|||||||
|
|
||||||
--- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using a given ObjectName as the index.
|
--- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using a given ObjectName as the index.
|
||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @param #string ObjectName
|
-- @param #string ObjectName The name of the object.
|
||||||
-- @param Core.Base#BASE Object
|
-- @param Core.Base#BASE Object The object itself.
|
||||||
-- @return Core.Base#BASE The added BASE Object.
|
-- @return Core.Base#BASE The added BASE Object.
|
||||||
function SET_BASE:Add( ObjectName, Object )
|
function SET_BASE:Add( ObjectName, Object )
|
||||||
self:F2( { ObjectName = ObjectName, Object = Object } )
|
self:F2( { ObjectName = ObjectName, Object = Object } )
|
||||||
@@ -234,9 +239,14 @@ do -- SET_BASE
|
|||||||
if self.Set[ObjectName] then
|
if self.Set[ObjectName] then
|
||||||
self:Remove( ObjectName, true )
|
self:Remove( ObjectName, true )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Add object to set.
|
||||||
self.Set[ObjectName] = Object
|
self.Set[ObjectName] = Object
|
||||||
|
|
||||||
|
-- Add Object name to Index.
|
||||||
table.insert( self.Index, ObjectName )
|
table.insert( self.Index, ObjectName )
|
||||||
|
|
||||||
|
-- Trigger Added event.
|
||||||
self:Added( ObjectName, Object )
|
self:Added( ObjectName, Object )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -254,6 +264,81 @@ do -- SET_BASE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the *union* of two sets.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param Core.Set#SET_BASE SetB Set *B*.
|
||||||
|
-- @return Core.Set#SET_BASE The union set, i.e. contains objects that are in set *A* **or** in set *B*.
|
||||||
|
function SET_BASE:GetSetUnion(SetB)
|
||||||
|
|
||||||
|
local union=SET_BASE:New()
|
||||||
|
|
||||||
|
for _,ObjectA in pairs(self.Set) do
|
||||||
|
union:AddObject(ObjectA)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _,ObjectB in pairs(SetB.Set) do
|
||||||
|
union:AddObject(ObjectB)
|
||||||
|
end
|
||||||
|
|
||||||
|
return union
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the *intersection* of this set, called *A*, and another set.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param Core.Set#SET_BASE SetB Set other set, called *B*.
|
||||||
|
-- @return Core.Set#SET_BASE A set of objects that is included in set *A* **and** in set *B*.
|
||||||
|
function SET_BASE:GetSetIntersection(SetB)
|
||||||
|
|
||||||
|
local intersection=SET_BASE:New()
|
||||||
|
|
||||||
|
local union=self:GetSetUnion(SetB)
|
||||||
|
|
||||||
|
for _,Object in pairs(union.Set) do
|
||||||
|
if self:IsIncludeObject(Object) and SetB:IsIncludeObject(Object) then
|
||||||
|
intersection:AddObject(intersection)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return intersection
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the *complement* of two sets.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param Core.Set#SET_BASE SetB Set other set, called *B*.
|
||||||
|
-- @return Core.Set#SET_BASE The set of objects that are in set *B* but **not** in this set *A*.
|
||||||
|
function SET_BASE:GetSetComplement(SetB)
|
||||||
|
|
||||||
|
local complement=SET_BASE:New()
|
||||||
|
|
||||||
|
local union=self:GetSetUnion(SetA, SetB)
|
||||||
|
|
||||||
|
for _,Object in pairs(union.Set) do
|
||||||
|
if SetA:IsIncludeObject(Object) and SetB:IsIncludeObject(Object) then
|
||||||
|
intersection:Add(intersection)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return intersection
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Compare two sets.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param Core.Set#SET_BASE SetA First set.
|
||||||
|
-- @param Core.Set#SET_BASE SetB Set to be merged into first set.
|
||||||
|
-- @return Core.Set#SET_BASE The set of objects that are included in SetA and SetB.
|
||||||
|
function SET_BASE:CompareSets(SetA, SetB)
|
||||||
|
|
||||||
|
for _,ObjectB in pairs(SetB.Set) do
|
||||||
|
if SetA:IsIncludeObject(ObjectB) then
|
||||||
|
SetA:Add(ObjectB)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return SetA
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Gets a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name.
|
--- Gets a @{Core.Base#BASE} object from the @{Core.Set#SET_BASE} and derived classes, based on the Object Name.
|
||||||
@@ -712,7 +797,7 @@ do -- SET_BASE
|
|||||||
--end
|
--end
|
||||||
|
|
||||||
|
|
||||||
--- Decides whether to include the Object
|
--- Decides whether to include the Object.
|
||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @param #table Object
|
-- @param #table Object
|
||||||
-- @return #SET_BASE self
|
-- @return #SET_BASE self
|
||||||
@@ -722,6 +807,16 @@ do -- SET_BASE
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Decides whether to include the Object.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param #table Object
|
||||||
|
-- @return #SET_BASE self
|
||||||
|
function SET_BASE:IsInSet(ObjectName)
|
||||||
|
self:F3( Object )
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
--- Gets a string with all the object names.
|
--- Gets a string with all the object names.
|
||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @return #string A string with the names of the objects.
|
-- @return #string A string with the names of the objects.
|
||||||
@@ -785,8 +880,8 @@ do -- SET_GROUP
|
|||||||
--
|
--
|
||||||
-- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s).
|
-- * @{#SET_GROUP.FilterCoalitions}: Builds the SET_GROUP with the groups belonging to the coalition(s).
|
||||||
-- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies).
|
-- * @{#SET_GROUP.FilterCategories}: Builds the SET_GROUP with the groups belonging to the category(ies).
|
||||||
-- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the gruops belonging to the country(ies).
|
-- * @{#SET_GROUP.FilterCountries}: Builds the SET_GROUP with the groups belonging to the country(ies).
|
||||||
-- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups starting with the same prefix string(s).
|
-- * @{#SET_GROUP.FilterPrefixes}: Builds the SET_GROUP with the groups *containing* the given string in the group name. **Attention!** Bad naming convention, as this not really filtering *prefixes*.
|
||||||
-- * @{#SET_GROUP.FilterActive}: Builds the SET_GROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set!
|
-- * @{#SET_GROUP.FilterActive}: Builds the SET_GROUP with the groups that are only active. Groups that are inactive (late activation) won't be included in the set!
|
||||||
--
|
--
|
||||||
-- For the Category Filter, extra methods have been added:
|
-- For the Category Filter, extra methods have been added:
|
||||||
@@ -965,7 +1060,7 @@ do -- SET_GROUP
|
|||||||
-- Note that for each unit in the group that is set, a default cargo bay limit is initialized.
|
-- Note that for each unit in the group that is set, a default cargo bay limit is initialized.
|
||||||
-- @param Core.Set#SET_GROUP self
|
-- @param Core.Set#SET_GROUP self
|
||||||
-- @param Wrapper.Group#GROUP group The group which should be added to the set.
|
-- @param Wrapper.Group#GROUP group The group which should be added to the set.
|
||||||
-- @return self
|
-- @return Core.Set#SET_GROUP self
|
||||||
function SET_GROUP:AddGroup( group )
|
function SET_GROUP:AddGroup( group )
|
||||||
|
|
||||||
self:Add( group:GetName(), group )
|
self:Add( group:GetName(), group )
|
||||||
@@ -981,7 +1076,7 @@ do -- SET_GROUP
|
|||||||
--- Add GROUP(s) to SET_GROUP.
|
--- Add GROUP(s) to SET_GROUP.
|
||||||
-- @param Core.Set#SET_GROUP self
|
-- @param Core.Set#SET_GROUP self
|
||||||
-- @param #string AddGroupNames A single name or an array of GROUP names.
|
-- @param #string AddGroupNames A single name or an array of GROUP names.
|
||||||
-- @return self
|
-- @return Core.Set#SET_GROUP self
|
||||||
function SET_GROUP:AddGroupsByName( AddGroupNames )
|
function SET_GROUP:AddGroupsByName( AddGroupNames )
|
||||||
|
|
||||||
local AddGroupNamesArray = ( type( AddGroupNames ) == "table" ) and AddGroupNames or { AddGroupNames }
|
local AddGroupNamesArray = ( type( AddGroupNames ) == "table" ) and AddGroupNames or { AddGroupNames }
|
||||||
@@ -996,7 +1091,7 @@ do -- SET_GROUP
|
|||||||
--- Remove GROUP(s) from SET_GROUP.
|
--- Remove GROUP(s) from SET_GROUP.
|
||||||
-- @param Core.Set#SET_GROUP self
|
-- @param Core.Set#SET_GROUP self
|
||||||
-- @param Wrapper.Group#GROUP RemoveGroupNames A single name or an array of GROUP names.
|
-- @param Wrapper.Group#GROUP RemoveGroupNames A single name or an array of GROUP names.
|
||||||
-- @return self
|
-- @return Core.Set#SET_GROUP self
|
||||||
function SET_GROUP:RemoveGroupsByName( RemoveGroupNames )
|
function SET_GROUP:RemoveGroupsByName( RemoveGroupNames )
|
||||||
|
|
||||||
local RemoveGroupNamesArray = ( type( RemoveGroupNames ) == "table" ) and RemoveGroupNames or { RemoveGroupNames }
|
local RemoveGroupNamesArray = ( type( RemoveGroupNames ) == "table" ) and RemoveGroupNames or { RemoveGroupNames }
|
||||||
@@ -1146,10 +1241,10 @@ do -- SET_GROUP
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of groups of defined GROUP prefixes.
|
--- Builds a set of groups that contain the given string in their group name.
|
||||||
-- All the groups starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all groups that **contain** the string.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param #string Prefixes The prefix of which the group name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the group name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_GROUP self
|
-- @return #SET_GROUP self
|
||||||
function SET_GROUP:FilterPrefixes( Prefixes )
|
function SET_GROUP:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.GroupPrefixes then
|
if not self.Filter.GroupPrefixes then
|
||||||
@@ -1748,7 +1843,7 @@ do -- SET_UNIT
|
|||||||
-- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies).
|
-- * @{#SET_UNIT.FilterCategories}: Builds the SET_UNIT with the units belonging to the category(ies).
|
||||||
-- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s).
|
-- * @{#SET_UNIT.FilterTypes}: Builds the SET_UNIT with the units belonging to the unit type(s).
|
||||||
-- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies).
|
-- * @{#SET_UNIT.FilterCountries}: Builds the SET_UNIT with the units belonging to the country(ies).
|
||||||
-- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units starting with the same prefix string(s).
|
-- * @{#SET_UNIT.FilterPrefixes}: Builds the SET_UNIT with the units sharing the same string(s) in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
-- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
-- * @{#SET_UNIT.FilterActive}: Builds the SET_UNIT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_UNIT, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_UNIT, you can start filtering using:
|
||||||
@@ -1909,8 +2004,8 @@ do -- SET_UNIT
|
|||||||
|
|
||||||
--- Remove UNIT(s) from SET_UNIT.
|
--- Remove UNIT(s) from SET_UNIT.
|
||||||
-- @param Core.Set#SET_UNIT self
|
-- @param Core.Set#SET_UNIT self
|
||||||
-- @param Wrapper.Unit#UNIT RemoveUnitNames A single name or an array of UNIT names.
|
-- @param #table RemoveUnitNames A single name or an array of UNIT names.
|
||||||
-- @return self
|
-- @return Core.Set#SET_UNIT self
|
||||||
function SET_UNIT:RemoveUnitsByName( RemoveUnitNames )
|
function SET_UNIT:RemoveUnitsByName( RemoveUnitNames )
|
||||||
|
|
||||||
local RemoveUnitNamesArray = ( type( RemoveUnitNames ) == "table" ) and RemoveUnitNames or { RemoveUnitNames }
|
local RemoveUnitNamesArray = ( type( RemoveUnitNames ) == "table" ) and RemoveUnitNames or { RemoveUnitNames }
|
||||||
@@ -2010,10 +2105,10 @@ do -- SET_UNIT
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of units of defined unit prefixes.
|
--- Builds a set of UNITs that contain a given string in their unit name.
|
||||||
-- All the units starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all units that **contain** the string.
|
||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
-- @param #string Prefixes The prefix of which the unit name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_UNIT self
|
-- @return #SET_UNIT self
|
||||||
function SET_UNIT:FilterPrefixes( Prefixes )
|
function SET_UNIT:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.UnitPrefixes then
|
if not self.Filter.UnitPrefixes then
|
||||||
@@ -2080,7 +2175,23 @@ do -- SET_UNIT
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Iterate the SET_UNIT and count how many UNITs are alive.
|
||||||
|
-- @param #SET_UNIT self
|
||||||
|
-- @return #number The number of UNITs alive.
|
||||||
|
function SET_UNIT: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
|
||||||
|
|
||||||
--- Starts the filtering.
|
--- Starts the filtering.
|
||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
@@ -2852,7 +2963,7 @@ do -- SET_STATIC
|
|||||||
-- * @{#SET_STATIC.FilterCategories}: Builds the SET_STATIC with the units belonging to the category(ies).
|
-- * @{#SET_STATIC.FilterCategories}: Builds the SET_STATIC with the units belonging to the category(ies).
|
||||||
-- * @{#SET_STATIC.FilterTypes}: Builds the SET_STATIC with the units belonging to the unit type(s).
|
-- * @{#SET_STATIC.FilterTypes}: Builds the SET_STATIC with the units belonging to the unit type(s).
|
||||||
-- * @{#SET_STATIC.FilterCountries}: Builds the SET_STATIC with the units belonging to the country(ies).
|
-- * @{#SET_STATIC.FilterCountries}: Builds the SET_STATIC with the units belonging to the country(ies).
|
||||||
-- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units starting with the same prefix string(s).
|
-- * @{#SET_STATIC.FilterPrefixes}: Builds the SET_STATIC with the units containing the same string(s) in their name. **ATTENTION** bad naming convention as this *does not** only filter *prefixes*.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_STATIC, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_STATIC, you can start filtering using:
|
||||||
--
|
--
|
||||||
@@ -3065,10 +3176,10 @@ do -- SET_STATIC
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of units of defined unit prefixes.
|
--- Builds a set of STATICs that contain the given string in their name.
|
||||||
-- All the units starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all statics that **contain** the string.
|
||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
-- @param #string Prefixes The prefix of which the unit name starts with.
|
-- @param #string Prefixes The string pattern(s) that need to be contained in the static name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_STATIC self
|
-- @return #SET_STATIC self
|
||||||
function SET_STATIC:FilterPrefixes( Prefixes )
|
function SET_STATIC:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.StaticPrefixes then
|
if not self.Filter.StaticPrefixes then
|
||||||
@@ -3099,6 +3210,24 @@ do -- SET_STATIC
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Iterate the SET_STATIC and count how many STATICSs are alive.
|
||||||
|
-- @param #SET_STATIC self
|
||||||
|
-- @return #number The number of UNITs alive.
|
||||||
|
function SET_STATIC:CountAlive()
|
||||||
|
|
||||||
|
local Set = self:GetSet()
|
||||||
|
|
||||||
|
local CountU = 0
|
||||||
|
for UnitID, UnitData in pairs(Set) do
|
||||||
|
if UnitData and UnitData:IsAlive() then
|
||||||
|
CountU = CountU + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return CountU
|
||||||
|
end
|
||||||
|
|
||||||
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
||||||
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
@@ -3109,13 +3238,13 @@ do -- SET_STATIC
|
|||||||
self:F3( { Event } )
|
self:F3( { Event } )
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||||
if not self.Database[Event.IniDCSStaticName] then
|
if not self.Database[Event.IniDCSUnitName] then
|
||||||
self.Database[Event.IniDCSStaticName] = STATIC:Register( Event.IniDCSStaticName )
|
self.Database[Event.IniDCSUnitName] = STATIC:Register( Event.IniDCSUnitName )
|
||||||
self:T3( self.Database[Event.IniDCSStaticName] )
|
self:T3( self.Database[Event.IniDCSUnitName] )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return Event.IniDCSStaticName, self.Database[Event.IniDCSStaticName]
|
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Handles the Database to check on any event that Object exists in the Database.
|
--- Handles the Database to check on any event that Object exists in the Database.
|
||||||
@@ -3125,10 +3254,10 @@ do -- SET_STATIC
|
|||||||
-- @return #string The name of the STATIC
|
-- @return #string The name of the STATIC
|
||||||
-- @return #table The STATIC
|
-- @return #table The STATIC
|
||||||
function SET_STATIC:FindInDatabase( Event )
|
function SET_STATIC:FindInDatabase( Event )
|
||||||
self:F2( { Event.IniDCSStaticName, self.Set[Event.IniDCSStaticName], Event } )
|
self:F2( { Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName], Event } )
|
||||||
|
|
||||||
|
|
||||||
return Event.IniDCSStaticName, self.Set[Event.IniDCSStaticName]
|
return Event.IniDCSUnitName, self.Set[Event.IniDCSUnitName]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -3546,7 +3675,7 @@ do -- SET_CLIENT
|
|||||||
-- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies).
|
-- * @{#SET_CLIENT.FilterCategories}: Builds the SET_CLIENT with the clients belonging to the category(ies).
|
||||||
-- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s).
|
-- * @{#SET_CLIENT.FilterTypes}: Builds the SET_CLIENT with the clients belonging to the client type(s).
|
||||||
-- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies).
|
-- * @{#SET_CLIENT.FilterCountries}: Builds the SET_CLIENT with the clients belonging to the country(ies).
|
||||||
-- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients starting with the same prefix string(s).
|
-- * @{#SET_CLIENT.FilterPrefixes}: Builds the SET_CLIENT with the clients containing the same string(s) in their unit/pilot name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
-- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
-- * @{#SET_CLIENT.FilterActive}: Builds the SET_CLIENT with the units that are only active. Units that are inactive (late activation) won't be included in the set!
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_CLIENT, you can start filtering using:
|
||||||
@@ -3729,10 +3858,10 @@ do -- SET_CLIENT
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of clients of defined client prefixes.
|
--- Builds a set of CLIENTs that contain the given string in their unit/pilot name.
|
||||||
-- All the clients starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all clients that **contain** the string.
|
||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @param #string Prefixes The prefix of which the client name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit/pilot name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_CLIENT self
|
-- @return #SET_CLIENT self
|
||||||
function SET_CLIENT:FilterPrefixes( Prefixes )
|
function SET_CLIENT:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.ClientPrefixes then
|
if not self.Filter.ClientPrefixes then
|
||||||
@@ -3985,7 +4114,7 @@ do -- SET_PLAYER
|
|||||||
-- * @{#SET_PLAYER.FilterCategories}: Builds the SET_PLAYER with the clients belonging to the category(ies).
|
-- * @{#SET_PLAYER.FilterCategories}: Builds the SET_PLAYER with the clients belonging to the category(ies).
|
||||||
-- * @{#SET_PLAYER.FilterTypes}: Builds the SET_PLAYER with the clients belonging to the client type(s).
|
-- * @{#SET_PLAYER.FilterTypes}: Builds the SET_PLAYER with the clients belonging to the client type(s).
|
||||||
-- * @{#SET_PLAYER.FilterCountries}: Builds the SET_PLAYER with the clients belonging to the country(ies).
|
-- * @{#SET_PLAYER.FilterCountries}: Builds the SET_PLAYER with the clients belonging to the country(ies).
|
||||||
-- * @{#SET_PLAYER.FilterPrefixes}: Builds the SET_PLAYER with the clients starting with the same prefix string(s).
|
-- * @{#SET_PLAYER.FilterPrefixes}: Builds the SET_PLAYER with the clients sharing the same string(s) in their unit/pilot name. **ATTENTION** Bad naming convention as this *does not* only filter prefixes.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_PLAYER, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_PLAYER, you can start filtering using:
|
||||||
--
|
--
|
||||||
@@ -4164,10 +4293,10 @@ do -- SET_PLAYER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of clients of defined client prefixes.
|
--- Builds a set of PLAYERs that contain the given string in their unit/pilot name.
|
||||||
-- All the clients starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all player clients that **contain** the string.
|
||||||
-- @param #SET_PLAYER self
|
-- @param #SET_PLAYER self
|
||||||
-- @param #string Prefixes The prefix of which the client name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the unit/pilot name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_PLAYER self
|
-- @return #SET_PLAYER self
|
||||||
function SET_PLAYER:FilterPrefixes( Prefixes )
|
function SET_PLAYER:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.ClientPrefixes then
|
if not self.Filter.ClientPrefixes then
|
||||||
@@ -4576,7 +4705,8 @@ do -- SET_AIRBASE
|
|||||||
if _DATABASE then
|
if _DATABASE then
|
||||||
|
|
||||||
-- We use the BaseCaptured event, which is generated by DCS when a base got captured.
|
-- We use the BaseCaptured event, which is generated by DCS when a base got captured.
|
||||||
self:HandleEvent( EVENTS.BaseCaptured )
|
self:HandleEvent(EVENTS.BaseCaptured)
|
||||||
|
self:HandleEvent(EVENTS.Dead)
|
||||||
|
|
||||||
-- We initialize the first set.
|
-- We initialize the first set.
|
||||||
for ObjectName, Object in pairs( self.Database ) do
|
for ObjectName, Object in pairs( self.Database ) do
|
||||||
@@ -4591,10 +4721,9 @@ do -- SET_AIRBASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Starts the filtering.
|
--- Base capturing event.
|
||||||
-- @param #SET_AIRBASE self
|
-- @param #SET_AIRBASE self
|
||||||
-- @param Core.Event#EVENT EventData
|
-- @param Core.Event#EVENT EventData
|
||||||
-- @return #SET_AIRBASE self
|
|
||||||
function SET_AIRBASE:OnEventBaseCaptured(EventData)
|
function SET_AIRBASE:OnEventBaseCaptured(EventData)
|
||||||
|
|
||||||
-- When a base got captured, we reevaluate the set.
|
-- When a base got captured, we reevaluate the set.
|
||||||
@@ -4610,24 +4739,36 @@ do -- SET_AIRBASE
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Dead event.
|
||||||
|
-- @param #SET_AIRBASE self
|
||||||
|
-- @param Core.Event#EVENT EventData
|
||||||
|
function SET_AIRBASE:OnEventDead(EventData)
|
||||||
|
|
||||||
|
local airbaseName, airbase=self:FindInDatabase(EventData)
|
||||||
|
|
||||||
|
if airbase and airbase:IsShip() or airbase:IsHelipad() then
|
||||||
|
self:RemoveAirbasesByName(airbaseName)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
||||||
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
||||||
-- @param #SET_AIRBASE self
|
-- @param #SET_AIRBASE self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event Event data.
|
||||||
-- @return #string The name of the AIRBASE
|
-- @return #string The name of the AIRBASE.
|
||||||
-- @return #table The AIRBASE
|
-- @return Wrapper.Airbase#AIRBASE The AIRBASE object.
|
||||||
function SET_AIRBASE:AddInDatabase( Event )
|
function SET_AIRBASE:AddInDatabase( Event )
|
||||||
self:F3( { Event } )
|
|
||||||
|
|
||||||
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Handles the Database to check on any event that Object exists in the Database.
|
--- Handles the Database to check on any event that Object exists in the Database.
|
||||||
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
|
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
|
||||||
-- @param #SET_AIRBASE self
|
-- @param #SET_AIRBASE self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event Event data.
|
||||||
-- @return #string The name of the AIRBASE
|
-- @return #string The name of the AIRBASE.
|
||||||
-- @return #table The AIRBASE
|
-- @return Wrapper.Airbase#AIRBASE The AIRBASE object.
|
||||||
function SET_AIRBASE:FindInDatabase( Event )
|
function SET_AIRBASE:FindInDatabase( Event )
|
||||||
self:F3( { Event } )
|
self:F3( { Event } )
|
||||||
|
|
||||||
@@ -4733,7 +4874,7 @@ do -- SET_CARGO
|
|||||||
-- Filter criteria are defined by:
|
-- Filter criteria are defined by:
|
||||||
--
|
--
|
||||||
-- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s).
|
-- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s).
|
||||||
-- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the prefix string(s).
|
-- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the same string(s). **ATTENTION** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
-- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s).
|
-- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s).
|
||||||
-- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies).
|
-- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies).
|
||||||
--
|
--
|
||||||
@@ -4787,7 +4928,7 @@ do -- SET_CARGO
|
|||||||
--- (R2.1) Add CARGO to SET_CARGO.
|
--- (R2.1) Add CARGO to SET_CARGO.
|
||||||
-- @param Core.Set#SET_CARGO self
|
-- @param Core.Set#SET_CARGO self
|
||||||
-- @param Cargo.Cargo#CARGO Cargo A single cargo.
|
-- @param Cargo.Cargo#CARGO Cargo A single cargo.
|
||||||
-- @return self
|
-- @return Core.Set#SET_CARGO self
|
||||||
function SET_CARGO:AddCargo( Cargo ) --R2.4
|
function SET_CARGO:AddCargo( Cargo ) --R2.4
|
||||||
|
|
||||||
self:Add( Cargo:GetName(), Cargo )
|
self:Add( Cargo:GetName(), Cargo )
|
||||||
@@ -4799,7 +4940,7 @@ do -- SET_CARGO
|
|||||||
--- (R2.1) Add CARGOs to SET_CARGO.
|
--- (R2.1) Add CARGOs to SET_CARGO.
|
||||||
-- @param Core.Set#SET_CARGO self
|
-- @param Core.Set#SET_CARGO self
|
||||||
-- @param #string AddCargoNames A single name or an array of CARGO names.
|
-- @param #string AddCargoNames A single name or an array of CARGO names.
|
||||||
-- @return self
|
-- @return Core.Set#SET_CARGO self
|
||||||
function SET_CARGO:AddCargosByName( AddCargoNames ) --R2.1
|
function SET_CARGO:AddCargosByName( AddCargoNames ) --R2.1
|
||||||
|
|
||||||
local AddCargoNamesArray = ( type( AddCargoNames ) == "table" ) and AddCargoNames or { AddCargoNames }
|
local AddCargoNamesArray = ( type( AddCargoNames ) == "table" ) and AddCargoNames or { AddCargoNames }
|
||||||
@@ -4814,7 +4955,7 @@ do -- SET_CARGO
|
|||||||
--- (R2.1) Remove CARGOs from SET_CARGO.
|
--- (R2.1) Remove CARGOs from SET_CARGO.
|
||||||
-- @param Core.Set#SET_CARGO self
|
-- @param Core.Set#SET_CARGO self
|
||||||
-- @param Wrapper.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
|
-- @param Wrapper.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
|
||||||
-- @return self
|
-- @return Core.Set#SET_CARGO self
|
||||||
function SET_CARGO:RemoveCargosByName( RemoveCargoNames ) --R2.1
|
function SET_CARGO:RemoveCargosByName( RemoveCargoNames ) --R2.1
|
||||||
|
|
||||||
local RemoveCargoNamesArray = ( type( RemoveCargoNames ) == "table" ) and RemoveCargoNames or { RemoveCargoNames }
|
local RemoveCargoNamesArray = ( type( RemoveCargoNames ) == "table" ) and RemoveCargoNames or { RemoveCargoNames }
|
||||||
@@ -4895,10 +5036,10 @@ do -- SET_CARGO
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (R2.1) Builds a set of cargos of defined cargo prefixes.
|
--- Builds a set of CARGOs that contain a given string in their name.
|
||||||
-- All the cargos starting with the given prefixes will be included within the set.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all cargos that **contain** the string.
|
||||||
-- @param #SET_CARGO self
|
-- @param #SET_CARGO self
|
||||||
-- @param #string Prefixes The prefix of which the cargo name starts with.
|
-- @param #string Prefixes The string pattern(s) that need to be in the cargo name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_CARGO self
|
-- @return #SET_CARGO self
|
||||||
function SET_CARGO:FilterPrefixes( Prefixes ) --R2.1
|
function SET_CARGO:FilterPrefixes( Prefixes ) --R2.1
|
||||||
if not self.Filter.CargoPrefixes then
|
if not self.Filter.CargoPrefixes then
|
||||||
@@ -5174,7 +5315,7 @@ do -- SET_ZONE
|
|||||||
-- You can set filter criteria to build the collection of zones in SET_ZONE.
|
-- You can set filter criteria to build the collection of zones in SET_ZONE.
|
||||||
-- Filter criteria are defined by:
|
-- Filter criteria are defined by:
|
||||||
--
|
--
|
||||||
-- * @{#SET_ZONE.FilterPrefixes}: Builds the SET_ZONE with the zones having a certain text pattern of prefix.
|
-- * @{#SET_ZONE.FilterPrefixes}: Builds the SET_ZONE with the zones having a certain text pattern in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_ZONE, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_ZONE, you can start filtering using:
|
||||||
--
|
--
|
||||||
@@ -5270,10 +5411,12 @@ do -- SET_ZONE
|
|||||||
|
|
||||||
--- Get a random zone from the set.
|
--- Get a random zone from the set.
|
||||||
-- @param #SET_ZONE self
|
-- @param #SET_ZONE self
|
||||||
|
-- @param #number margin Number of tries to find a zone
|
||||||
-- @return Core.Zone#ZONE_BASE The random Zone.
|
-- @return Core.Zone#ZONE_BASE The random Zone.
|
||||||
-- @return #nil if no zone in the collection.
|
-- @return #nil if no zone in the collection.
|
||||||
function SET_ZONE:GetRandomZone()
|
function SET_ZONE:GetRandomZone(margin)
|
||||||
|
|
||||||
|
local margin = margin or 100
|
||||||
if self:Count() ~= 0 then
|
if self:Count() ~= 0 then
|
||||||
|
|
||||||
local Index = self.Index
|
local Index = self.Index
|
||||||
@@ -5282,9 +5425,11 @@ do -- SET_ZONE
|
|||||||
-- Loop until a zone has been found.
|
-- Loop until a zone has been found.
|
||||||
-- The :GetZoneMaybe() call will evaluate the probability for the zone to be selected.
|
-- The :GetZoneMaybe() call will evaluate the probability for the zone to be selected.
|
||||||
-- If the zone is not selected, then nil is returned by :GetZoneMaybe() and the loop continues!
|
-- If the zone is not selected, then nil is returned by :GetZoneMaybe() and the loop continues!
|
||||||
while not ZoneFound do
|
local counter = 0
|
||||||
|
while (not ZoneFound) or (counter < margin) do
|
||||||
local ZoneRandom = math.random( 1, #Index )
|
local ZoneRandom = math.random( 1, #Index )
|
||||||
ZoneFound = self.Set[Index[ZoneRandom]]:GetZoneMaybe()
|
ZoneFound = self.Set[Index[ZoneRandom]]:GetZoneMaybe()
|
||||||
|
counter = counter + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
return ZoneFound
|
return ZoneFound
|
||||||
@@ -5305,10 +5450,10 @@ do -- SET_ZONE
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of zones of defined zone prefixes.
|
--- Builds a set of ZONEs that contain the given string in their name.
|
||||||
-- All the zones starting with the given prefixes will be included within the set.
|
-- **ATTENTION!** Bad naming convention as this **does not** filter only **prefixes** but all zones that **contain** the string.
|
||||||
-- @param #SET_ZONE self
|
-- @param #SET_ZONE self
|
||||||
-- @param #string Prefixes The prefix of which the zone name starts with.
|
-- @param #string Prefixes The string pattern(s) that need to be contained in the zone name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_ZONE self
|
-- @return #SET_ZONE self
|
||||||
function SET_ZONE:FilterPrefixes( Prefixes )
|
function SET_ZONE:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.Prefixes then
|
if not self.Filter.Prefixes then
|
||||||
@@ -5507,7 +5652,7 @@ do -- SET_ZONE_GOAL
|
|||||||
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
|
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
|
||||||
-- Filter criteria are defined by:
|
-- Filter criteria are defined by:
|
||||||
--
|
--
|
||||||
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern of prefix.
|
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern in their name. **ATTENTION!** Bad naming convention as this *does not* only filter *prefixes*.
|
||||||
--
|
--
|
||||||
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
|
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
|
||||||
--
|
--
|
||||||
@@ -5623,10 +5768,10 @@ do -- SET_ZONE_GOAL
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of zones of defined zone prefixes.
|
--- Builds a set of ZONE_GOALs that contain the given string in their name.
|
||||||
-- All the zones starting with the given prefixes will be included within the set.
|
-- **ATTENTION!** Bad naming convention as this **does not** filter only **prefixes** but all zones that **contain** the string.
|
||||||
-- @param #SET_ZONE_GOAL self
|
-- @param #SET_ZONE_GOAL self
|
||||||
-- @param #string Prefixes The prefix of which the zone name starts with.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the zone name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_ZONE_GOAL self
|
-- @return #SET_ZONE_GOAL self
|
||||||
function SET_ZONE_GOAL:FilterPrefixes( Prefixes )
|
function SET_ZONE_GOAL:FilterPrefixes( Prefixes )
|
||||||
if not self.Filter.Prefixes then
|
if not self.Filter.Prefixes then
|
||||||
|
|||||||
@@ -1718,27 +1718,29 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
||||||
nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true)
|
nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true)
|
||||||
spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true)
|
spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true)
|
||||||
|
--[[
|
||||||
elseif Parkingdata~=nil then
|
elseif Parkingdata~=nil then
|
||||||
-- Parking data explicitly set by user as input parameter.
|
-- Parking data explicitly set by user as input parameter.
|
||||||
nfree=#Parkingdata
|
nfree=#Parkingdata
|
||||||
spots=Parkingdata
|
spots=Parkingdata
|
||||||
|
]]
|
||||||
else
|
else
|
||||||
if ishelo then
|
if ishelo then
|
||||||
if termtype==nil then
|
if termtype==nil then
|
||||||
-- Helo is spawned. Try exclusive helo spots first.
|
-- Helo is spawned. Try exclusive helo spots first.
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly))
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
if nfree<nunits then
|
if nfree<nunits then
|
||||||
-- Not enough helo ports. Let's try also other terminal types.
|
-- Not enough helo ports. Let's try also other terminal types.
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable))
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- No terminal type specified. We try all spots except shelters.
|
-- No terminal type specified. We try all spots except shelters.
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype))
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1747,29 +1749,30 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
if isbomber or istransport or istanker or isawacs then
|
if isbomber or istransport or istanker or isawacs then
|
||||||
-- First we fill the potentially bigger spots.
|
-- First we fill the potentially bigger spots.
|
||||||
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig))
|
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
if nfree<nunits then
|
if nfree<nunits then
|
||||||
-- Now we try the smaller ones.
|
-- Now we try the smaller ones.
|
||||||
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig))
|
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:T(string.format("Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft))
|
self:T(string.format("Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Terminal type explicitly given.
|
-- Terminal type explicitly given.
|
||||||
self:T(string.format("Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring(termtype)))
|
self:T(string.format("Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring(termtype)))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get parking data.
|
-- Debug: Get parking data.
|
||||||
|
--[[
|
||||||
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
||||||
self:T(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
self:T(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
||||||
for _,_spot in pairs(parkingdata) do
|
for _,_spot in pairs(parkingdata) do
|
||||||
@@ -1777,6 +1780,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
||||||
end
|
end
|
||||||
self:T(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
self:T(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
||||||
|
]]
|
||||||
|
|
||||||
-- Set this to true if not enough spots are available for emergency air start.
|
-- Set this to true if not enough spots are available for emergency air start.
|
||||||
local _notenough=false
|
local _notenough=false
|
||||||
@@ -2144,27 +2148,29 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
|||||||
self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
self:T(string.format("Group %s is spawned on farp/ship/runway %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName()))
|
||||||
nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true)
|
nfree=SpawnAirbase:GetFreeParkingSpotsNumber(termtype, true)
|
||||||
spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true)
|
spots=SpawnAirbase:GetFreeParkingSpotsTable(termtype, true)
|
||||||
|
--[[
|
||||||
elseif Parkingdata~=nil then
|
elseif Parkingdata~=nil then
|
||||||
-- Parking data explicitly set by user as input parameter.
|
-- Parking data explicitly set by user as input parameter.
|
||||||
nfree=#Parkingdata
|
nfree=#Parkingdata
|
||||||
spots=Parkingdata
|
spots=Parkingdata
|
||||||
|
]]
|
||||||
else
|
else
|
||||||
if ishelo then
|
if ishelo then
|
||||||
if termtype==nil then
|
if termtype==nil then
|
||||||
-- Helo is spawned. Try exclusive helo spots first.
|
-- Helo is spawned. Try exclusive helo spots first.
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly))
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterOnly))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterOnly, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
if nfree<nunits then
|
if nfree<nunits then
|
||||||
-- Not enough helo ports. Let's try also other terminal types.
|
-- Not enough helo ports. Let's try also other terminal types.
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable))
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.HelicopterUsable))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.HelicopterUsable, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- No terminal type specified. We try all spots except shelters.
|
-- No terminal type specified. We try all spots except shelters.
|
||||||
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype))
|
self:T(string.format("Helo group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), termtype))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -2176,29 +2182,30 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
|||||||
if isbomber or istransport then
|
if isbomber or istransport then
|
||||||
-- First we fill the potentially bigger spots.
|
-- First we fill the potentially bigger spots.
|
||||||
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig))
|
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenBig))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
if nfree<nunits then
|
if nfree<nunits then
|
||||||
-- Now we try the smaller ones.
|
-- Now we try the smaller ones.
|
||||||
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig))
|
self:T(string.format("Transport/bomber group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.OpenMedOrBig))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.OpenMedOrBig, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:T(string.format("Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft))
|
self:T(string.format("Fighter group %s is at %s using terminal type %d.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), AIRBASE.TerminalType.FighterAircraft))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, AIRBASE.TerminalType.FighterAircraft, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Terminal type explicitly given.
|
-- Terminal type explicitly given.
|
||||||
self:T(string.format("Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring(termtype)))
|
self:T(string.format("Plane group %s is at %s using terminal type %s.", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), tostring(termtype)))
|
||||||
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits)
|
spots=SpawnAirbase:FindFreeParkingSpotForAircraft(TemplateGroup, termtype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nunits, Parkingdata)
|
||||||
nfree=#spots
|
nfree=#spots
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get parking data.
|
-- Debug: Get parking data.
|
||||||
|
--[[
|
||||||
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
local parkingdata=SpawnAirbase:GetParkingSpotsTable(termtype)
|
||||||
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
self:T2(string.format("Parking at %s, terminal type %s:", SpawnAirbase:GetName(), tostring(termtype)))
|
||||||
for _,_spot in pairs(parkingdata) do
|
for _,_spot in pairs(parkingdata) do
|
||||||
@@ -2206,6 +2213,7 @@ function SPAWN:ParkAircraft( SpawnAirbase, TerminalType, Parkingdata, SpawnIndex
|
|||||||
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
SpawnAirbase:GetName(), _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy))
|
||||||
end
|
end
|
||||||
self:T(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
self:T(string.format("%s at %s: free parking spots = %d - number of units = %d", self.SpawnTemplatePrefix, SpawnAirbase:GetName(), nfree, nunits))
|
||||||
|
]]
|
||||||
|
|
||||||
-- Set this to true if not enough spots are available for emergency air start.
|
-- Set this to true if not enough spots are available for emergency air start.
|
||||||
local _notenough=false
|
local _notenough=false
|
||||||
|
|||||||
@@ -1,104 +1,156 @@
|
|||||||
--- **Core** - Spawn new statics in your running missions.
|
--- **Core** - Spawn statics.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Spawn new statics from a static already defined using the mission editor.
|
-- * Spawn new statics from a static already defined in the mission editor.
|
||||||
-- * Spawn new statics from a given template.
|
-- * Spawn new statics from a given template.
|
||||||
-- * Spawn new statics from a given type.
|
-- * Spawn new statics from a given type.
|
||||||
-- * Spawn with a custom heading and location.
|
-- * Spawn with a custom heading and location.
|
||||||
-- * Spawn within a zone.
|
-- * Spawn within a zone.
|
||||||
|
-- * Spawn statics linked to units, .e.g on aircraft carriers.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
-- ### [SPAWNSTATIC Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPS - Spawning Statics)
|
-- ## [SPAWNSTATIC Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPS%20-%20Spawning%20Statics)
|
||||||
--
|
--
|
||||||
-- ### [SPAWNSTATIC Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPS%20-%20Spawning%20Statics)
|
|
||||||
--
|
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # YouTube Channel
|
-- # YouTube Channel
|
||||||
--
|
--
|
||||||
-- ### [SPAWNSTATIC YouTube Channel]()
|
-- ## [SPAWNSTATIC YouTube Channel]() [No videos yet!]
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions: **funkyfranky**
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Core.SpawnStatic
|
-- @module Core.SpawnStatic
|
||||||
-- @image Core_Spawnstatic.JPG
|
-- @image Core_Spawnstatic.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @type SPAWNSTATIC
|
--- @type SPAWNSTATIC
|
||||||
|
-- @field #string SpawnTemplatePrefix Name of the template group.
|
||||||
|
-- @field #number CountryID Country ID.
|
||||||
|
-- @field #number CoalitionID Coalition ID.
|
||||||
|
-- @field #number CategoryID Category ID.
|
||||||
|
-- @field #number SpawnIndex Running number increased with each new Spawn.
|
||||||
|
-- @field Wrapper.Unit#UNIT InitLinkUnit The unit the static is linked to.
|
||||||
|
-- @field #number InitOffsetX Link offset X coordinate.
|
||||||
|
-- @field #number InitOffsetY Link offset Y coordinate.
|
||||||
|
-- @field #number InitOffsetAngle Link offset angle in degrees.
|
||||||
|
-- @field #number InitStaticHeading Heading of the static.
|
||||||
|
-- @field #string InitStaticLivery Livery for aircraft.
|
||||||
|
-- @field #string InitStaticShape Shape of teh static.
|
||||||
|
-- @field #string InitStaticType Type of the static.
|
||||||
|
-- @field #string InitStaticCategory Categrory of the static.
|
||||||
|
-- @field #string InitStaticName Name of the static.
|
||||||
|
-- @field Core.Point#COORDINATE InitStaticCoordinate Coordinate where to spawn the static.
|
||||||
|
-- @field #boolean InitDead Set static to be dead if true.
|
||||||
|
-- @field #boolean InitCargo If true, static can act as cargo.
|
||||||
|
-- @field #number InitCargoMass Mass of cargo in kg.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- Allows to spawn dynamically new @{Static}s.
|
--- Allows to spawn dynamically new @{Static}s into your mission.
|
||||||
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME),
|
|
||||||
-- SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc), and "copy"
|
|
||||||
-- these properties to create a new static object and place it at the desired coordinate.
|
|
||||||
--
|
--
|
||||||
-- New spawned @{Static}s get **the same name** as the name of the template Static,
|
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc),
|
||||||
-- or gets the given name when a new name is provided at the Spawn method.
|
-- and "copy" these properties to create a new static object and place it at the desired coordinate.
|
||||||
|
--
|
||||||
|
-- New spawned @{Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
|
||||||
-- By default, spawned @{Static}s will follow a naming convention at run-time:
|
-- By default, spawned @{Static}s will follow a naming convention at run-time:
|
||||||
--
|
--
|
||||||
-- * Spawned @{Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**,
|
-- * Spawned @{Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
|
||||||
-- and _nnn_ is a **counter from 0 to 99999**.
|
|
||||||
--
|
--
|
||||||
|
-- # SPAWNSTATIC Constructors
|
||||||
--
|
--
|
||||||
-- ## SPAWNSTATIC construction methods
|
-- Firstly, we need to create a SPAWNSTATIC object that will be used to spawn new statics into the mission. There are three ways to do this.
|
||||||
--
|
--
|
||||||
-- Create a new SPAWNSTATIC object with the @{#SPAWNSTATIC.NewFromStatic}():
|
-- ## Use another Static
|
||||||
--
|
--
|
||||||
-- * @{#SPAWNSTATIC.NewFromStatic}(): Creates a new SPAWNSTATIC object given a name that is used as the base of the naming of each spawned Static.
|
-- A new SPAWNSTATIC object can be created using another static by the @{#SPAWNSTATIC.NewFromStatic}() function. All parameters such as position, heading, country will be initialized
|
||||||
|
-- from the static.
|
||||||
--
|
--
|
||||||
-- ## **Spawn** methods
|
-- ## From a Template
|
||||||
--
|
--
|
||||||
-- Groups can be spawned at different times and methods:
|
-- A SPAWNSTATIC object can also be created from a template table using the @{#SPAWNSTATIC.NewFromTemplate}(SpawnTemplate, CountryID) function. All parameters are taken from the template.
|
||||||
--
|
--
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(): Spawn a new group from a POINT_VEC2 coordinate.
|
-- ## From a Type
|
||||||
-- (The group will be spawned at land height ).
|
--
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromZone}(): Spawn a new group in a @{Zone}.
|
-- A very basic method is to create a SPAWNSTATIC object by just giving the type of the static. All parameters must be initialized from the InitXYZ functions described below. Otherwise default values
|
||||||
|
-- are used. For example, if no spawn coordinate is given, the static will be created at the origin of the map.
|
||||||
|
--
|
||||||
|
-- # Setting Parameters
|
||||||
|
--
|
||||||
|
-- Parameters such as the spawn position, heading, country etc. can be set via :Init*XYZ* functions. Note that these functions must be given before the actual spawn command!
|
||||||
|
--
|
||||||
|
-- * @{#SPAWNSTATIC.InitCoordinate}(Coordinate) Sets the coordinate where the static is spawned. Statics are always spawnd on the ground.
|
||||||
|
-- * @{#SPAWNSTATIC.InitHeading}(Heading) sets the orientation of the static.
|
||||||
|
-- * @{#SPAWNSTATIC.InitLivery}(LiveryName) sets the livery of the static. Not all statics support this.
|
||||||
|
-- * @{#SPAWNSTATIC.InitType}(StaticType) sets the type of the static.
|
||||||
|
-- * @{#SPAWNSTATIC.InitShape}(StaticType) sets the shape of the static. Not all statics have this parameter.
|
||||||
|
-- * @{#SPAWNSTATIC.InitNamePrefix}(NamePrefix) sets the name prefix of the spawned statics.
|
||||||
|
-- * @{#SPAWNSTATIC.InitCountry}(CountryID) sets the country and therefore the coalition of the spawned statics.
|
||||||
|
-- * @{#SPAWNSTATIC.InitLinkToUnit}(Unit, OffsetX, OffsetY, OffsetAngle) links the static to a unit, e.g. to an aircraft carrier.
|
||||||
|
--
|
||||||
|
-- # Spawning the Statics
|
||||||
|
--
|
||||||
|
-- Once the SPAWNSTATIC object is created and parameters are initialized, the spawn command can be given. There are different methods where some can be used to directly set parameters
|
||||||
|
-- such as position and heading.
|
||||||
|
--
|
||||||
|
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
|
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
|
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
|
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
--
|
--
|
||||||
-- @field #SPAWNSTATIC SPAWNSTATIC
|
-- @field #SPAWNSTATIC SPAWNSTATIC
|
||||||
--
|
--
|
||||||
SPAWNSTATIC = {
|
SPAWNSTATIC = {
|
||||||
ClassName = "SPAWNSTATIC",
|
ClassName = "SPAWNSTATIC",
|
||||||
|
SpawnIndex = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Static template table data.
|
||||||
|
-- @type SPAWNSTATIC.TemplateData
|
||||||
|
-- @field #string name Name of the static.
|
||||||
|
-- @field #string type Type of the static.
|
||||||
|
-- @field #string category Category of the static.
|
||||||
|
-- @field #number x X-coordinate of the static.
|
||||||
|
-- @field #number y Y-coordinate of teh static.
|
||||||
|
-- @field #number heading Heading in rad.
|
||||||
|
-- @field #boolean dead Static is dead if true.
|
||||||
|
-- @field #string livery_id Livery name.
|
||||||
|
-- @field #number unitId Unit ID.
|
||||||
|
-- @field #number groupId Group ID.
|
||||||
|
-- @field #table offsets Offset parameters when linked to a unit.
|
||||||
|
-- @field #number mass Cargo mass in kg.
|
||||||
|
-- @field #boolean canCargo Static can be a cargo.
|
||||||
|
|
||||||
--- @type SPAWNSTATIC.SpawnZoneTable
|
--- Creates the main object to spawn a @{Static} defined in the mission editor (ME).
|
||||||
-- @list <Core.Zone#ZONE_BASE> SpawnZone
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates the main object to spawn a @{Static} defined in the ME.
|
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix.
|
-- @param #string SpawnTemplateName Name of the static object in the ME. Each new static will have the name starting with this prefix.
|
||||||
-- @param DCS#country.id SpawnCountryID The ID of the country.
|
-- @param DCS#country.id SpawnCountryID (Optional) The ID of the country.
|
||||||
-- @param DCS#coalition.side SpawnCoalitionID The ID of the coalition.
|
-- @return #SPAWNSTATIC self
|
||||||
-- @return #SPAWNSTATIC
|
function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||||
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, SpawnCountryID, SpawnCoalitionID )
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
self:F( { SpawnTemplatePrefix } )
|
|
||||||
|
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate(SpawnTemplateName)
|
||||||
|
|
||||||
local TemplateStatic, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( SpawnTemplatePrefix )
|
|
||||||
if TemplateStatic then
|
if TemplateStatic then
|
||||||
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
self.SpawnTemplatePrefix = SpawnTemplateName
|
||||||
|
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 = SpawnCoalitionID or 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 = '" .. SpawnTemplatePrefix .. "'" )
|
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
||||||
end
|
end
|
||||||
|
|
||||||
self:SetEventPriority( 5 )
|
self:SetEventPriority( 5 )
|
||||||
@@ -106,206 +158,325 @@ function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, SpawnCountryID, SpawnCo
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates the main object to spawn a @{Static} based on a type name.
|
--- Creates the main object to spawn a @{Static} given a template table.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #string SpawnTypeName is the name of the type.
|
-- @param #table SpawnTemplate Template used for spawning.
|
||||||
-- @return #SPAWNSTATIC
|
-- @param DCS#country.id CountryID The ID of the country. Default `country.id.USA`.
|
||||||
function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, SpawnCountryID, SpawnCoalitionID )
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:NewFromTemplate(SpawnTemplate, CountryID)
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
self:F( { SpawnTypeName } )
|
|
||||||
|
|
||||||
self.SpawnTypeName = SpawnTypeName
|
self.TemplateStaticUnit = UTILS.DeepCopy(SpawnTemplate)
|
||||||
self.CountryID = SpawnCountryID
|
self.SpawnTemplatePrefix = SpawnTemplate.name
|
||||||
self.CoalitionID = SpawnCoalitionID
|
self.CountryID = CountryID or country.id.USA
|
||||||
self.SpawnIndex = 0
|
|
||||||
|
|
||||||
self:SetEventPriority( 5 )
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Creates the main object to spawn a @{Static} from a given type.
|
||||||
--- Creates a new @{Static} at the original position.
|
-- NOTE that you have to init many other parameters as spawn coordinate etc.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
-- @param #string StaticType Type of the static.
|
||||||
-- @param #string (optional) The name of the new static.
|
-- @param #string StaticCategory Category of the static, e.g. "Planes".
|
||||||
-- @return #SPAWNSTATIC
|
-- @param DCS#country.id CountryID The ID of the country. Default `country.id.USA`.
|
||||||
function SPAWNSTATIC:Spawn( Heading, NewName ) --R2.3
|
-- @return #SPAWNSTATIC self
|
||||||
self:F( { Heading, NewName } )
|
function SPAWNSTATIC:NewFromType(StaticType, StaticCategory, CountryID)
|
||||||
|
|
||||||
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
|
||||||
|
|
||||||
if StaticTemplate then
|
self.InitStaticType=StaticType
|
||||||
|
self.InitStaticCategory=StaticCategory
|
||||||
|
self.CountryID=CountryID or country.id.USA
|
||||||
|
self.SpawnTemplatePrefix=self.InitStaticType
|
||||||
|
|
||||||
local StaticUnitTemplate = StaticTemplate.units[1]
|
self.InitStaticCoordinate=COORDINATE:New(0, 0, 0)
|
||||||
|
self.InitStaticHeading=0
|
||||||
|
|
||||||
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
return self
|
||||||
StaticTemplate.heading = ( Heading / 180 ) * math.pi
|
|
||||||
|
|
||||||
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
|
|
||||||
|
|
||||||
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
|
||||||
|
|
||||||
self.SpawnIndex = self.SpawnIndex + 1
|
|
||||||
|
|
||||||
return _DATABASE:FindStatic(Static:getName())
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Initialize heading of the spawned static.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Position where the static is spawned.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitCoordinate(Coordinate)
|
||||||
|
self.InitStaticCoordinate=Coordinate
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize heading of the spawned static.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #number Heading The heading in degrees.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitHeading(Heading)
|
||||||
|
self.InitStaticHeading=Heading
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize livery of the spawned static.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #string LiveryName Name of the livery to use.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitLivery(LiveryName)
|
||||||
|
self.InitStaticLivery=LiveryName
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize type of the spawned static.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #string StaticType Type of the static, e.g. "FA-18C_hornet".
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitType(StaticType)
|
||||||
|
self.InitStaticType=StaticType
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize shape of the spawned static. Required by some but not all statics.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #string StaticShape Shape of the static, e.g. "carrier_tech_USA".
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitShape(StaticShape)
|
||||||
|
self.InitStaticShape=StaticShape
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize parameters for spawning FARPs.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #number CallsignID Callsign ID. Default 1 (="London").
|
||||||
|
-- @param #number Frequency Frequency in MHz. Default 127.5 MHz.
|
||||||
|
-- @param #number Modulation Modulation 0=AM, 1=FM.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation)
|
||||||
|
self.InitFarp=true
|
||||||
|
self.InitFarpCallsignID=CallsignID or 1
|
||||||
|
self.InitFarpFreq=Frequency or 127.5
|
||||||
|
self.InitFarpModu=Modulation or 0
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize cargo mass.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #number Mass Mass of the cargo in kg.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitCargoMass(Mass)
|
||||||
|
self.InitCargoMass=Mass
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize as cargo.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #boolean IsCargo If true, this static can act as cargo.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitCargo(IsCargo)
|
||||||
|
self.InitCargo=IsCargo
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize country of the spawned static. This determines the category.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #string CountryID The country ID, e.g. country.id.USA.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitCountry(CountryID)
|
||||||
|
self.CountryID=CountryID
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize name prefix statics get. This will be appended by "#0001", "#0002" etc.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #string NamePrefix Name prefix of statics spawned. Will append #0001, etc to the name.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitNamePrefix(NamePrefix)
|
||||||
|
self.SpawnTemplatePrefix=NamePrefix
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Init link to a unit.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit The unit to which the static is linked.
|
||||||
|
-- @param #number OffsetX Offset in X.
|
||||||
|
-- @param #number OffsetY Offset in Y.
|
||||||
|
-- @param #number OffsetAngle Offset angle in degrees.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitLinkToUnit(Unit, OffsetX, OffsetY, OffsetAngle)
|
||||||
|
|
||||||
|
self.InitLinkUnit=Unit
|
||||||
|
self.InitOffsetX=OffsetX or 0
|
||||||
|
self.InitOffsetY=OffsetY or 0
|
||||||
|
self.InitOffsetAngle=OffsetAngle or 0
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Spawn a new STATIC object.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #number Heading (Optional) The heading of the static, which is a number in degrees from 0 to 360. Default is the heading of the template.
|
||||||
|
-- @param #string NewName (Optional) The name of the new static.
|
||||||
|
-- @return Wrapper.Static#STATIC The static spawned.
|
||||||
|
function SPAWNSTATIC:Spawn(Heading, NewName)
|
||||||
|
|
||||||
|
if Heading then
|
||||||
|
self.InitStaticHeading=Heading
|
||||||
|
end
|
||||||
|
|
||||||
|
if NewName then
|
||||||
|
self.InitStaticName=NewName
|
||||||
|
end
|
||||||
|
|
||||||
|
return self:_SpawnStatic(self.TemplateStaticUnit, self.CountryID)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Creates a new @{Static} from a POINT_VEC2.
|
--- Creates a new @{Static} from a POINT_VEC2.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
||||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
||||||
-- @param #string (optional) The name of the new static.
|
-- @param #string NewName (Optional) The name of the new static.
|
||||||
-- @return #SPAWNSTATIC
|
-- @return Wrapper.Static#STATIC The static spawned.
|
||||||
function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1
|
function SPAWNSTATIC:SpawnFromPointVec2(PointVec2, Heading, NewName)
|
||||||
self:F( { PointVec2, Heading, NewName } )
|
|
||||||
|
|
||||||
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
local vec2={x=PointVec2:GetX(), y=PointVec2:GetY()}
|
||||||
|
|
||||||
if StaticTemplate then
|
local Coordinate=COORDINATE:NewFromVec2(vec2)
|
||||||
|
|
||||||
local StaticUnitTemplate = StaticTemplate.units[1]
|
return self:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
||||||
|
|
||||||
StaticUnitTemplate.x = PointVec2.x
|
|
||||||
StaticUnitTemplate.y = PointVec2.z
|
|
||||||
|
|
||||||
StaticTemplate.route = nil
|
|
||||||
StaticTemplate.groupId = nil
|
|
||||||
|
|
||||||
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
|
||||||
StaticUnitTemplate.name = StaticTemplate.name
|
|
||||||
StaticUnitTemplate.heading = ( Heading / 180 ) * math.pi
|
|
||||||
|
|
||||||
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID)
|
|
||||||
|
|
||||||
self:F({StaticTemplate = StaticTemplate})
|
|
||||||
|
|
||||||
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
|
||||||
|
|
||||||
self.SpawnIndex = self.SpawnIndex + 1
|
|
||||||
|
|
||||||
return _DATABASE:FindStatic(Static:getName())
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new @{Static} from a COORDINATE.
|
--- Creates a new @{Static} from a COORDINATE.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Point#COORDINATE Coordinate The 3D coordinate where to spawn the static.
|
-- @param Core.Point#COORDINATE Coordinate The 3D coordinate where to spawn the static.
|
||||||
-- @param #number Heading (Optional) Heading The heading of the static, which is a number in degrees from 0 to 360. Default is 0 degrees.
|
-- @param #number Heading (Optional) Heading The heading of the static in degrees. Default is 0 degrees.
|
||||||
-- @param #string NewName (Optional) The name of the new static.
|
-- @param #string NewName (Optional) The name of the new static.
|
||||||
-- @return #SPAWNSTATIC
|
-- @return Wrapper.Static#STATIC The spawned STATIC object.
|
||||||
function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName) --R2.4
|
function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
||||||
self:F( { PointVec2, Heading, NewName } )
|
|
||||||
|
|
||||||
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
-- Set up coordinate.
|
||||||
|
self.InitStaticCoordinate=Coordinate
|
||||||
|
|
||||||
if StaticTemplate then
|
if Heading then
|
||||||
|
self.InitStaticHeading=Heading
|
||||||
Heading=Heading or 0
|
|
||||||
|
|
||||||
local StaticUnitTemplate = StaticTemplate.units[1]
|
|
||||||
|
|
||||||
StaticUnitTemplate.x = Coordinate.x
|
|
||||||
StaticUnitTemplate.y = Coordinate.z
|
|
||||||
StaticUnitTemplate.alt = Coordinate.y
|
|
||||||
|
|
||||||
StaticTemplate.route = nil
|
|
||||||
StaticTemplate.groupId = nil
|
|
||||||
|
|
||||||
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
|
||||||
StaticUnitTemplate.name = StaticTemplate.name
|
|
||||||
StaticUnitTemplate.heading = ( Heading / 180 ) * math.pi
|
|
||||||
|
|
||||||
_DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID)
|
|
||||||
|
|
||||||
self:F({StaticTemplate = StaticTemplate})
|
|
||||||
|
|
||||||
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
|
||||||
|
|
||||||
self.SpawnIndex = self.SpawnIndex + 1
|
|
||||||
|
|
||||||
return _DATABASE:FindStatic(Static:getName())
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
if NewName then
|
||||||
end
|
self.InitStaticName=NewName
|
||||||
|
|
||||||
|
|
||||||
--- Respawns the original @{Static}.
|
|
||||||
-- @param #SPAWNSTATIC self
|
|
||||||
-- @param #number delay Delay before respawn in seconds.
|
|
||||||
-- @return #SPAWNSTATIC
|
|
||||||
function SPAWNSTATIC:ReSpawn(delay)
|
|
||||||
|
|
||||||
if delay and delay>0 then
|
|
||||||
self:ScheduleOnce(delay, SPAWNSTATIC.ReSpawn, self)
|
|
||||||
else
|
|
||||||
|
|
||||||
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
|
||||||
|
|
||||||
if StaticTemplate then
|
|
||||||
|
|
||||||
local StaticUnitTemplate = StaticTemplate.units[1]
|
|
||||||
StaticTemplate.route = nil
|
|
||||||
StaticTemplate.groupId = nil
|
|
||||||
|
|
||||||
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
|
||||||
|
|
||||||
return _DATABASE:FindStatic(Static:getName())
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return self:_SpawnStatic(self.TemplateStaticUnit, self.CountryID)
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates the original @{Static} at a POINT_VEC2.
|
|
||||||
-- @param #SPAWNSTATIC self
|
|
||||||
-- @param Core.Point#COORDINATE Coordinate The 2D coordinate where to spawn the static.
|
|
||||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
|
||||||
-- @return #SPAWNSTATIC
|
|
||||||
function SPAWNSTATIC:ReSpawnAt( Coordinate, Heading )
|
|
||||||
|
|
||||||
local StaticTemplate, CoalitionID, CategoryID, CountryID = _DATABASE:GetStaticGroupTemplate( self.SpawnTemplatePrefix )
|
|
||||||
|
|
||||||
if StaticTemplate then
|
|
||||||
|
|
||||||
local StaticUnitTemplate = StaticTemplate.units[1]
|
|
||||||
|
|
||||||
StaticUnitTemplate.x = Coordinate.x
|
|
||||||
StaticUnitTemplate.y = Coordinate.z
|
|
||||||
|
|
||||||
StaticUnitTemplate.heading = Heading and ( ( Heading / 180 ) * math.pi ) or StaticTemplate.heading
|
|
||||||
|
|
||||||
local Static = coalition.addStaticObject( self.CountryID or CountryID, StaticTemplate.units[1] )
|
|
||||||
|
|
||||||
return _DATABASE:FindStatic(Static:getName())
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new @{Static} from a @{Zone}.
|
--- Creates a new @{Static} from a @{Zone}.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
|
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
|
||||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
-- @param #number Heading (Optional)The heading of the static in degrees. Default is the heading of the template.
|
||||||
-- @param #string NewName (optional) The name of the new static.
|
-- @param #string NewName (Optional) The name of the new static.
|
||||||
-- @return #SPAWNSTATIC
|
-- @return Wrapper.Static#STATIC The static spawned.
|
||||||
function SPAWNSTATIC:SpawnFromZone( Zone, Heading, NewName ) --R2.1
|
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
||||||
self:F( { Zone, Heading, NewName } )
|
|
||||||
|
|
||||||
|
-- Spawn the new static at the center of the zone.
|
||||||
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||||
|
|
||||||
return Static
|
return Static
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Spawns a new static using a given template. Additionally, the country ID needs to be specified, which also determines the coalition of the spawned static.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #SPAWNSTATIC.TemplateData Template Spawn unit template.
|
||||||
|
-- @param #number CountryID The country ID.
|
||||||
|
-- @return Wrapper.Static#STATIC The static spawned.
|
||||||
|
function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||||
|
|
||||||
|
Template=Template or {}
|
||||||
|
|
||||||
|
local CountryID=CountryID or self.CountryID
|
||||||
|
|
||||||
|
if self.InitStaticType then
|
||||||
|
Template.type=self.InitStaticType
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitStaticCategory then
|
||||||
|
Template.category=self.InitStaticCategory
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitStaticCoordinate then
|
||||||
|
Template.x = self.InitStaticCoordinate.x
|
||||||
|
Template.y = self.InitStaticCoordinate.z
|
||||||
|
Template.alt = self.InitStaticCoordinate.y
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitStaticHeading then
|
||||||
|
Template.heading = math.rad(self.InitStaticHeading)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitStaticShape then
|
||||||
|
Template.shape_name=self.InitStaticShape
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitStaticLivery then
|
||||||
|
Template.livery_id=self.InitStaticLivery
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitDead~=nil then
|
||||||
|
Template.dead=self.InitDead
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitCargo~=nil then
|
||||||
|
Template.isCargo=self.InitCargo
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitLinkUnit then
|
||||||
|
Template.linkUnit=self.InitLinkUnit:GetID()
|
||||||
|
Template.linkOffset=true
|
||||||
|
Template.offsets={}
|
||||||
|
Template.offsets.y=self.InitOffsetY
|
||||||
|
Template.offsets.x=self.InitOffsetX
|
||||||
|
Template.offsets.angle=self.InitOffsetAngle and math.rad(self.InitOffsetAngle) or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.InitFarp then
|
||||||
|
Template.heliport_callsign_id = self.InitFarpCallsignID
|
||||||
|
Template.heliport_frequency = self.InitFarpFreq
|
||||||
|
Template.heliport_modulation = self.InitFarpModu
|
||||||
|
Template.unitId=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Increase spawn index counter.
|
||||||
|
self.SpawnIndex = self.SpawnIndex + 1
|
||||||
|
|
||||||
|
-- Name of the spawned static.
|
||||||
|
Template.name = self.InitStaticName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex)
|
||||||
|
|
||||||
|
-- Add and register the new static.
|
||||||
|
local mystatic=_DATABASE:AddStatic(Template.name)
|
||||||
|
|
||||||
|
-- Debug output.
|
||||||
|
self:T(Template)
|
||||||
|
|
||||||
|
-- Add static to the game.
|
||||||
|
local Static=nil
|
||||||
|
|
||||||
|
if self.InitFarp then
|
||||||
|
|
||||||
|
local TemplateGroup={}
|
||||||
|
TemplateGroup.units={}
|
||||||
|
TemplateGroup.units[1]=Template
|
||||||
|
|
||||||
|
TemplateGroup.visible=true
|
||||||
|
TemplateGroup.hidden=false
|
||||||
|
TemplateGroup.x=Template.x
|
||||||
|
TemplateGroup.y=Template.y
|
||||||
|
TemplateGroup.name=Template.name
|
||||||
|
|
||||||
|
self:T("Spawning FARP")
|
||||||
|
self:T({Template=Template})
|
||||||
|
self:T({TemplateGroup=TemplateGroup})
|
||||||
|
|
||||||
|
-- ED's dirty way to spawn FARPS.
|
||||||
|
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||||
|
else
|
||||||
|
Static=coalition.addStaticObject(CountryID, Template)
|
||||||
|
end
|
||||||
|
|
||||||
|
return mystatic
|
||||||
|
end
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ do
|
|||||||
-- @return #SPOT
|
-- @return #SPOT
|
||||||
function SPOT:onafterLaseOff( From, Event, To )
|
function SPOT:onafterLaseOff( From, Event, To )
|
||||||
|
|
||||||
self:F( {"Stopped lasing for ", self.Target:GetName() , SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
|
self:F( {"Stopped lasing for ", self.Target and self.Target:GetName() or "coord", SpotIR = self.SportIR, SpotLaser = self.SpotLaser } )
|
||||||
|
|
||||||
self.Lasing = false
|
self.Lasing = false
|
||||||
|
|
||||||
|
|||||||
292
Moose Development/Moose/Core/Timer.lua
Normal file
292
Moose Development/Moose/Core/Timer.lua
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
--- **Core** - Timer scheduler.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Delay function calls
|
||||||
|
-- * Easy set up and little overhead
|
||||||
|
-- * Set start, stop and time interval
|
||||||
|
-- * Define max function calls
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
-- @module Core.Timer
|
||||||
|
-- @image Core_Scheduler.JPG
|
||||||
|
|
||||||
|
|
||||||
|
--- TIMER class.
|
||||||
|
-- @type TIMER
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #number tid Timer ID returned by the DCS API function.
|
||||||
|
-- @field #number uid Unique ID of the timer.
|
||||||
|
-- @field #function func Timer function.
|
||||||
|
-- @field #table para Parameters passed to the timer function.
|
||||||
|
-- @field #number Tstart Relative start time in seconds.
|
||||||
|
-- @field #number Tstop Relative stop time in seconds.
|
||||||
|
-- @field #number dT Time interval between function calls in seconds.
|
||||||
|
-- @field #number ncalls Counter of function calls.
|
||||||
|
-- @field #number ncallsMax Max number of function calls. If reached, timer is stopped.
|
||||||
|
-- @field #boolean isrunning If `true`, timer is running. Else it was not started yet or was stopped.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *Better three hours too soon than a minute too late.* - William Shakespeare
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- # The TIMER Concept
|
||||||
|
--
|
||||||
|
-- The TIMER class is the little sister of the @{Core.Scheduler#SCHEDULER} class. It does the same thing but is a bit easier to use and has less overhead. It should be sufficient in many cases.
|
||||||
|
--
|
||||||
|
-- It provides an easy interface to the DCS [timer.scheduleFunction](https://wiki.hoggitworld.com/view/DCS_func_scheduleFunction).
|
||||||
|
--
|
||||||
|
-- # Construction
|
||||||
|
--
|
||||||
|
-- A new TIMER is created by the @{#TIMER.New}(*func*, *...*) function
|
||||||
|
--
|
||||||
|
-- local mytimer=TIMER:New(myfunction, a, b)
|
||||||
|
--
|
||||||
|
-- The first parameter *func* is the function that is called followed by the necessary comma separeted parameters that are passed to that function.
|
||||||
|
--
|
||||||
|
-- ## Starting the Timer
|
||||||
|
--
|
||||||
|
-- The timer is started by the @{#TIMER.Start}(*Tstart*, *dT*, *Duration*) function
|
||||||
|
--
|
||||||
|
-- mytimer:Start(5, 1, 20)
|
||||||
|
--
|
||||||
|
-- where
|
||||||
|
--
|
||||||
|
-- * *Tstart* is the relative start time in seconds. In the example, the first function call happens after 5 sec.
|
||||||
|
-- * *dT* is the time interval between function calls in seconds. Above, the function is called once per second.
|
||||||
|
-- * *Duration* is the duration in seconds after which the timer is stopped. This is relative to the start time. Here, the timer will run for 20 seconds.
|
||||||
|
--
|
||||||
|
-- Note that
|
||||||
|
--
|
||||||
|
-- * if *Tstart* is not specified (*nil*), the first function call happens immediately, i.e. after one millisecond.
|
||||||
|
-- * if *dT* is not specified (*nil*), the function is called only once.
|
||||||
|
-- * if *Duration* is not specified (*nil*), the timer runs forever or until stopped manually or until the max function calls are reached (see below).
|
||||||
|
--
|
||||||
|
-- For example,
|
||||||
|
--
|
||||||
|
-- mytimer:Start(3) -- Will call the function once after 3 seconds.
|
||||||
|
-- mytimer:Start(nil, 0.5) -- Will call right now and then every 0.5 sec until all eternity.
|
||||||
|
-- mytimer:Start(nil, 2.0, 20) -- Will call right now and then every 2.0 sec for 20 sec.
|
||||||
|
-- mytimer:Start(1.0, nil, 10) -- Does not make sense as the function is only called once anyway.
|
||||||
|
--
|
||||||
|
-- ## Stopping the Timer
|
||||||
|
--
|
||||||
|
-- The timer can be stopped manually by the @{#TIMER.Stop}(*Delay*) function
|
||||||
|
--
|
||||||
|
-- mytimer:Stop()
|
||||||
|
--
|
||||||
|
-- If the optional paramter *Delay* is specified, the timer is stopped after *delay* seconds.
|
||||||
|
--
|
||||||
|
-- ## Limit Function Calls
|
||||||
|
--
|
||||||
|
-- The timer can be stopped after a certain amount of function calles with the @{#TIMER.SetMaxFunctionCalls}(*Nmax*) function
|
||||||
|
--
|
||||||
|
-- mytimer:SetMaxFunctionCalls(20)
|
||||||
|
--
|
||||||
|
-- where *Nmax* is the number of calls after which the timer is stopped, here 20.
|
||||||
|
--
|
||||||
|
-- For example,
|
||||||
|
--
|
||||||
|
-- mytimer:SetMaxFunctionCalls(66):Start(1.0, 0.1)
|
||||||
|
--
|
||||||
|
-- will start the timer after one second and call the function every 0.1 seconds. Once the function has been called 66 times, the timer is stopped.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #TIMER
|
||||||
|
TIMER = {
|
||||||
|
ClassName = "TIMER",
|
||||||
|
lid = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Timer ID.
|
||||||
|
_TIMERID=0
|
||||||
|
|
||||||
|
--- Timer data base.
|
||||||
|
--_TIMERDB={}
|
||||||
|
|
||||||
|
--- TIMER class version.
|
||||||
|
-- @field #string version
|
||||||
|
TIMER.version="0.1.1"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: A lot.
|
||||||
|
-- TODO: Write docs.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new TIMER object.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... Parameters passed to the function if any.
|
||||||
|
-- @return #TIMER self
|
||||||
|
function TIMER:New(Function, ...)
|
||||||
|
|
||||||
|
-- Inherit BASE.
|
||||||
|
local self=BASE:Inherit(self, BASE:New()) --#TIMER
|
||||||
|
|
||||||
|
-- Function to call.
|
||||||
|
self.func=Function
|
||||||
|
|
||||||
|
-- Function arguments.
|
||||||
|
self.para=arg or {}
|
||||||
|
|
||||||
|
-- Number of function calls.
|
||||||
|
self.ncalls=0
|
||||||
|
|
||||||
|
-- Not running yet.
|
||||||
|
self.isrunning=false
|
||||||
|
|
||||||
|
-- Increase counter
|
||||||
|
_TIMERID=_TIMERID+1
|
||||||
|
|
||||||
|
-- Set UID.
|
||||||
|
self.uid=_TIMERID
|
||||||
|
|
||||||
|
-- Log id.
|
||||||
|
self.lid=string.format("TIMER UID=%d | ", self.uid)
|
||||||
|
|
||||||
|
-- Add to DB.
|
||||||
|
--_TIMERDB[self.uid]=self
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a new TIMER object.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @param #number Tstart Relative start time in seconds.
|
||||||
|
-- @param #number dT Interval between function calls in seconds. If not specified `nil`, the function is called only once.
|
||||||
|
-- @param #number Duration Time in seconds for how long the timer is running. If not specified `nil`, the timer runs forever or until stopped manually by the `TIMER:Stop()` function.
|
||||||
|
-- @return #TIMER self
|
||||||
|
function TIMER:Start(Tstart, dT, Duration)
|
||||||
|
|
||||||
|
-- Current time.
|
||||||
|
local Tnow=timer.getTime()
|
||||||
|
|
||||||
|
-- Start time in sec.
|
||||||
|
self.Tstart=Tstart and Tnow+Tstart or Tnow+0.001 -- one millisecond delay if Tstart=nil
|
||||||
|
|
||||||
|
-- Set time interval.
|
||||||
|
self.dT=dT
|
||||||
|
|
||||||
|
-- Stop time.
|
||||||
|
if Duration then
|
||||||
|
self.Tstop=self.Tstart+Duration
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Call DCS timer function.
|
||||||
|
self.tid=timer.scheduleFunction(self._Function, self, self.Tstart)
|
||||||
|
|
||||||
|
-- Set log id.
|
||||||
|
self.lid=string.format("TIMER UID=%d/%d | ", self.uid, self.tid)
|
||||||
|
|
||||||
|
-- Is now running.
|
||||||
|
self.isrunning=true
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Starting Timer in %.3f sec, dT=%s, Tstop=%s", self.Tstart-Tnow, tostring(self.dT), tostring(self.Tstop)))
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Stop the timer by removing the timer function.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the timer is stopped.
|
||||||
|
-- @return #TIMER self
|
||||||
|
function TIMER:Stop(Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
|
||||||
|
self.Tstop=timer.getTime()+Delay
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
if self.tid then
|
||||||
|
|
||||||
|
-- Remove timer function.
|
||||||
|
self:T(self.lid..string.format("Stopping timer by removing timer function after %d calls!", self.ncalls))
|
||||||
|
timer.removeFunction(self.tid)
|
||||||
|
|
||||||
|
-- Not running any more.
|
||||||
|
self.isrunning=false
|
||||||
|
|
||||||
|
-- Remove DB entry.
|
||||||
|
--_TIMERDB[self.uid]=nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set max number of function calls. When the function has been called this many times, the TIMER is stopped.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @param #number Nmax Set number of max function calls.
|
||||||
|
-- @return #TIMER self
|
||||||
|
function TIMER:SetMaxFunctionCalls(Nmax)
|
||||||
|
self.ncallsMax=Nmax
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the timer has been started and was not stopped.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @return #boolean If `true`, the timer is running.
|
||||||
|
function TIMER:IsRunning()
|
||||||
|
return self.isrunning
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Call timer function.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @param #number time DCS model time in seconds.
|
||||||
|
-- @return #number Time when the function is called again or `nil` if the timer is stopped.
|
||||||
|
function TIMER:_Function(time)
|
||||||
|
|
||||||
|
-- Call function.
|
||||||
|
self.func(unpack(self.para))
|
||||||
|
|
||||||
|
-- Increase number of calls.
|
||||||
|
self.ncalls=self.ncalls+1
|
||||||
|
|
||||||
|
-- Next time.
|
||||||
|
local Tnext=self.dT and time+self.dT or nil
|
||||||
|
|
||||||
|
-- Check if we stop the timer.
|
||||||
|
local stopme=false
|
||||||
|
if Tnext==nil then
|
||||||
|
-- No next time.
|
||||||
|
self:T(self.lid..string.format("No next time as dT=nil ==> Stopping timer after %d function calls", self.ncalls))
|
||||||
|
stopme=true
|
||||||
|
elseif self.Tstop and Tnext>self.Tstop then
|
||||||
|
-- Stop time passed.
|
||||||
|
self:T(self.lid..string.format("Stop time passed %.3f > %.3f ==> Stopping timer after %d function calls", Tnext, self.Tstop, self.ncalls))
|
||||||
|
stopme=true
|
||||||
|
elseif self.ncallsMax and self.ncalls>=self.ncallsMax then
|
||||||
|
-- Number of max function calls reached.
|
||||||
|
self:T(self.lid..string.format("Max function calls Nmax=%d reached ==> Stopping timer after %d function calls", self.ncallsMax, self.ncalls))
|
||||||
|
stopme=true
|
||||||
|
end
|
||||||
|
|
||||||
|
if stopme then
|
||||||
|
-- Remove timer function.
|
||||||
|
self:Stop()
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
-- Call again in Tnext seconds.
|
||||||
|
return Tnext
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -96,6 +96,11 @@ do -- world
|
|||||||
-- @function [parent=#world] getMarkPanels
|
-- @function [parent=#world] getMarkPanels
|
||||||
-- @return #table Table of marks.
|
-- @return #table Table of marks.
|
||||||
|
|
||||||
|
--- Returns a table of DCS airbase objects.
|
||||||
|
-- @function [parent=#world] getAirbases
|
||||||
|
-- @param #number coalitionId The coalition side number ID. Default is all airbases are returned.
|
||||||
|
-- @return #table Table of DCS airbase objects.
|
||||||
|
|
||||||
end -- world
|
end -- world
|
||||||
|
|
||||||
|
|
||||||
@@ -360,7 +365,7 @@ do -- Types
|
|||||||
|
|
||||||
--- Time is given in seconds.
|
--- Time is given in seconds.
|
||||||
-- @type Time
|
-- @type Time
|
||||||
-- @extends #number
|
-- @extends #number Time in seconds.
|
||||||
|
|
||||||
--- Model time is the time that drives the simulation. Model time may be stopped, accelerated and decelerated relative real time.
|
--- Model time is the time that drives the simulation. Model time may be stopped, accelerated and decelerated relative real time.
|
||||||
-- @type ModelTime
|
-- @type ModelTime
|
||||||
@@ -368,20 +373,20 @@ do -- Types
|
|||||||
|
|
||||||
--- Mission time is a model time plus time of the mission start.
|
--- Mission time is a model time plus time of the mission start.
|
||||||
-- @type MissionTime
|
-- @type MissionTime
|
||||||
-- @extends #number
|
-- @extends #number Time in seconds.
|
||||||
|
|
||||||
|
|
||||||
--- Distance is given in meters.
|
--- Distance is given in meters.
|
||||||
-- @type Distance
|
-- @type Distance
|
||||||
-- @extends #number
|
-- @extends #number Distance in meters.
|
||||||
|
|
||||||
--- Angle is given in radians.
|
--- Angle is given in radians.
|
||||||
-- @type Angle
|
-- @type Angle
|
||||||
-- @extends #number
|
-- @extends #number Angle in radians.
|
||||||
|
|
||||||
--- Azimuth is an angle of rotation around world axis y counter-clockwise.
|
--- Azimuth is an angle of rotation around world axis y counter-clockwise.
|
||||||
-- @type Azimuth
|
-- @type Azimuth
|
||||||
-- @extends #number
|
-- @extends #number Angle in radians.
|
||||||
|
|
||||||
--- Mass is given in kilograms.
|
--- Mass is given in kilograms.
|
||||||
-- @type Mass
|
-- @type Mass
|
||||||
@@ -401,15 +406,15 @@ do -- Types
|
|||||||
|
|
||||||
--- Position is a composite structure. It consists of both coordinate vector and orientation matrix. Position3 (also known as "Pos3" for short) is a table that has following format:
|
--- Position is a composite structure. It consists of both coordinate vector and orientation matrix. Position3 (also known as "Pos3" for short) is a table that has following format:
|
||||||
-- @type Position3
|
-- @type Position3
|
||||||
-- @field #Vec3 p
|
-- @field #Vec3 p 3D position vector.
|
||||||
-- @field #Vec3 x
|
-- @field #Vec3 x Orientation component of vector pointing East.
|
||||||
-- @field #Vec3 y
|
-- @field #Vec3 y Orientation component of vector pointing up.
|
||||||
-- @field #Vec3 z
|
-- @field #Vec3 z Orientation component of vector pointing North.
|
||||||
|
|
||||||
--- 3-dimensional box.
|
--- 3-dimensional box.
|
||||||
-- @type Box3
|
-- @type Box3
|
||||||
-- @field #Vec3 min
|
-- @field #Vec3 min Min.
|
||||||
-- @field #Vec3 max
|
-- @field #Vec3 max Max
|
||||||
|
|
||||||
--- Each object belongs to a type. Object type is a named couple of properties those independent of mission and common for all units of the same type. Name of unit type is a string. Samples of unit type: "Su-27", "KAMAZ" and "M2 Bradley".
|
--- Each object belongs to a type. Object type is a named couple of properties those independent of mission and common for all units of the same type. Name of unit type is a string. Samples of unit type: "Su-27", "KAMAZ" and "M2 Bradley".
|
||||||
-- @type TypeName
|
-- @type TypeName
|
||||||
@@ -514,7 +519,7 @@ do -- Object
|
|||||||
--- Returns object coordinates for current time.
|
--- Returns object coordinates for current time.
|
||||||
-- @function [parent=#Object] getPoint
|
-- @function [parent=#Object] getPoint
|
||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
-- @return #Vec3
|
-- @return #Vec3 3D position vector with x,y,z components.
|
||||||
|
|
||||||
--- Returns object position for current time.
|
--- Returns object position for current time.
|
||||||
-- @function [parent=#Object] getPosition
|
-- @function [parent=#Object] getPosition
|
||||||
@@ -524,7 +529,7 @@ do -- Object
|
|||||||
--- Returns the unit's velocity vector.
|
--- Returns the unit's velocity vector.
|
||||||
-- @function [parent=#Object] getVelocity
|
-- @function [parent=#Object] getVelocity
|
||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
-- @return #Vec3
|
-- @return #Vec3 3D velocity vector.
|
||||||
|
|
||||||
--- Returns true if the unit is in air.
|
--- Returns true if the unit is in air.
|
||||||
-- @function [parent=#Object] inAir
|
-- @function [parent=#Object] inAir
|
||||||
@@ -731,7 +736,66 @@ do -- Airbase
|
|||||||
|
|
||||||
end -- Airbase
|
end -- Airbase
|
||||||
|
|
||||||
|
do -- Spot
|
||||||
|
|
||||||
|
--- [DCS Class Spot](https://wiki.hoggitworld.com/view/DCS_Class_Spot)
|
||||||
|
-- Represents a spot from laser or IR-pointer.
|
||||||
|
-- @type Spot
|
||||||
|
-- @field #Spot.Category Category enum that stores spot categories.
|
||||||
|
|
||||||
|
--- Enum that stores spot categories.
|
||||||
|
-- @type Spot.Category
|
||||||
|
-- @field #string INFRA_RED
|
||||||
|
-- @field #string LASER
|
||||||
|
|
||||||
|
|
||||||
|
--- Creates a laser ray emanating from the given object to a point in 3d space.
|
||||||
|
-- @function [parent=#Spot] createLaser
|
||||||
|
-- @param DCS#Object Source The source object of the laser.
|
||||||
|
-- @param DCS#Vec3 LocalRef An optional 3D offset for the source.
|
||||||
|
-- @param DCS#Vec3 Vec3 Target coordinate where the ray is pointing at.
|
||||||
|
-- @param #number LaserCode Any 4 digit number between 1111 and 1788.
|
||||||
|
-- @return #Spot
|
||||||
|
|
||||||
|
--- Creates an infrared ray emanating from the given object to a point in 3d space. Can be seen with night vision goggles.
|
||||||
|
-- @function [parent=#Spot] createInfraRed
|
||||||
|
-- @param DCS#Object Source Source position of the IR ray.
|
||||||
|
-- @param DCS#Vec3 LocalRef An optional 3D offset for the source.
|
||||||
|
-- @param DCS#Vec3 Vec3 Target coordinate where the ray is pointing at.
|
||||||
|
-- @return #Spot
|
||||||
|
|
||||||
|
--- Returns a vec3 table of the x, y, and z coordinates for the position of the given object in 3D space. Coordinates are dependent on the position of the maps origin.
|
||||||
|
-- @function [parent=#Spot] getPoint
|
||||||
|
-- @param #Spot self
|
||||||
|
-- @return DCS#Vec3 Point in 3D, where the beam is pointing at.
|
||||||
|
|
||||||
|
--- Sets the destination point from which the source of the spot is drawn toward.
|
||||||
|
-- @function [parent=#Spot] setPoint
|
||||||
|
-- @param #Spot self
|
||||||
|
-- @param DCS#Vec3 Vec3 Point in 3D, where the beam is pointing at.
|
||||||
|
|
||||||
|
--- Returns the number that is used to define the laser code for which laser designation can track.
|
||||||
|
-- @function [parent=#Spot] getCode
|
||||||
|
-- @param #Spot self
|
||||||
|
-- @return #number Code The laser code used.
|
||||||
|
|
||||||
|
--- Sets the number that is used to define the laser code for which laser designation can track.
|
||||||
|
-- @function [parent=#Spot] setCode
|
||||||
|
-- @param #Spot self
|
||||||
|
-- @param #number Code The laser code. Default value is 1688.
|
||||||
|
|
||||||
|
--- Destroys the spot.
|
||||||
|
-- @function [parent=#Spot] destroy
|
||||||
|
-- @param #Spot self
|
||||||
|
|
||||||
|
--- Gets the category of the spot (laser or IR).
|
||||||
|
-- @function [parent=#Spot] getCategory
|
||||||
|
-- @param #Spot self
|
||||||
|
-- @return #string Category.
|
||||||
|
|
||||||
|
Spot = {} --#Spot
|
||||||
|
|
||||||
|
end -- Spot
|
||||||
|
|
||||||
do -- Controller
|
do -- Controller
|
||||||
--- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
|
--- Controller is an object that performs A.I.-routines. Other words controller is an instance of A.I.. Controller stores current main task, active enroute tasks and behavior options. Controller performs commands. Please, read DCS A-10C GUI Manual EN.pdf chapter "Task Planning for Unit Groups", page 91 to understand A.I. system of DCS:A-10C.
|
||||||
@@ -1088,6 +1152,10 @@ do -- Unit
|
|||||||
-- @param #Unit self
|
-- @param #Unit self
|
||||||
-- @return #Unit.Desc
|
-- @return #Unit.Desc
|
||||||
|
|
||||||
|
--- GROUND - Switch on/off radar emissions
|
||||||
|
-- @function [parent=#Unit] enableEmission
|
||||||
|
-- @param #Unit self
|
||||||
|
-- @param #boolean switch
|
||||||
|
|
||||||
Unit = {} --#Unit
|
Unit = {} --#Unit
|
||||||
|
|
||||||
@@ -1158,7 +1226,7 @@ do -- Group
|
|||||||
-- @param #Group self
|
-- @param #Group self
|
||||||
-- @return #number
|
-- @return #number
|
||||||
|
|
||||||
--- Returns initial size of the group. If some of the units will be destroyed, initial size of the group will not be changed. Initial size limits the unitNumber parameter for Group.getUnit() function.
|
--- Returns initial size of the group. If some of the units will be destroyed, initial size of the group will not be changed; Initial size limits the unitNumber parameter for Group.getUnit() function.
|
||||||
-- @function [parent=#Group] getInitialSize
|
-- @function [parent=#Group] getInitialSize
|
||||||
-- @param #Group self
|
-- @param #Group self
|
||||||
-- @return #number
|
-- @return #number
|
||||||
@@ -1173,6 +1241,11 @@ do -- Group
|
|||||||
-- @param #Group self
|
-- @param #Group self
|
||||||
-- @return #Controller
|
-- @return #Controller
|
||||||
|
|
||||||
|
--- GROUND - Switch on/off radar emissions
|
||||||
|
-- @function [parent=#Group] enableEmission
|
||||||
|
-- @param #Group self
|
||||||
|
-- @param #boolean switch
|
||||||
|
|
||||||
Group = {} --#Group
|
Group = {} --#Group
|
||||||
|
|
||||||
end -- Group
|
end -- Group
|
||||||
|
|||||||
@@ -693,7 +693,7 @@ ARTY.db={
|
|||||||
|
|
||||||
--- Arty script version.
|
--- Arty script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ARTY.version="1.1.7"
|
ARTY.version="1.2.0"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -1146,12 +1146,11 @@ end
|
|||||||
-- @param alias (Optional) Alias name the group will be calling itself when sending messages. Default is the group name.
|
-- @param alias (Optional) Alias name the group will be calling itself when sending messages. Default is the group name.
|
||||||
-- @return #ARTY ARTY object or nil if group does not exist or is not a ground or naval group.
|
-- @return #ARTY ARTY object or nil if group does not exist or is not a ground or naval group.
|
||||||
function ARTY:NewFromCargoGroup(cargogroup, alias)
|
function ARTY:NewFromCargoGroup(cargogroup, alias)
|
||||||
BASE:F2({cargogroup=cargogroup, alias=alias})
|
|
||||||
|
|
||||||
if cargogroup then
|
if cargogroup then
|
||||||
BASE:T(self.lid..string.format("ARTY script version %s. Added CARGO group %s.", ARTY.version, cargogroup:GetName()))
|
BASE:T(string.format("ARTY script version %s. Added CARGO group %s.", ARTY.version, cargogroup:GetName()))
|
||||||
else
|
else
|
||||||
BASE:E(self.lid.."ERROR: Requested ARTY CARGO GROUP does not exist! (Has to be a MOOSE CARGO(!) group.)")
|
BASE:E("ERROR: Requested ARTY CARGO GROUP does not exist! (Has to be a MOOSE CARGO(!) group.)")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2766,16 +2765,10 @@ function ARTY:onafterStatus(Controllable, From, Event, To)
|
|||||||
self:_EventFromTo("onafterStatus", Event, From, To)
|
self:_EventFromTo("onafterStatus", Event, From, To)
|
||||||
|
|
||||||
-- Get ammo.
|
-- Get ammo.
|
||||||
local ntot, nshells, nrockets, nmissiles=self:GetAmmo()
|
local nammo, nshells, nrockets, nmissiles=self:GetAmmo()
|
||||||
|
|
||||||
-- FSM state.
|
|
||||||
local fsmstate=self:GetState()
|
|
||||||
self:I(self.lid..string.format("Status %s, Ammo total=%d: shells=%d [smoke=%d, illu=%d, nukes=%d*%.3f kT], rockets=%d, missiles=%d", fsmstate, ntot, nshells, self.Nsmoke, self.Nillu, self.Nukes, self.nukewarhead/1000000, nrockets, nmissiles))
|
|
||||||
|
|
||||||
if self.Controllable and self.Controllable:IsAlive() then
|
|
||||||
|
|
||||||
-- We have a cargo group ==> check if group was loaded into a carrier.
|
-- We have a cargo group ==> check if group was loaded into a carrier.
|
||||||
if self.cargogroup then
|
if self.iscargo and self.cargogroup then
|
||||||
if self.cargogroup:IsLoaded() and not self:is("InTransit") then
|
if self.cargogroup:IsLoaded() and not self:is("InTransit") then
|
||||||
-- Group is now InTransit state. Current target is canceled.
|
-- Group is now InTransit state. Current target is canceled.
|
||||||
self:T(self.lid..string.format("Group %s has been loaded into a carrier and is now transported.", self.alias))
|
self:T(self.lid..string.format("Group %s has been loaded into a carrier and is now transported.", self.alias))
|
||||||
@@ -2787,17 +2780,17 @@ function ARTY:onafterStatus(Controllable, From, Event, To)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- FSM state.
|
||||||
|
local fsmstate=self:GetState()
|
||||||
|
self:T(self.lid..string.format("Status %s, Ammo total=%d: shells=%d [smoke=%d, illu=%d, nukes=%d*%.3f kT], rockets=%d, missiles=%d", fsmstate, nammo, nshells, self.Nsmoke, self.Nillu, self.Nukes, self.nukewarhead/1000000, nrockets, nmissiles))
|
||||||
|
|
||||||
|
if self.Controllable and self.Controllable:IsAlive() then
|
||||||
|
|
||||||
-- Debug current status info.
|
-- Debug current status info.
|
||||||
if self.Debug then
|
if self.Debug then
|
||||||
self:_StatusReport()
|
self:_StatusReport()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Group is being transported as cargo ==> skip everything and check again in 5 seconds.
|
|
||||||
if self:is("InTransit") then
|
|
||||||
self:__Status(-5)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Group on the move.
|
-- Group on the move.
|
||||||
if self:is("Moving") then
|
if self:is("Moving") then
|
||||||
self:T2(self.lid..string.format("%s: Moving", Controllable:GetName()))
|
self:T2(self.lid..string.format("%s: Moving", Controllable:GetName()))
|
||||||
@@ -2884,7 +2877,7 @@ function ARTY:onafterStatus(Controllable, From, Event, To)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Get ammo.
|
-- Get ammo.
|
||||||
local nammo, nshells, nrockets, nmissiles=self:GetAmmo()
|
--local nammo, nshells, nrockets, nmissiles=self:GetAmmo()
|
||||||
|
|
||||||
-- Check if we have a target in the queue for which weapons are still available.
|
-- Check if we have a target in the queue for which weapons are still available.
|
||||||
local gotsome=false
|
local gotsome=false
|
||||||
@@ -2914,9 +2907,23 @@ function ARTY:onafterStatus(Controllable, From, Event, To)
|
|||||||
-- Call status again in ~10 sec.
|
-- Call status again in ~10 sec.
|
||||||
self:__Status(self.StatusInterval)
|
self:__Status(self.StatusInterval)
|
||||||
|
|
||||||
|
elseif self.iscargo then
|
||||||
|
|
||||||
|
-- We have a cargo group ==> check if group was loaded into a carrier.
|
||||||
|
if self.cargogroup and self.cargogroup:IsAlive() then
|
||||||
|
|
||||||
|
-- Group is being transported as cargo ==> skip everything and check again in 5 seconds.
|
||||||
|
if self:is("InTransit") then
|
||||||
|
self:__Status(-5)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
self:E(self.lid..string.format("Arty group %s is not alive!", self.groupname))
|
self:E(self.lid..string.format("Arty group %s is not alive!", self.groupname))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -4814,7 +4821,8 @@ function ARTY:_CheckShootingStarted()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check if we waited long enough and no shot was fired.
|
-- Check if we waited long enough and no shot was fired.
|
||||||
if dt > self.WaitForShotTime and self.Nshots==0 then
|
--if dt > self.WaitForShotTime and self.Nshots==0 then
|
||||||
|
if dt > self.WaitForShotTime and (self.Nshots==0 or self.currentTarget.nshells >= self.Nshots) then --https://github.com/FlightControl-Master/MOOSE/issues/1356
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("%s, no shot event after %d seconds. Removing current target %s from list.", self.groupname, self.WaitForShotTime, name))
|
self:T(self.lid..string.format("%s, no shot event after %d seconds. Removing current target %s from list.", self.groupname, self.WaitForShotTime, name))
|
||||||
|
|||||||
@@ -1001,7 +1001,13 @@ do -- DESIGNATE
|
|||||||
local ID = self.Detection:GetDetectedItemID( DetectedItem )
|
local ID = self.Detection:GetDetectedItemID( DetectedItem )
|
||||||
local MenuText = ID --.. ", " .. Coord:ToStringA2G( AttackGroup )
|
local MenuText = ID --.. ", " .. Coord:ToStringA2G( AttackGroup )
|
||||||
|
|
||||||
|
-- Use injected MenuName from TaskA2GDispatcher if using same Detection Object
|
||||||
|
if DetectedItem.DesignateMenuName then
|
||||||
|
MenuText = string.format( "(%3s) %s", Designating, DetectedItem.DesignateMenuName )
|
||||||
|
else
|
||||||
MenuText = string.format( "(%3s) %s", Designating, MenuText )
|
MenuText = string.format( "(%3s) %s", Designating, MenuText )
|
||||||
|
end
|
||||||
|
|
||||||
local DetectedMenu = MENU_GROUP_DELAYED:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
local DetectedMenu = MENU_GROUP_DELAYED:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||||
|
|
||||||
-- Build the Lasing menu.
|
-- Build the Lasing menu.
|
||||||
|
|||||||
961
Moose Development/Moose/Functional/Mantis.lua
Normal file
961
Moose Development/Moose/Functional/Mantis.lua
Normal file
@@ -0,0 +1,961 @@
|
|||||||
|
--- **Functional** -- Modular, Automatic and Network capable Targeting and Interception System for Air Defenses
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- **MANTIS** - Moose derived Modular, Automatic and Network capable Targeting and Interception System
|
||||||
|
-- Controls a network of SAM sites. Use detection to switch on the AA site closest to the enemy
|
||||||
|
-- Leverage evasiveness from SEAD
|
||||||
|
-- Leverage attack range setup added by DCS in 11/20
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Missions:
|
||||||
|
--
|
||||||
|
-- ### [MANTIS - Modular, Automatic and Network capable Targeting and Interception System](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/MTS%20-%20Mantis/MTS-010%20-%20Basic%20Mantis%20Demo)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author : **applevangelist **
|
||||||
|
--
|
||||||
|
-- @module Functional.Mantis
|
||||||
|
-- @image Functional.Mantis.jpg
|
||||||
|
|
||||||
|
-- Date: Apr 2021
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
--- **MANTIS** class, extends #Core.Base#BASE
|
||||||
|
-- @type MANTIS
|
||||||
|
-- @field #string Classname
|
||||||
|
-- @field #string name Name of this Mantis
|
||||||
|
-- @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 #string EWR_Templates_Prefix Prefix to build the #SET_GROUP for EWR group
|
||||||
|
-- @field Core.Set#SET_GROUP EWR_Group The EWR #SET_GROUP
|
||||||
|
-- @field Core.Set#SET_GROUP Adv_EWR_Group The EWR #SET_GROUP used for advanced mode
|
||||||
|
-- @field #string HQ_Template_CC The ME name of the HQ object
|
||||||
|
-- @field Wrapper.Group#GROUP HQ_CC The #GROUP object of the HQ
|
||||||
|
-- @field #table SAM_Table Table of SAM sites
|
||||||
|
-- @field #string lid Prefix for logging
|
||||||
|
-- @field Functional.Detection#DETECTION_AREAS Detection The #DETECTION_AREAS object for EWR
|
||||||
|
-- @field Functional.Detection#DETECTION_AREAS AWACS_Detection The #DETECTION_AREAS object for AWACS
|
||||||
|
-- @field #boolean debug Switch on extra messages
|
||||||
|
-- @field #boolean verbose Switch on extra logging
|
||||||
|
-- @field #number checkradius Radius of the SAM sites
|
||||||
|
-- @field #number grouping Radius to group detected objects
|
||||||
|
-- @field #number acceptrange Radius of the EWR detection
|
||||||
|
-- @field #number detectinterval Interval in seconds for the target detection
|
||||||
|
-- @field #number engagerange Firing engage range of the SAMs, see [https://wiki.hoggitworld.com/view/DCS_option_engagementRange]
|
||||||
|
-- @field #boolean autorelocate Relocate HQ and EWR groups in random intervals. Note: You need to select units for this which are *actually mobile*
|
||||||
|
-- @field #boolean advanced Use advanced mode, will decrease reactivity of MANTIS, if HQ and/or EWR network dies. Set SAMs to RED state if both are dead. Requires usage of an HQ object
|
||||||
|
-- @field #number adv_ratio Percentage to use for advanced mode, defaults to 100%
|
||||||
|
-- @field #number adv_state Advanced mode state tracker
|
||||||
|
-- @field #boolean advAwacs Boolean switch to use Awacs as a separate detection stream
|
||||||
|
-- @field #number awacsrange Detection range of an optional Awacs unit
|
||||||
|
-- @field #boolean UseAIOnOff Decide if we are using AI on/off (true) or AlarmState red/green (default)
|
||||||
|
-- @field Functional.Shorad#SHORAD Shorad SHORAD Object, if available
|
||||||
|
-- @field #boolean ShoradLink If true, #MANTIS has #SHORAD enabled
|
||||||
|
-- @field #number ShoradTime Timer in seconds, how long #SHORAD will be active after a detection inside of the defense range
|
||||||
|
-- @field #number ShoradActDistance Distance of an attacker in meters from a Mantis SAM site, on which Shorad will be switched on. Useful to not give away Shorad sites too early. Default 15km. Should be smaller than checkradius.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
|
--- *The worst thing that can happen to a good cause is, not to be skillfully attacked, but to be ineptly defended.* - Frédéric Bastiat
|
||||||
|
--
|
||||||
|
-- Simple Class for a more intelligent Air Defense System
|
||||||
|
--
|
||||||
|
-- #MANTIS
|
||||||
|
-- Moose derived Modular, Automatic and Network capable Targeting and Interception System.
|
||||||
|
-- Controls a network of SAM sites. Use detection to switch on the AA site closest to the enemy.
|
||||||
|
-- Leverage evasiveness from @{Functional.Sead#SEAD}.
|
||||||
|
-- Leverage attack range setup added by DCS in 11/20.
|
||||||
|
--
|
||||||
|
-- Set up your SAM sites in the mission editor. Name the groups with common prefix like "Red SAM".
|
||||||
|
-- Set up your EWR system in the mission editor. Name the groups with common prefix like "Red EWR". Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
|
||||||
|
-- [optional] Set up your HQ. Can be any group, e.g. a command vehicle.
|
||||||
|
--
|
||||||
|
-- # 1. Basic tactical considerations when setting up your SAM sites
|
||||||
|
--
|
||||||
|
-- ## 1.1 Radar systems and AWACS
|
||||||
|
--
|
||||||
|
-- Typically, your setup should consist of EWR (early warning) radars to detect and track targets, accompanied by AWACS if your scenario forsees that. Ensure that your EWR radars have a good coverage of the area you want to track.
|
||||||
|
-- **Location** is of highest importantance here. Whilst AWACS in DCS has almost the "all seeing eye", EWR don't have that. Choose your location wisely, against a mountain backdrop or inside a valley even the best EWR system
|
||||||
|
-- doesn't work well. Prefer higher-up locations with a good view; use F7 in-game to check where you actually placed your EWR and have a look around. Apart from the obvious choice, do also consider other radar units
|
||||||
|
-- for this role, most have "SR" (search radar) or "STR" (search and track radar) in their names, use the encyclopedia to see what they actually do.
|
||||||
|
--
|
||||||
|
-- ## 1.2 SAM sites
|
||||||
|
--
|
||||||
|
-- Typically your SAM should cover all attack ranges. The closer the enemy gets, the more systems you will need to deploy to defend your location. Use a combination of long-range systems like the SA-10/11, midrange like SA-6 and short-range like
|
||||||
|
-- SA-2 for defense (Patriot, Hawk, Gepard, Blindfire for the blue side). For close-up defense and defense against HARMs or low-flying aircraft, helicopters it is also advisable to deploy SA-15 TOR systems, Shilka, Strela and Tunguska units, as well as manpads (Think Gepard, Avenger, Chaparral,
|
||||||
|
-- Linebacker, Roland systems for the blue side). If possible, overlap ranges for mutual coverage.
|
||||||
|
--
|
||||||
|
-- ## 1.3 Typical problems
|
||||||
|
--
|
||||||
|
-- Often times, people complain because the detection cannot "see" oncoming targets and/or Mantis switches on too late. Three typial problems here are
|
||||||
|
--
|
||||||
|
-- * bad placement of radar units,
|
||||||
|
-- * overestimation how far units can "see" and
|
||||||
|
-- * not taking into account that a SAM site will take (e.g for a SA-6) 30-40 seconds between switching to RED, acquiring the target and firing.
|
||||||
|
--
|
||||||
|
-- An attacker doing 350knots will cover ca 180meters/second or thus more than 6km until the SA-6 fires. Use triggers zones and the ruler in the missione editor to understand distances and zones. Take into account that the ranges given by the circles
|
||||||
|
-- in the mission editor are absolute maximum ranges; in-game this is rather 50-75% of that depending on the system. Fiddle with placement and options to see what works best for your scenario, and remember **everything in here is in meters**.
|
||||||
|
--
|
||||||
|
-- # 2. Start up your MANTIS with a basic setting
|
||||||
|
--
|
||||||
|
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
|
||||||
|
-- `myredmantis:Start()`
|
||||||
|
--
|
||||||
|
-- [optional] Use
|
||||||
|
--
|
||||||
|
-- * `MANTIS:SetEWRGrouping(radius)`
|
||||||
|
-- * `MANTIS:SetEWRRange(radius)`
|
||||||
|
-- * `MANTIS:SetSAMRadius(radius)`
|
||||||
|
-- * `MANTIS:SetDetectInterval(interval)`
|
||||||
|
-- * `MANTIS:SetAutoRelocate(hq, ewr)`
|
||||||
|
--
|
||||||
|
-- before starting #MANTIS to fine-tune your setup.
|
||||||
|
--
|
||||||
|
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
|
||||||
|
--
|
||||||
|
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
||||||
|
-- `mybluemantis:Start()`
|
||||||
|
--
|
||||||
|
-- # 3. Default settings
|
||||||
|
--
|
||||||
|
-- By default, the following settings are active:
|
||||||
|
--
|
||||||
|
-- * SAM_Templates_Prefix = "Red SAM" - SAM site group names in the mission editor begin with "Red SAM"
|
||||||
|
-- * EWR_Templates_Prefix = "Red EWR" - EWR group names in the mission editor begin with "Red EWR" - can also be combined with an AWACS unit
|
||||||
|
-- * checkradius = 25000 (meters) - SAMs will engage enemy flights, if they are within a 25km around each SAM site - `MANTIS:SetSAMRadius(radius)`
|
||||||
|
-- * grouping = 5000 (meters) - Detection (EWR) will group enemy flights to areas of 5km for tracking - `MANTIS:SetEWRGrouping(radius)`
|
||||||
|
-- * acceptrange = 80000 (meters) - Detection (EWR) will on consider flights inside a 80km radius - `MANTIS:SetEWRRange(radius)`
|
||||||
|
-- * detectinterval = 30 (seconds) - MANTIS will decide every 30 seconds which SAM to activate - `MANTIS:SetDetectInterval(interval)`
|
||||||
|
-- * engagerange = 85 (percent) - SAMs will only fire if flights are inside of a 85% radius of their max firerange - `MANTIS:SetSAMRange(range)`
|
||||||
|
-- * dynamic = false - Group filtering is set to once, i.e. newly added groups will not be part of the setup by default - `MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic)`
|
||||||
|
-- * autorelocate = false - HQ and (mobile) EWR system will not relocate in random intervals between 30mins and 1 hour - `MANTIS:SetAutoRelocate(hq, ewr)`
|
||||||
|
-- * debug = false - Debugging reports on screen are set to off - `MANTIS:Debug(onoff)`
|
||||||
|
--
|
||||||
|
-- # 4. Advanced Mode
|
||||||
|
--
|
||||||
|
-- Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Awacs is counted as one EWR unit. It will set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option.
|
||||||
|
--
|
||||||
|
-- E.g. `mymantis:SetAdvancedMode( true, 90 )`
|
||||||
|
--
|
||||||
|
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
||||||
|
--
|
||||||
|
-- # 5. Integrate SHORAD
|
||||||
|
--
|
||||||
|
-- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in
|
||||||
|
-- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so:
|
||||||
|
--
|
||||||
|
-- `local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()`
|
||||||
|
-- `myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")`
|
||||||
|
-- `-- now set up MANTIS`
|
||||||
|
-- `mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
||||||
|
-- `mymantis:AddShorad(myshorad,720)`
|
||||||
|
-- `mymantis:Start()`
|
||||||
|
--
|
||||||
|
-- and (optionally) remove the link later on with
|
||||||
|
--
|
||||||
|
-- `mymantis:RemoveShorad()`
|
||||||
|
--
|
||||||
|
-- @field #MANTIS
|
||||||
|
MANTIS = {
|
||||||
|
ClassName = "MANTIS",
|
||||||
|
name = "mymantis",
|
||||||
|
SAM_Templates_Prefix = "",
|
||||||
|
SAM_Group = nil,
|
||||||
|
EWR_Templates_Prefix = "",
|
||||||
|
EWR_Group = nil,
|
||||||
|
Adv_EWR_Group = nil,
|
||||||
|
HQ_Template_CC = "",
|
||||||
|
HQ_CC = nil,
|
||||||
|
SAM_Table = {},
|
||||||
|
lid = "",
|
||||||
|
Detection = nil,
|
||||||
|
AWACS_Detection = nil,
|
||||||
|
debug = false,
|
||||||
|
checkradius = 25000,
|
||||||
|
grouping = 5000,
|
||||||
|
acceptrange = 80000,
|
||||||
|
detectinterval = 30,
|
||||||
|
engagerange = 75,
|
||||||
|
autorelocate = false,
|
||||||
|
advanced = false,
|
||||||
|
adv_ratio = 100,
|
||||||
|
adv_state = 0,
|
||||||
|
AWACS_Prefix = "",
|
||||||
|
advAwacs = false,
|
||||||
|
verbose = false,
|
||||||
|
awacsrange = 250000,
|
||||||
|
Shorad = nil,
|
||||||
|
ShoradLink = false,
|
||||||
|
ShoradTime = 600,
|
||||||
|
ShoradActDistance = 15000,
|
||||||
|
UseAIOnOff = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- MANTIS System
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
--- Function to instantiate a new object of class MANTIS
|
||||||
|
--@param #MANTIS self
|
||||||
|
--@param #string name Name of this MANTIS for reporting
|
||||||
|
--@param #string samprefix Prefixes for the SAM groups from the ME, e.g. all groups starting with "Red Sam..."
|
||||||
|
--@param #string ewrprefix Prefixes for the EWR groups from the ME, e.g. all groups starting with "Red EWR..."
|
||||||
|
--@param #string hq Group name of your HQ (optional)
|
||||||
|
--@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 #string awacs Group name of your Awacs (optional)
|
||||||
|
--@param #boolean AIOnOff Make MANTIS switch AI on and off instead of changing the alarm state between RED and GREEN (optional)
|
||||||
|
--@return #MANTIS self
|
||||||
|
--@usage Start up your MANTIS with a basic setting
|
||||||
|
--
|
||||||
|
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
|
||||||
|
-- `myredmantis:Start()`
|
||||||
|
--
|
||||||
|
-- [optional] Use
|
||||||
|
--
|
||||||
|
-- * `MANTIS:SetEWRGrouping(radius)`
|
||||||
|
-- * `MANTIS:SetEWRRange(radius)`
|
||||||
|
-- * `MANTIS:SetSAMRadius(radius)`
|
||||||
|
-- * `MANTIS:SetDetectInterval(interval)`
|
||||||
|
-- * `MANTIS:SetAutoRelocate(hq, ewr)`
|
||||||
|
--
|
||||||
|
-- before starting #MANTIS to fine-tune your setup.
|
||||||
|
--
|
||||||
|
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
|
||||||
|
--
|
||||||
|
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
||||||
|
-- `mybluemantis:Start()`
|
||||||
|
--
|
||||||
|
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, AIOnOff)
|
||||||
|
|
||||||
|
-- DONE: Create some user functions for these
|
||||||
|
-- DONE: Make HQ useful
|
||||||
|
-- DONE: Set SAMs to auto if EWR dies
|
||||||
|
-- DONE: Refresh SAM table in dynamic mode
|
||||||
|
-- DONE: Treat Awacs separately, since they might be >80km off site
|
||||||
|
|
||||||
|
self.name = name or "mymantis"
|
||||||
|
self.SAM_Templates_Prefix = samprefix or "Red SAM"
|
||||||
|
self.EWR_Templates_Prefix = ewrprefix or "Red EWR"
|
||||||
|
self.HQ_Template_CC = hq or nil
|
||||||
|
self.Coalition = coaltion or "red"
|
||||||
|
self.SAM_Table = {}
|
||||||
|
self.dynamic = dynamic or false
|
||||||
|
self.checkradius = 25000
|
||||||
|
self.grouping = 5000
|
||||||
|
self.acceptrange = 80000
|
||||||
|
self.detectinterval = 30
|
||||||
|
self.engagerange = 75
|
||||||
|
self.autorelocate = false
|
||||||
|
self.autorelocateunits = { HQ = false, EWR = false}
|
||||||
|
self.advanced = false
|
||||||
|
self.adv_ratio = 100
|
||||||
|
self.adv_state = 0
|
||||||
|
self.verbose = false
|
||||||
|
self.Adv_EWR_Group = nil
|
||||||
|
self.AWACS_Prefix = awacs or nil
|
||||||
|
self.awacsrange = 250000 --DONE: 250km, User Function to change
|
||||||
|
self.Shorad = nil
|
||||||
|
self.ShoradLink = false
|
||||||
|
self.ShoradTime = 600
|
||||||
|
self.ShoradActDistance = 15000
|
||||||
|
-- TODO: add emissions on/off when available .... in 2 weeks
|
||||||
|
self.UseAIOnOff = AIOnOff or false
|
||||||
|
|
||||||
|
if type(awacs) == "string" then
|
||||||
|
self.advAwacs = true
|
||||||
|
else
|
||||||
|
self.advAwacs = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
local self = BASE:Inherit(self, BASE:New()) -- #MANTIS
|
||||||
|
|
||||||
|
-- Set the string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("MANTIS %s | ", self.name)
|
||||||
|
|
||||||
|
-- Debug trace.
|
||||||
|
if self.debug then
|
||||||
|
BASE:TraceOnOff(true)
|
||||||
|
BASE:TraceClass(self.ClassName)
|
||||||
|
--BASE:TraceClass("SEAD")
|
||||||
|
BASE:TraceLevel(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.dynamic then
|
||||||
|
-- Set SAM SET_GROUP
|
||||||
|
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition):FilterStart()
|
||||||
|
-- Set EWR SET_GROUP
|
||||||
|
self.EWR_Group = SET_GROUP:New():FilterPrefixes({self.SAM_Templates_Prefix,self.EWR_Templates_Prefix}):FilterCoalitions(self.Coalition):FilterStart()
|
||||||
|
else
|
||||||
|
-- Set SAM SET_GROUP
|
||||||
|
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition):FilterOnce()
|
||||||
|
-- Set EWR SET_GROUP
|
||||||
|
self.EWR_Group = SET_GROUP:New():FilterPrefixes({self.SAM_Templates_Prefix,self.EWR_Templates_Prefix}):FilterCoalitions(self.Coalition):FilterOnce()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set up CC
|
||||||
|
if self.HQ_Template_CC then
|
||||||
|
self.HQ_CC = GROUP:FindByName(self.HQ_Template_CC)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- @field #string version
|
||||||
|
self.version="0.4.0"
|
||||||
|
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- MANTIS helper functions
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- [internal] Function to get the self.SAM_Table
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #table table
|
||||||
|
function MANTIS:_GetSAMTable()
|
||||||
|
return self.SAM_Table
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [internal] Function to set the self.SAM_Table
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #MANTIS self
|
||||||
|
function MANTIS:_SetSAMTable(table)
|
||||||
|
self.SAM_Table = table
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set the grouping radius of the detection in meters
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number radius Radius upon which detected objects will be grouped
|
||||||
|
function MANTIS:SetEWRGrouping(radius)
|
||||||
|
local radius = radius or 5000
|
||||||
|
self.grouping = radius
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set the detection radius of the EWR in meters
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number radius Radius of the EWR detection zone
|
||||||
|
function MANTIS:SetEWRRange(radius)
|
||||||
|
local radius = radius or 80000
|
||||||
|
self.acceptrange = radius
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set switch-on/off zone for the SAM sites in meters
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number radius Radius of the firing zone
|
||||||
|
function MANTIS:SetSAMRadius(radius)
|
||||||
|
local radius = radius or 25000
|
||||||
|
self.checkradius = radius
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set SAM firing engage range, 0-100 percent, e.g. 75
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number range Percent of the max fire range
|
||||||
|
function MANTIS:SetSAMRange(range)
|
||||||
|
local range = range or 75
|
||||||
|
if range < 0 or range > 100 then
|
||||||
|
range = 75
|
||||||
|
end
|
||||||
|
self.engagerange = range
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set a new SAM firing engage range, use this method to adjust range while running MANTIS, e.g. for different setups day and night
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number range Percent of the max fire range
|
||||||
|
function MANTIS:SetNewSAMRangeWhileRunning(range)
|
||||||
|
local range = range or 75
|
||||||
|
if range < 0 or range > 100 then
|
||||||
|
range = 75
|
||||||
|
end
|
||||||
|
self.engagerange = range
|
||||||
|
self:_RefreshSAMTable()
|
||||||
|
self.mysead.EngagementRange = range
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set switch-on/off the debug state
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #boolean onoff Set true to switch on
|
||||||
|
function MANTIS:Debug(onoff)
|
||||||
|
local onoff = onoff or false
|
||||||
|
self.debug = onoff
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to get the HQ object for further use
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return Wrapper.GROUP#GROUP The HQ #GROUP object or *nil* if it doesn't exist
|
||||||
|
function MANTIS:GetCommandCenter()
|
||||||
|
if self.HQ_CC then
|
||||||
|
return self.HQ_CC
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set separate AWACS detection instance
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #string prefix Name of the AWACS group in the mission editor
|
||||||
|
function MANTIS:SetAwacs(prefix)
|
||||||
|
if prefix ~= nil then
|
||||||
|
if type(prefix) == "string" then
|
||||||
|
self.AWACS_Prefix = prefix
|
||||||
|
self.advAwacs = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set AWACS detection range. Defaults to 250.000m (250km) - use **before** starting your Mantis!
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number range Detection range of the AWACS group
|
||||||
|
function MANTIS:SetAwacsRange(range)
|
||||||
|
local range = range or 250000
|
||||||
|
self.awacsrange = range
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set the HQ object for further use
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param Wrapper.GROUP#GROUP group The #GROUP object to be set as HQ
|
||||||
|
function MANTIS:SetCommandCenter(group)
|
||||||
|
local group = group or nil
|
||||||
|
if group ~= nil then
|
||||||
|
if type(group) == "string" then
|
||||||
|
self.HQ_CC = GROUP:FindByName(group)
|
||||||
|
self.HQ_Template_CC = group
|
||||||
|
else
|
||||||
|
self.HQ_CC = group
|
||||||
|
self.HQ_Template_CC = group:GetName()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set the detection interval
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #number interval The interval in seconds
|
||||||
|
function MANTIS:SetDetectInterval(interval)
|
||||||
|
local interval = interval or 30
|
||||||
|
self.detectinterval = interval
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set Advanded Mode
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #boolean onoff If true, will activate Advanced Mode
|
||||||
|
-- @param #number ratio [optional] Percentage to use for advanced mode, defaults to 100%
|
||||||
|
-- @usage Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option.
|
||||||
|
-- E.g. `mymantis:SetAdvancedMode(true, 90)`
|
||||||
|
function MANTIS:SetAdvancedMode(onoff, ratio)
|
||||||
|
self:F({onoff, ratio})
|
||||||
|
local onoff = onoff or false
|
||||||
|
local ratio = ratio or 100
|
||||||
|
if (type(self.HQ_Template_CC) == "string") and onoff and self.dynamic then
|
||||||
|
self.adv_ratio = ratio
|
||||||
|
self.advanced = true
|
||||||
|
self.adv_state = 0
|
||||||
|
self.Adv_EWR_Group = SET_GROUP:New():FilterPrefixes(self.EWR_Templates_Prefix):FilterCoalitions(self.Coalition):FilterStart()
|
||||||
|
env.info(string.format("***** Starting Advanced Mode MANTIS Version %s *****", self.version))
|
||||||
|
else
|
||||||
|
local text = self.lid.." Advanced Mode requires a HQ and dynamic to be set. Revisit your MANTIS:New() statement to add both."
|
||||||
|
local m= MESSAGE:New(text,10,"MANTIS",true):ToAll()
|
||||||
|
BASE:E(text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set using AI on/off instead of changing alarm state
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #boolean switch Decide if we are changing alarm state or AI state
|
||||||
|
function MANTIS:SetUsingAIOnOff(switch)
|
||||||
|
self.UseAIOnOff = switch or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Internal] Function to check if HQ is alive
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #boolean True if HQ is alive, else false
|
||||||
|
function MANTIS:_CheckHQState()
|
||||||
|
local text = self.lid.." Checking HQ State"
|
||||||
|
self:T(text)
|
||||||
|
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(text) end
|
||||||
|
-- start check
|
||||||
|
if self.advanced then
|
||||||
|
local hq = self.HQ_Template_CC
|
||||||
|
local hqgrp = GROUP:FindByName(hq)
|
||||||
|
if hqgrp then
|
||||||
|
if hqgrp:IsAlive() then -- ok we're on, hq exists and as alive
|
||||||
|
env.info(self.lid.." HQ is alive!")
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
env.info(self.lid.." HQ is dead!")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Internal] Function to check if EWR is (at least partially) alive
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #boolean True if EWR is alive, else false
|
||||||
|
function MANTIS:_CheckEWRState()
|
||||||
|
local text = self.lid.." Checking EWR State"
|
||||||
|
self:F(text)
|
||||||
|
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(text) end
|
||||||
|
-- start check
|
||||||
|
if self.advanced then
|
||||||
|
local EWR_Group = self.Adv_EWR_Group
|
||||||
|
--local EWR_Set = EWR_Group.Set
|
||||||
|
local nalive = EWR_Group:CountAlive()
|
||||||
|
if self.advAwacs then
|
||||||
|
local awacs = GROUP:FindByName(self.AWACS_Prefix)
|
||||||
|
if awacs ~= nil then
|
||||||
|
if awacs:IsAlive() then
|
||||||
|
nalive = nalive+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
env.info(self.lid..string.format(" No of EWR alive is %d", nalive))
|
||||||
|
if nalive > 0 then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Internal] Function to determine state of the advanced mode
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #number Newly calculated interval
|
||||||
|
-- @return #number Previous state for tracking 0, 1, or 2
|
||||||
|
function MANTIS:_CheckAdvState()
|
||||||
|
local text = self.lid.." Checking Advanced State"
|
||||||
|
self:F(text)
|
||||||
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(text) end
|
||||||
|
-- start check
|
||||||
|
local currstate = self.adv_state -- save curr state for comparison later
|
||||||
|
local EWR_State = self:_CheckEWRState()
|
||||||
|
local HQ_State = self:_CheckHQState()
|
||||||
|
-- set state
|
||||||
|
if EWR_State and HQ_State then -- both alive
|
||||||
|
self.adv_state = 0 --everything is fine
|
||||||
|
elseif EWR_State or HQ_State then -- one alive
|
||||||
|
self.adv_state = 1 --slow down level 1
|
||||||
|
else -- none alive
|
||||||
|
self.adv_state = 2 --slow down level 2
|
||||||
|
end
|
||||||
|
-- calculate new detectioninterval
|
||||||
|
local interval = self.detectinterval -- e.g. 30
|
||||||
|
local ratio = self.adv_ratio / 100 -- e.g. 80/100 = 0.8
|
||||||
|
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 text = self.lid..string.format(" Calculated OldState/NewState/Interval: %d / %d / %d", currstate, self.adv_state, newinterval)
|
||||||
|
self:F(text)
|
||||||
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(text) end
|
||||||
|
return newinterval, currstate
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to set autorelocation for HQ and EWR objects. Note: Units must be actually mobile in DCS!
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #boolean hq If true, will relocate HQ object
|
||||||
|
-- @param #boolean ewr If true, will relocate EWR objects
|
||||||
|
function MANTIS:SetAutoRelocate(hq, ewr)
|
||||||
|
self:F({hq, ewr})
|
||||||
|
local hqrel = hq or false
|
||||||
|
local ewrel = ewr or false
|
||||||
|
if hqrel or ewrel then
|
||||||
|
self.autorelocate = true
|
||||||
|
self.autorelocateunits = { HQ = hqrel, EWR = ewrel }
|
||||||
|
self:T({self.autorelocate, self.autorelocateunits})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [Internal] Function to execute the relocation
|
||||||
|
-- @param #MANTIS self
|
||||||
|
function MANTIS:_RelocateGroups()
|
||||||
|
self:T(self.lid.." Relocating Groups")
|
||||||
|
local text = self.lid.." Relocating Groups"
|
||||||
|
local m= MESSAGE:New(text,10,"MANTIS",true):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(text) end
|
||||||
|
if self.autorelocate then
|
||||||
|
-- relocate HQ
|
||||||
|
if self.autorelocateunits.HQ and self.HQ_CC then --only relocate if HQ exists
|
||||||
|
local _hqgrp = self.HQ_CC
|
||||||
|
self:T(self.lid.." Relocating HQ")
|
||||||
|
local text = self.lid.." Relocating HQ"
|
||||||
|
local m= MESSAGE:New(text,10,"MANTIS"):ToAll()
|
||||||
|
_hqgrp:RelocateGroundRandomInRadius(20,500,true,true)
|
||||||
|
end
|
||||||
|
--relocate EWR
|
||||||
|
-- TODO: maybe dependent on AlarmState? Observed: SA11 SR only relocates if no objects in reach
|
||||||
|
if self.autorelocateunits.EWR then
|
||||||
|
-- get EWR Group
|
||||||
|
local EWR_GRP = SET_GROUP:New():FilterPrefixes(self.EWR_Templates_Prefix):FilterCoalitions(self.Coalition):FilterOnce()
|
||||||
|
local EWR_Grps = EWR_GRP.Set --table of objects in SET_GROUP
|
||||||
|
for _,_grp in pairs (EWR_Grps) do
|
||||||
|
if _grp:IsGround() then
|
||||||
|
self:T(self.lid.." Relocating EWR ".._grp:GetName())
|
||||||
|
local text = self.lid.." Relocating EWR ".._grp:GetName()
|
||||||
|
local m= MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(text) end
|
||||||
|
_grp:RelocateGroundRandomInRadius(20,500,true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to check if any object is in the given SAM zone
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param #table dectset Table of coordinates of detected items
|
||||||
|
-- @param samcoordinate Core.Point#COORDINATE Coordinate object.
|
||||||
|
-- @return #boolean True if in any zone, else false
|
||||||
|
-- @return #number Distance Target distance in meters or zero when no object is in zone
|
||||||
|
function MANTIS:CheckObjectInZone(dectset, samcoordinate)
|
||||||
|
self:F(self.lid.."CheckObjectInZone Called")
|
||||||
|
-- check if non of the coordinate is in the given defense zone
|
||||||
|
local radius = self.checkradius
|
||||||
|
local set = dectset
|
||||||
|
for _,_coord in pairs (set) do
|
||||||
|
local coord = _coord -- get current coord to check
|
||||||
|
-- output for cross-check
|
||||||
|
local dectstring = coord:ToStringLLDMS()
|
||||||
|
local samstring = samcoordinate:ToStringLLDMS()
|
||||||
|
local targetdistance = samcoordinate:DistanceFromPointVec2(coord)
|
||||||
|
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)
|
||||||
|
if self.verbose then env.info(self.lid..text) end
|
||||||
|
-- end output to cross-check
|
||||||
|
if targetdistance <= radius then
|
||||||
|
return true, targetdistance
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to start the detection via EWR groups
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return Functional.Detection #DETECTION_AREAS The running detection set
|
||||||
|
function MANTIS:StartDetection()
|
||||||
|
self:F(self.lid.."Starting Detection")
|
||||||
|
|
||||||
|
-- start detection
|
||||||
|
local groupset = self.EWR_Group
|
||||||
|
local grouping = self.grouping or 5000
|
||||||
|
local acceptrange = self.acceptrange or 80000
|
||||||
|
local interval = self.detectinterval or 60
|
||||||
|
|
||||||
|
--@param Functional.Detection #DETECTION_AREAS _MANTISdetection [internal] The MANTIS detection object
|
||||||
|
_MANTISdetection = DETECTION_AREAS:New( groupset, grouping ) --[internal] Grouping detected objects to 5000m zones
|
||||||
|
_MANTISdetection:FilterCategories({ Unit.Category.AIRPLANE, Unit.Category.HELICOPTER })
|
||||||
|
_MANTISdetection:SetAcceptRange(acceptrange)
|
||||||
|
_MANTISdetection:SetRefreshTimeInterval(interval)
|
||||||
|
_MANTISdetection:Start()
|
||||||
|
|
||||||
|
function _MANTISdetection:OnAfterDetectedItem(From,Event,To,DetectedItem)
|
||||||
|
--BASE:I( { From, Event, To, DetectedItem })
|
||||||
|
local debug = false
|
||||||
|
if DetectedItem.IsDetected and debug then
|
||||||
|
local Coordinate = DetectedItem.Coordinate -- Core.Point#COORDINATE
|
||||||
|
local text = "MANTIS: Detection at "..Coordinate:ToStringLLDMS()
|
||||||
|
local m = MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return _MANTISdetection
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to start the detection via AWACS if defined as separate
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return Functional.Detection #DETECTION_AREAS The running detection set
|
||||||
|
function MANTIS:StartAwacsDetection()
|
||||||
|
self:F(self.lid.."Starting Awacs Detection")
|
||||||
|
|
||||||
|
-- start detection
|
||||||
|
local group = self.AWACS_Prefix
|
||||||
|
local groupset = SET_GROUP:New():FilterPrefixes(group):FilterCoalitions(self.Coalition):FilterStart()
|
||||||
|
local grouping = self.grouping or 5000
|
||||||
|
--local acceptrange = self.acceptrange or 80000
|
||||||
|
local interval = self.detectinterval or 60
|
||||||
|
|
||||||
|
--@param Functional.Detection #DETECTION_AREAS _MANTISdetection [internal] The MANTIS detection object
|
||||||
|
_MANTISAwacs = DETECTION_AREAS:New( groupset, grouping ) --[internal] Grouping detected objects to 5000m zones
|
||||||
|
_MANTISAwacs:FilterCategories({ Unit.Category.AIRPLANE, Unit.Category.HELICOPTER })
|
||||||
|
_MANTISAwacs:SetAcceptRange(self.awacsrange) --250km
|
||||||
|
_MANTISAwacs:SetRefreshTimeInterval(interval)
|
||||||
|
_MANTISAwacs:Start()
|
||||||
|
|
||||||
|
function _MANTISAwacs:OnAfterDetectedItem(From,Event,To,DetectedItem)
|
||||||
|
--BASE:I( { From, Event, To, DetectedItem })
|
||||||
|
local debug = false
|
||||||
|
if DetectedItem.IsDetected and debug then
|
||||||
|
local Coordinate = DetectedItem.Coordinate -- Core.Point#COORDINATE
|
||||||
|
local text = "Awacs Detection at "..Coordinate:ToStringLLDMS()
|
||||||
|
local m = MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return _MANTISAwacs
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to set the SAM start state
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #MANTIS self
|
||||||
|
function MANTIS:SetSAMStartState()
|
||||||
|
-- DONE: if using dynamic filtering, update SAM_Table and the (active) SEAD groups, pull req #1405/#1406
|
||||||
|
self:F(self.lid.."Setting SAM Start States")
|
||||||
|
-- get SAM Group
|
||||||
|
local SAM_SET = self.SAM_Group
|
||||||
|
local SAM_Grps = SAM_SET.Set --table of objects
|
||||||
|
local SAM_Tbl = {} -- table of SAM defense zones
|
||||||
|
local SEAD_Grps = {} -- table of SAM names to make evasive
|
||||||
|
local engagerange = self.engagerange -- firing range in % of max
|
||||||
|
--cycle through groups and set alarm state etc
|
||||||
|
for _i,_group in pairs (SAM_Grps) do
|
||||||
|
local group = _group
|
||||||
|
-- TODO: add emissions on/off
|
||||||
|
if self.UseAIOnOff then
|
||||||
|
group:SetAIOff()
|
||||||
|
else
|
||||||
|
group:OptionAlarmStateGreen() -- AI off
|
||||||
|
end
|
||||||
|
group:SetOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,engagerange) --default engagement will be 75% of firing range
|
||||||
|
if group:IsGround() then
|
||||||
|
local grpname = group:GetName()
|
||||||
|
local grpcoord = group:GetCoordinate()
|
||||||
|
table.insert( SAM_Tbl, {grpname, grpcoord})
|
||||||
|
table.insert( SEAD_Grps, grpname )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.SAM_Table = SAM_Tbl
|
||||||
|
-- make SAMs evasive
|
||||||
|
local mysead = SEAD:New( SEAD_Grps )
|
||||||
|
mysead:SetEngagementRange(engagerange)
|
||||||
|
self.mysead = mysead
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to update SAM table and SEAD state
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #MANTIS self
|
||||||
|
function MANTIS:_RefreshSAMTable()
|
||||||
|
self:F(self.lid.."Setting SAM Start States")
|
||||||
|
-- Requires SEAD 0.2.2 or better
|
||||||
|
-- get SAM Group
|
||||||
|
local SAM_SET = self.SAM_Group
|
||||||
|
local SAM_Grps = SAM_SET.Set --table of objects
|
||||||
|
local SAM_Tbl = {} -- table of SAM defense zones
|
||||||
|
local SEAD_Grps = {} -- table of SAM names to make evasive
|
||||||
|
local engagerange = self.engagerange -- firing range in % of max
|
||||||
|
--cycle through groups and set alarm state etc
|
||||||
|
for _i,_group in pairs (SAM_Grps) do
|
||||||
|
local group = _group
|
||||||
|
group:SetOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,engagerange) --engagement will be 75% of firing range
|
||||||
|
if group:IsGround() then
|
||||||
|
local grpname = group:GetName()
|
||||||
|
local grpcoord = group:GetCoordinate()
|
||||||
|
table.insert( SAM_Tbl, {grpname, grpcoord}) -- make the table lighter, as I don't really use the zone here
|
||||||
|
table.insert( SEAD_Grps, grpname )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.SAM_Table = SAM_Tbl
|
||||||
|
-- make SAMs evasive
|
||||||
|
if self.mysead ~= nil then
|
||||||
|
local mysead = self.mysead
|
||||||
|
mysead:UpdateSet( SEAD_Grps )
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to link up #MANTIS with a #SHORAD installation
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @param Functional.Shorad#SHORAD Shorad The #SHORAD object
|
||||||
|
-- @param #number Shoradtime Number of seconds #SHORAD stays active post wake-up
|
||||||
|
function MANTIS:AddShorad(Shorad,Shoradtime)
|
||||||
|
local Shorad = Shorad or nil
|
||||||
|
local ShoradTime = Shoradtime or 600
|
||||||
|
local ShoradLink = true
|
||||||
|
if Shorad:IsInstanceOf("SHORAD") then
|
||||||
|
self.ShoradLink = ShoradLink
|
||||||
|
self.Shorad = Shorad --#SHORAD
|
||||||
|
self.ShoradTime = Shoradtime -- #number
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to unlink #MANTIS from a #SHORAD installation
|
||||||
|
-- @param #MANTIS self
|
||||||
|
function MANTIS:RemoveShorad()
|
||||||
|
self.ShoradLink = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- MANTIS main functions
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Function to set the SAM start state
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #MANTIS self
|
||||||
|
function MANTIS:Start()
|
||||||
|
self:F(self.lid.."Starting MANTIS")
|
||||||
|
self:SetSAMStartState()
|
||||||
|
self.Detection = self:StartDetection()
|
||||||
|
if self.advAwacs then
|
||||||
|
self.AWACS_Detection = self:StartAwacsDetection()
|
||||||
|
end
|
||||||
|
-- detection function
|
||||||
|
local function check(detection)
|
||||||
|
--get detected set
|
||||||
|
local detset = detection:GetDetectedItemCoordinates()
|
||||||
|
self:F("Check:", {detset})
|
||||||
|
-- randomly update SAM Table
|
||||||
|
local rand = math.random(1,100)
|
||||||
|
if rand > 65 then -- 1/3 of cases
|
||||||
|
self:_RefreshSAMTable()
|
||||||
|
end
|
||||||
|
-- switch SAMs on/off if (n)one of the detected groups is inside their reach
|
||||||
|
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates
|
||||||
|
for _,_data in pairs (samset) do
|
||||||
|
local samcoordinate = _data[2]
|
||||||
|
local name = _data[1]
|
||||||
|
local samgroup = GROUP:FindByName(name)
|
||||||
|
local IsInZone, Distance = self:CheckObjectInZone(detset, samcoordinate)
|
||||||
|
if IsInZone then --check any target in zone
|
||||||
|
if samgroup:IsAlive() then
|
||||||
|
-- switch on SAM
|
||||||
|
if self.UseAIOnOff then
|
||||||
|
-- TODO: add emissions on/off
|
||||||
|
samgroup:SetAIOn()
|
||||||
|
end
|
||||||
|
samgroup:OptionAlarmStateRed()
|
||||||
|
-- link in to SHORAD if available
|
||||||
|
-- DONE: Test integration fully
|
||||||
|
if self.ShoradLink and Distance < self.ShoradActDistance then -- don't give SHORAD position away too early
|
||||||
|
local Shorad = self.Shorad
|
||||||
|
local radius = self.checkradius
|
||||||
|
local ontime = self.ShoradTime
|
||||||
|
Shorad:WakeUpShorad(name, radius, ontime)
|
||||||
|
end
|
||||||
|
-- debug output
|
||||||
|
local text = string.format("SAM %s switched to alarm state RED!", name)
|
||||||
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(self.lid..text) end
|
||||||
|
end --end alive
|
||||||
|
else
|
||||||
|
if samgroup:IsAlive() then
|
||||||
|
-- switch off SAM
|
||||||
|
if self.UseAIOnOff then
|
||||||
|
-- TODO: add emissions on/off
|
||||||
|
samgroup:SetAIOff()
|
||||||
|
else
|
||||||
|
samgroup:OptionAlarmStateGreen()
|
||||||
|
end
|
||||||
|
--samgroup:OptionROEWeaponFree()
|
||||||
|
--samgroup:SetAIOn()
|
||||||
|
local text = string.format("SAM %s switched to alarm state GREEN!", name)
|
||||||
|
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||||
|
if self.verbose then env.info(self.lid..text) end
|
||||||
|
end --end alive
|
||||||
|
end --end check
|
||||||
|
end --for for loop
|
||||||
|
end --end function
|
||||||
|
-- relocation relay function
|
||||||
|
local function relocate()
|
||||||
|
self:_RelocateGroups()
|
||||||
|
end
|
||||||
|
-- check advanced state
|
||||||
|
local function checkadvstate()
|
||||||
|
local interval, oldstate = self:_CheckAdvState()
|
||||||
|
local newstate = self.adv_state
|
||||||
|
if newstate ~= oldstate then
|
||||||
|
-- deal with new state
|
||||||
|
if newstate == 2 then
|
||||||
|
-- switch alarm state RED
|
||||||
|
if self.MantisTimer.isrunning then
|
||||||
|
self.MantisTimer:Stop()
|
||||||
|
self.MantisTimer.isrunning = false
|
||||||
|
end -- stop Awacs timer
|
||||||
|
if self.MantisATimer.isrunning then
|
||||||
|
self.MantisATimer:Stop()
|
||||||
|
self.MantisATimer.isrunning = false
|
||||||
|
end -- stop timer
|
||||||
|
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates
|
||||||
|
for _,_data in pairs (samset) do
|
||||||
|
local name = _data[1]
|
||||||
|
local samgroup = GROUP:FindByName(name)
|
||||||
|
if samgroup:IsAlive() then
|
||||||
|
if self.UseAIOnOff then
|
||||||
|
-- TODO: add emissions on/off
|
||||||
|
samgroup:SetAIOn()
|
||||||
|
end
|
||||||
|
samgroup:OptionAlarmStateRed()
|
||||||
|
end -- end alive
|
||||||
|
end -- end for loop
|
||||||
|
elseif newstate <= 1 then
|
||||||
|
-- change MantisTimer to slow down or speed up
|
||||||
|
if self.MantisTimer.isrunning then
|
||||||
|
self.MantisTimer:Stop()
|
||||||
|
self.MantisTimer.isrunning = false
|
||||||
|
end
|
||||||
|
if self.MantisATimer.isrunning then
|
||||||
|
self.MantisATimer:Stop()
|
||||||
|
self.MantisATimer.isrunning = false
|
||||||
|
end
|
||||||
|
self.MantisTimer = TIMER:New(check,self.Detection)
|
||||||
|
self.MantisTimer:Start(5,interval,nil)
|
||||||
|
self.MantisTimer.isrunning = true
|
||||||
|
if self.advAwacs then
|
||||||
|
self.MantisATimer = TIMER:New(check,self.AWACS_Detection)
|
||||||
|
self.MantisATimer:Start(15,interval,nil)
|
||||||
|
self.MantisATimer.isrunning = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end -- end newstate vs oldstate
|
||||||
|
end
|
||||||
|
-- timers to run the system
|
||||||
|
local interval = self.detectinterval
|
||||||
|
self.MantisTimer = TIMER:New(check,self.Detection)
|
||||||
|
self.MantisTimer:Start(5,interval,nil)
|
||||||
|
self.MantisTimer.isrunning = true
|
||||||
|
-- Awacs timer
|
||||||
|
if self.advAwacs then
|
||||||
|
self.MantisATimer = TIMER:New(check,self.AWACS_Detection)
|
||||||
|
self.MantisATimer:Start(15,interval,nil)
|
||||||
|
self.MantisATimer.isrunning = true
|
||||||
|
end
|
||||||
|
-- timer to relocate HQ and EWR
|
||||||
|
if self.autorelocate then
|
||||||
|
local relointerval = math.random(1800,3600) -- random between 30 and 60 mins
|
||||||
|
self.MantisReloTimer = TIMER:New(relocate)
|
||||||
|
self.MantisReloTimer:Start(relointerval,relointerval,nil)
|
||||||
|
end
|
||||||
|
-- timer for advanced state check
|
||||||
|
if self.advanced then
|
||||||
|
self.MantisAdvTimer = TIMER:New(checkadvstate)
|
||||||
|
self.MantisAdvTimer:Start(30,interval*5,nil)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to stop MANTIS
|
||||||
|
-- @param #MANTIS self
|
||||||
|
-- @return #MANTIS self
|
||||||
|
function MANTIS:Stop()
|
||||||
|
if self.MantisTimer.isrunning then
|
||||||
|
self.MantisTimer:Stop()
|
||||||
|
end
|
||||||
|
if self.MantisATimer.isrunning then
|
||||||
|
self.MantisATimer:Stop()
|
||||||
|
end
|
||||||
|
if self.autorelocate then
|
||||||
|
self.MantisReloTimer:Stop()
|
||||||
|
end
|
||||||
|
if self.advanced then
|
||||||
|
self.MantisAdvTimer:Stop()
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- MANTIS end
|
||||||
|
-----------------------------------------------------------------------
|
||||||
@@ -53,6 +53,7 @@
|
|||||||
-- @type RANGE
|
-- @type RANGE
|
||||||
-- @field #string ClassName Name of the Class.
|
-- @field #string ClassName Name of the Class.
|
||||||
-- @field #boolean Debug If true, debug info is send as messages on the screen.
|
-- @field #boolean Debug If true, debug info is send as messages on the screen.
|
||||||
|
-- @field #boolean verbose Verbosity level. Higher means more output to DCS log file.
|
||||||
-- @field #string id String id of range for output in DCS log.
|
-- @field #string id String id of range for output in DCS log.
|
||||||
-- @field #string rangename Name of the range.
|
-- @field #string rangename Name of the range.
|
||||||
-- @field Core.Point#COORDINATE location Coordinate of the range location.
|
-- @field Core.Point#COORDINATE location Coordinate of the range location.
|
||||||
@@ -93,6 +94,8 @@
|
|||||||
-- @field Core.RadioQueue#RADIOQUEUE instructor Instructor radio queue.
|
-- @field Core.RadioQueue#RADIOQUEUE instructor Instructor radio queue.
|
||||||
-- @field #number rangecontrolfreq Frequency on which the range control transmitts.
|
-- @field #number rangecontrolfreq Frequency on which the range control transmitts.
|
||||||
-- @field Core.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue.
|
-- @field Core.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue.
|
||||||
|
-- @field #string rangecontrolrelayname Name of relay unit.
|
||||||
|
-- @field #string instructorrelayname Name of relay unit.
|
||||||
-- @field #string soundpath Path inside miz file where the sound files are located. Default is "Range Soundfiles/".
|
-- @field #string soundpath Path inside miz file where the sound files are located. Default is "Range Soundfiles/".
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
@@ -287,6 +290,7 @@
|
|||||||
RANGE={
|
RANGE={
|
||||||
ClassName = "RANGE",
|
ClassName = "RANGE",
|
||||||
Debug = false,
|
Debug = false,
|
||||||
|
verbose = 0,
|
||||||
id = nil,
|
id = nil,
|
||||||
rangename = nil,
|
rangename = nil,
|
||||||
location = nil,
|
location = nil,
|
||||||
@@ -516,7 +520,7 @@ RANGE.MenuF10Root=nil
|
|||||||
|
|
||||||
--- Range script version.
|
--- Range script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RANGE.version="2.2.2"
|
RANGE.version="2.3.0"
|
||||||
|
|
||||||
--TODO list:
|
--TODO list:
|
||||||
--TODO: Verbosity level for messages.
|
--TODO: Verbosity level for messages.
|
||||||
@@ -554,7 +558,6 @@ function RANGE:New(rangename)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
local text=string.format("Script version %s - creating new RANGE object %s.", RANGE.version, self.rangename)
|
local text=string.format("Script version %s - creating new RANGE object %s.", RANGE.version, self.rangename)
|
||||||
self:I(self.id..text)
|
self:I(self.id..text)
|
||||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
|
||||||
|
|
||||||
-- Defaults
|
-- Defaults
|
||||||
self:SetDefaultPlayerSmokeBomb()
|
self:SetDefaultPlayerSmokeBomb()
|
||||||
@@ -721,7 +724,6 @@ function RANGE:onafterStart()
|
|||||||
-- Starting range.
|
-- Starting range.
|
||||||
local text=string.format("Starting RANGE %s. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
local text=string.format("Starting RANGE %s. Number of strafe targets = %d. Number of bomb targets = %d.", self.rangename, self.nstrafetargets, self.nbombtargets)
|
||||||
self:I(self.id..text)
|
self:I(self.id..text)
|
||||||
MESSAGE:New(text,10):ToAllIf(self.Debug)
|
|
||||||
|
|
||||||
-- Event handling.
|
-- Event handling.
|
||||||
if self.eventmoose then
|
if self.eventmoose then
|
||||||
@@ -755,6 +757,7 @@ function RANGE:onafterStart()
|
|||||||
|
|
||||||
-- Radio queue.
|
-- Radio queue.
|
||||||
self.rangecontrol=RADIOQUEUE:New(self.rangecontrolfreq, nil, self.rangename)
|
self.rangecontrol=RADIOQUEUE:New(self.rangecontrolfreq, nil, self.rangename)
|
||||||
|
self.rangecontrol.schedonce=true
|
||||||
|
|
||||||
-- Init numbers.
|
-- Init numbers.
|
||||||
self.rangecontrol:SetDigit(0, RANGE.Sound.RC0.filename, RANGE.Sound.RC0.duration, self.soundpath)
|
self.rangecontrol:SetDigit(0, RANGE.Sound.RC0.filename, RANGE.Sound.RC0.duration, self.soundpath)
|
||||||
@@ -770,6 +773,7 @@ function RANGE:onafterStart()
|
|||||||
|
|
||||||
-- Set location where the messages are transmitted from.
|
-- Set location where the messages are transmitted from.
|
||||||
self.rangecontrol:SetSenderCoordinate(self.location)
|
self.rangecontrol:SetSenderCoordinate(self.location)
|
||||||
|
self.rangecontrol:SetSenderUnitName(self.rangecontrolrelayname)
|
||||||
|
|
||||||
-- Start range control radio queue.
|
-- Start range control radio queue.
|
||||||
self.rangecontrol:Start(1, 0.1)
|
self.rangecontrol:Start(1, 0.1)
|
||||||
@@ -779,6 +783,7 @@ function RANGE:onafterStart()
|
|||||||
|
|
||||||
-- Radio queue.
|
-- Radio queue.
|
||||||
self.instructor=RADIOQUEUE:New(self.instructorfreq, nil, self.rangename)
|
self.instructor=RADIOQUEUE:New(self.instructorfreq, nil, self.rangename)
|
||||||
|
self.instructor.schedonce=true
|
||||||
|
|
||||||
-- Init numbers.
|
-- Init numbers.
|
||||||
self.instructor:SetDigit(0, RANGE.Sound.IR0.filename, RANGE.Sound.IR0.duration, self.soundpath)
|
self.instructor:SetDigit(0, RANGE.Sound.IR0.filename, RANGE.Sound.IR0.duration, self.soundpath)
|
||||||
@@ -794,6 +799,7 @@ function RANGE:onafterStart()
|
|||||||
|
|
||||||
-- Set location where the messages are transmitted from.
|
-- Set location where the messages are transmitted from.
|
||||||
self.instructor:SetSenderCoordinate(self.location)
|
self.instructor:SetSenderCoordinate(self.location)
|
||||||
|
self.instructor:SetSenderUnitName(self.instructorrelayname)
|
||||||
|
|
||||||
-- Start instructor radio queue.
|
-- Start instructor radio queue.
|
||||||
self.instructor:Start(1, 0.1)
|
self.instructor:Start(1, 0.1)
|
||||||
@@ -1067,18 +1073,22 @@ end
|
|||||||
--- Enable range control and set frequency.
|
--- Enable range control and set frequency.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number frequency Frequency in MHz. Default 256 MHz.
|
-- @param #number frequency Frequency in MHz. Default 256 MHz.
|
||||||
|
-- @param #string relayunitname Name of the unit used for transmission.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
function RANGE:SetRangeControl(frequency)
|
function RANGE:SetRangeControl(frequency, relayunitname)
|
||||||
self.rangecontrolfreq=frequency or 256
|
self.rangecontrolfreq=frequency or 256
|
||||||
|
self.rangecontrolrelayname=relayunitname
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enable instructor radio and set frequency.
|
--- Enable instructor radio and set frequency.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number frequency Frequency in MHz. Default 305 MHz.
|
-- @param #number frequency Frequency in MHz. Default 305 MHz.
|
||||||
|
-- @param #string relayunitname Name of the unit used for transmission.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
function RANGE:SetInstructorRadio(frequency)
|
function RANGE:SetInstructorRadio(frequency, relayunitname)
|
||||||
self.instructorfreq=frequency or 305
|
self.instructorfreq=frequency or 305
|
||||||
|
self.instructorrelayname=relayunitname
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1140,7 +1150,6 @@ function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inversehe
|
|||||||
-- Neither unit nor static object with this name could be found.
|
-- Neither unit nor static object with this name could be found.
|
||||||
local text=string.format("ERROR! Could not find ANY strafe target object with name %s.", _name)
|
local text=string.format("ERROR! Could not find ANY strafe target object with name %s.", _name)
|
||||||
self:E(self.id..text)
|
self:E(self.id..text)
|
||||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1160,7 +1169,6 @@ function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inversehe
|
|||||||
if ntargets==0 then
|
if ntargets==0 then
|
||||||
local text=string.format("ERROR! No strafe target could be found when calling RANGE:AddStrafePit() for range %s", self.rangename)
|
local text=string.format("ERROR! No strafe target could be found when calling RANGE:AddStrafePit() for range %s", self.rangename)
|
||||||
self:E(self.id..text)
|
self:E(self.id..text)
|
||||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1230,7 +1238,6 @@ function RANGE:AddStrafePit(targetnames, boxlength, boxwidth, heading, inversehe
|
|||||||
-- Debug info
|
-- Debug info
|
||||||
local text=string.format("Adding new strafe target %s with %d targets: heading = %03d, box_L = %.1f, box_W = %.1f, goodpass = %d, foul line = %.1f", _name, ntargets, heading, l, w, goodpass, foulline)
|
local text=string.format("Adding new strafe target %s with %d targets: heading = %03d, box_L = %.1f, box_W = %.1f, goodpass = %d, foul line = %.1f", _name, ntargets, heading, l, w, goodpass, foulline)
|
||||||
self:T(self.id..text)
|
self:T(self.id..text)
|
||||||
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1559,13 +1566,13 @@ function RANGE:OnEventBirth(EventData)
|
|||||||
-- Debug output.
|
-- Debug output.
|
||||||
local text=string.format("Player %s, callsign %s entered unit %s (UID %d) of group %s (GID %d)", _playername, _callsign, _unitName, _uid, _group:GetName(), _gid)
|
local text=string.format("Player %s, callsign %s entered unit %s (UID %d) of group %s (GID %d)", _playername, _callsign, _unitName, _uid, _group:GetName(), _gid)
|
||||||
self:T(self.id..text)
|
self:T(self.id..text)
|
||||||
MESSAGE:New(text, 5):ToAllIf(self.Debug)
|
|
||||||
|
|
||||||
-- Reset current strafe status.
|
-- Reset current strafe status.
|
||||||
self.strafeStatus[_uid] = nil
|
self.strafeStatus[_uid] = nil
|
||||||
|
|
||||||
-- Add Menu commands after a delay of 0.1 seconds.
|
-- Add Menu commands after a delay of 0.1 seconds.
|
||||||
SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
|
--SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
|
||||||
|
self:ScheduleOnce(0.1, self._AddF10Commands, self, _unitName)
|
||||||
|
|
||||||
-- By default, some bomb impact points and do not flare each hit on target.
|
-- By default, some bomb impact points and do not flare each hit on target.
|
||||||
self.PlayerSettings[_playername]={} --#RANGE.PlayerData
|
self.PlayerSettings[_playername]={} --#RANGE.PlayerData
|
||||||
@@ -1583,7 +1590,8 @@ function RANGE:OnEventBirth(EventData)
|
|||||||
|
|
||||||
-- Start check in zone timer.
|
-- Start check in zone timer.
|
||||||
if self.planes[_uid] ~= true then
|
if self.planes[_uid] ~= true then
|
||||||
SCHEDULER:New(nil, self._CheckInZone, {self, EventData.IniUnitName}, 1, 1)
|
--SCHEDULER:New(nil, self._CheckInZone, {self, EventData.IniUnitName}, 1, 1)
|
||||||
|
self.timerCheckZone=TIMER:New(self._CheckInZone, self, EventData.IniUnitName):Start(1, 1)
|
||||||
self.planes[_uid] = true
|
self.planes[_uid] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1666,15 +1674,12 @@ function RANGE:OnEventHit(EventData)
|
|||||||
|
|
||||||
if _unit and _playername then
|
if _unit and _playername then
|
||||||
|
|
||||||
|
-- Flare target.
|
||||||
|
if self.PlayerSettings[_playername].flaredirecthits then
|
||||||
|
|
||||||
-- Position of target.
|
-- Position of target.
|
||||||
local targetPos = _target:GetCoordinate()
|
local targetPos = _target:GetCoordinate()
|
||||||
|
|
||||||
-- Message to player.
|
|
||||||
--local text=string.format("%s, direct hit on target %s.", self:_myname(_unitName), targetname)
|
|
||||||
--self:DisplayMessageToGroup(_unit, text, 10, true)
|
|
||||||
|
|
||||||
-- Flare target.
|
|
||||||
if self.PlayerSettings[_playername].flaredirecthits then
|
|
||||||
targetPos:Flare(self.PlayerSettings[_playername].flarecolor)
|
targetPos:Flare(self.PlayerSettings[_playername].flarecolor)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1716,9 +1721,6 @@ function RANGE:OnEventShot(EventData)
|
|||||||
self:T(self.id.."EVENT SHOT: Weapon name = ".._weaponName)
|
self:T(self.id.."EVENT SHOT: Weapon name = ".._weaponName)
|
||||||
self:T(self.id.."EVENT SHOT: Weapon cate = "..weaponcategory)
|
self:T(self.id.."EVENT SHOT: Weapon cate = "..weaponcategory)
|
||||||
|
|
||||||
-- Special cases:
|
|
||||||
--local _viggen=string.match(_weapon, "ROBOT") or string.match(_weapon, "RB75") or string.match(_weapon, "BK90") or string.match(_weapon, "RB15") or string.match(_weapon, "RB04")
|
|
||||||
|
|
||||||
-- Tracking conditions for bombs, rockets and missiles.
|
-- Tracking conditions for bombs, rockets and missiles.
|
||||||
local _bombs = weaponcategory==Weapon.Category.BOMB --string.match(_weapon, "weapons.bombs")
|
local _bombs = weaponcategory==Weapon.Category.BOMB --string.match(_weapon, "weapons.bombs")
|
||||||
local _rockets = weaponcategory==Weapon.Category.ROCKET --string.match(_weapon, "weapons.nurs")
|
local _rockets = weaponcategory==Weapon.Category.ROCKET --string.match(_weapon, "weapons.nurs")
|
||||||
@@ -1752,7 +1754,7 @@ function RANGE:OnEventShot(EventData)
|
|||||||
self:T(self.id..string.format("RANGE %s: Tracking %s - %s.", self.rangename, _weapon, EventData.weapon:getName()))
|
self:T(self.id..string.format("RANGE %s: Tracking %s - %s.", self.rangename, _weapon, EventData.weapon:getName()))
|
||||||
|
|
||||||
-- Init bomb position.
|
-- Init bomb position.
|
||||||
local _lastBombPos = {x=0,y=0,z=0}
|
local _lastBombPos = {x=0,y=0,z=0} --DCS#Vec3
|
||||||
|
|
||||||
-- Function monitoring the position of a bomb until impact.
|
-- Function monitoring the position of a bomb until impact.
|
||||||
local function trackBomb(_ordnance)
|
local function trackBomb(_ordnance)
|
||||||
@@ -1908,8 +1910,39 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function RANGE:onafterStatus(From, Event, To)
|
function RANGE:onafterStatus(From, Event, To)
|
||||||
|
|
||||||
|
if self.verbose>0 then
|
||||||
|
|
||||||
|
local fsmstate=self:GetState()
|
||||||
|
|
||||||
|
local text=string.format("Range status: %s", fsmstate)
|
||||||
|
|
||||||
|
if self.instructor then
|
||||||
|
local alive="N/A"
|
||||||
|
if self.instructorrelayname then
|
||||||
|
local relay=UNIT:FindByName(self.instructorrelayname)
|
||||||
|
if relay then
|
||||||
|
alive=tostring(relay:IsAlive())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
text=text..string.format(", Instructor %.3f MHz (Relay=%s alive=%s)", self.instructorfreq, tostring(self.instructorrelayname), alive)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.rangecontrol then
|
||||||
|
local alive="N/A"
|
||||||
|
if self.rangecontrolrelayname then
|
||||||
|
local relay=UNIT:FindByName(self.rangecontrolrelayname)
|
||||||
|
if relay then
|
||||||
|
alive=tostring(relay:IsAlive())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
text=text..string.format(", Control %.3f MHz (Relay=%s alive=%s)", self.rangecontrolfreq, tostring(self.rangecontrolrelayname), alive)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Check range status.
|
-- Check range status.
|
||||||
self:I(self.id..string.format("Range status: %s", self:GetState()))
|
self:I(self.id..text)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-- Check player status.
|
-- Check player status.
|
||||||
self:_CheckPlayers()
|
self:_CheckPlayers()
|
||||||
@@ -2701,6 +2734,32 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
|
|
||||||
if _unit and _playername then
|
if _unit and _playername then
|
||||||
|
|
||||||
|
--- Function to check if unit is in zone and facing in the right direction and is below the max alt.
|
||||||
|
local function checkme(targetheading, _zone)
|
||||||
|
local zone=_zone --Core.Zone#ZONE
|
||||||
|
|
||||||
|
-- Heading check.
|
||||||
|
local unitheading = _unit:GetHeading()
|
||||||
|
local pitheading = targetheading-180
|
||||||
|
local deltaheading = unitheading-pitheading
|
||||||
|
local towardspit = math.abs(deltaheading)<=90 or math.abs(deltaheading-360)<=90
|
||||||
|
|
||||||
|
if towardspit then
|
||||||
|
|
||||||
|
local vec3=_unit:GetVec3()
|
||||||
|
local vec2={x=vec3.x, y=vec3.z} --DCS#Vec2
|
||||||
|
local landheight=land.getHeight(vec2)
|
||||||
|
local unitalt=vec3.y-landheight
|
||||||
|
|
||||||
|
if unitalt<=self.strafemaxalt then
|
||||||
|
local unitinzone=zone:IsVec2InZone(vec2)
|
||||||
|
return unitinzone
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- Current position of player unit.
|
-- Current position of player unit.
|
||||||
local _unitID = _unit:GetID()
|
local _unitID = _unit:GetID()
|
||||||
|
|
||||||
@@ -2712,18 +2771,8 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
-- Get the current approach zone and check if player is inside.
|
-- Get the current approach zone and check if player is inside.
|
||||||
local zone=_currentStrafeRun.zone.polygon --Core.Zone#ZONE_POLYGON_BASE
|
local zone=_currentStrafeRun.zone.polygon --Core.Zone#ZONE_POLYGON_BASE
|
||||||
|
|
||||||
local unitheading = _unit:GetHeading()
|
-- Check if unit in zone and facing the right direction.
|
||||||
local pitheading = _currentStrafeRun.zone.heading - 180
|
local unitinzone=checkme(_currentStrafeRun.zone.heading, zone)
|
||||||
local deltaheading = unitheading-pitheading
|
|
||||||
local towardspit = math.abs(deltaheading)<=90 or math.abs(deltaheading-360)<=90
|
|
||||||
local unitalt=_unit:GetHeight()-_unit:GetCoordinate():GetLandHeight()
|
|
||||||
|
|
||||||
-- Check if unit is inside zone and below max height AGL.
|
|
||||||
local unitinzone=_unit:IsInZone(zone) and unitalt <= self.strafemaxalt and towardspit
|
|
||||||
|
|
||||||
-- Debug output
|
|
||||||
local text=string.format("Checking still in zone. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _unitName, _playername, tostring(unitinzone), unitalt, deltaheading)
|
|
||||||
self:T2(self.id..text)
|
|
||||||
|
|
||||||
-- Check if player is in strafe zone and below max alt.
|
-- Check if player is in strafe zone and below max alt.
|
||||||
if unitinzone then
|
if unitinzone then
|
||||||
@@ -2823,22 +2872,10 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
for _,_targetZone in pairs(self.strafeTargets) do
|
for _,_targetZone in pairs(self.strafeTargets) do
|
||||||
|
|
||||||
-- Get the current approach zone and check if player is inside.
|
-- Get the current approach zone and check if player is inside.
|
||||||
local zonenname=_targetZone.name
|
|
||||||
local zone=_targetZone.polygon --Core.Zone#ZONE_POLYGON_BASE
|
local zone=_targetZone.polygon --Core.Zone#ZONE_POLYGON_BASE
|
||||||
|
|
||||||
-- Check if player is in zone and below max alt and flying towards the target.
|
-- Check if unit in zone and facing the right direction.
|
||||||
local unitheading = _unit:GetHeading()
|
local unitinzone=checkme(_targetZone.heading, zone)
|
||||||
local pitheading = _targetZone.heading - 180
|
|
||||||
local deltaheading = unitheading-pitheading
|
|
||||||
local towardspit = math.abs(deltaheading)<=90 or math.abs(deltaheading-360)<=90
|
|
||||||
local unitalt =_unit:GetHeight()-_unit:GetCoordinate():GetLandHeight()
|
|
||||||
|
|
||||||
-- Check if unit is inside zone and below max height AGL.
|
|
||||||
local unitinzone=_unit:IsInZone(zone) and unitalt <= self.strafemaxalt and towardspit
|
|
||||||
|
|
||||||
-- Debug info.
|
|
||||||
local text=string.format("Checking zone %s. Unit = %s, player = %s in zone = %s. alt = %d, delta heading = %d", _targetZone.name, _unitName, _playername, tostring(unitinzone), unitalt, deltaheading)
|
|
||||||
self:T2(self.id..text)
|
|
||||||
|
|
||||||
-- Player is inside zone.
|
-- Player is inside zone.
|
||||||
if unitinzone then
|
if unitinzone then
|
||||||
@@ -2847,7 +2884,7 @@ function RANGE:_CheckInZone(_unitName)
|
|||||||
local _ammo=self:_GetAmmo(_unitName)
|
local _ammo=self:_GetAmmo(_unitName)
|
||||||
|
|
||||||
-- Init strafe status for this player.
|
-- Init strafe status for this player.
|
||||||
self.strafeStatus[_unitID] = {hits = 0, zone = _targetZone, time = 1, ammo=_ammo, pastfoulline=false }
|
self.strafeStatus[_unitID] = {hits = 0, zone = _targetZone, time = 1, ammo=_ammo, pastfoulline=false}
|
||||||
|
|
||||||
-- Rolling in!
|
-- Rolling in!
|
||||||
local _msg=string.format("%s, rolling in on strafe pit %s.", self:_myname(_unitName), _targetZone.name)
|
local _msg=string.format("%s, rolling in on strafe pit %s.", self:_myname(_unitName), _targetZone.name)
|
||||||
@@ -3054,11 +3091,9 @@ function RANGE:_GetAmmo(unitname)
|
|||||||
|
|
||||||
local text=string.format("Player %s has %d rounds ammo of type %s", playername, Nammo, Tammo)
|
local text=string.format("Player %s has %d rounds ammo of type %s", playername, Nammo, Tammo)
|
||||||
self:T(self.id..text)
|
self:T(self.id..text)
|
||||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
|
||||||
else
|
else
|
||||||
local text=string.format("Player %s has %d ammo of type %s", playername, Nammo, Tammo)
|
local text=string.format("Player %s has %d ammo of type %s", playername, Nammo, Tammo)
|
||||||
self:T(self.id..text)
|
self:T(self.id..text)
|
||||||
MESSAGE:New(text, 10):ToAllIf(self.Debug)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Authors: **FlightControl**
|
-- ### Authors: **FlightControl**, **applevangelist**
|
||||||
|
--
|
||||||
|
-- Last Update: Feb 2021
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -39,18 +41,55 @@
|
|||||||
SEAD = {
|
SEAD = {
|
||||||
ClassName = "SEAD",
|
ClassName = "SEAD",
|
||||||
TargetSkill = {
|
TargetSkill = {
|
||||||
Average = { Evade = 50, DelayOff = { 10, 25 }, DelayOn = { 10, 30 } } ,
|
Average = { Evade = 30, DelayOn = { 40, 60 } } ,
|
||||||
Good = { Evade = 30, DelayOff = { 8, 20 }, DelayOn = { 20, 40 } } ,
|
Good = { Evade = 20, DelayOn = { 30, 50 } } ,
|
||||||
High = { Evade = 15, DelayOff = { 5, 17 }, DelayOn = { 30, 50 } } ,
|
High = { Evade = 15, DelayOn = { 20, 40 } } ,
|
||||||
Excellent = { Evade = 10, DelayOff = { 3, 10 }, DelayOn = { 30, 60 } }
|
Excellent = { Evade = 10, DelayOn = { 10, 30 } }
|
||||||
},
|
},
|
||||||
SEADGroupPrefixes = {}
|
SEADGroupPrefixes = {},
|
||||||
|
SuppressedGroups = {},
|
||||||
|
EngagementRange = 75 -- default 75% engagement range Feature Request #1355
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- TODO Complete list?
|
||||||
|
--- Missile enumerators
|
||||||
|
-- @field Harms
|
||||||
|
SEAD.Harms = {
|
||||||
|
--[[
|
||||||
|
["X58"] = "weapons.missiles.X_58", --Kh-58X anti-radiation missiles fired
|
||||||
|
["Kh25"] = "weapons.missiles.Kh25MP_PRGS1VP", --Kh-25MP anti-radiation missiles fired
|
||||||
|
["X25"] = "weapons.missiles.X_25MP", --Kh-25MPU anti-radiation missiles fired
|
||||||
|
["X28"] = "weapons.missiles.X_28", --Kh-28 anti-radiation missiles fired
|
||||||
|
["X31"] = "weapons.missiles.X_31P", --Kh-31P anti-radiation missiles fired
|
||||||
|
["AGM45A"] = "weapons.missiles.AGM_45A", --AGM-45A anti-radiation missiles fired
|
||||||
|
["AGM45"] = "weapons.missiles.AGM_45", --AGM-45B anti-radiation missiles fired
|
||||||
|
["AGM88"] = "weapons.missiles.AGM_88", --AGM-88C anti-radiation missiles fired
|
||||||
|
["AGM122"] = "weapons.missiles.AGM_122", --AGM-122 Sidearm anti-radiation missiles fired
|
||||||
|
["LD10"] = "weapons.missiles.LD-10", --LD-10 anti-radiation missiles fired
|
||||||
|
["ALARM"] = "weapons.missiles.ALARM", --ALARM anti-radiation missiles fired
|
||||||
|
["AGM84E"] = "weapons.missiles.AGM_84E", --AGM84 anti-radiation missiles fired
|
||||||
|
["AGM84A"] = "weapons.missiles.AGM_84A", --AGM84 anti-radiation missiles fired
|
||||||
|
["AGM84H"] = "weapons.missiles.AGM_84H", --AGM84 anti-radiation missiles fired
|
||||||
|
--]]
|
||||||
|
["AGM_88"] = "AGM_88",
|
||||||
|
["AGM_45"] = "AGM_45",
|
||||||
|
["AGM_122"] = "AGM_122",
|
||||||
|
["AGM_84"] = "AGM_84",
|
||||||
|
["AGM_45"] = "AGM_45",
|
||||||
|
["ALARN"] = "ALARM",
|
||||||
|
["LD-10"] = "LD-10",
|
||||||
|
["X_58"] = "X_58",
|
||||||
|
["X_28"] = "X_28",
|
||||||
|
["X_25"] = "X_25",
|
||||||
|
["X_31"] = "X_31",
|
||||||
|
["Kh25"] = "Kh25",
|
||||||
|
}
|
||||||
|
|
||||||
--- 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 table{string,...}|string SEADGroupPrefixes which is a table of Prefixes of the SA Groups in the DCSRTE on which evasive actions need to be taken.
|
-- @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.
|
||||||
-- @return SEAD
|
-- @return SEAD
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- CCCP SEAD Defenses
|
-- -- CCCP SEAD Defenses
|
||||||
@@ -66,29 +105,77 @@ function SEAD:New( SEADGroupPrefixes )
|
|||||||
self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix
|
self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes
|
self.SEADGroupPrefixes[SEADGroupPrefixes] = SEADGroupPrefixes
|
||||||
end
|
end
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Shot )
|
self:HandleEvent( EVENTS.Shot )
|
||||||
|
self:I("*** SEAD - Started Version 0.2.5")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update the active SEAD Set
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param #table SEADGroupPrefixes The prefixes to add, note: can also be a single #string
|
||||||
|
-- @return #SEAD self
|
||||||
|
function SEAD:UpdateSet( SEADGroupPrefixes )
|
||||||
|
|
||||||
|
self:F( SEADGroupPrefixes )
|
||||||
|
|
||||||
|
if type( SEADGroupPrefixes ) == 'table' then
|
||||||
|
for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do
|
||||||
|
self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.SEADGroupPrefixes[SEADGroupPrefixes] = SEADGroupPrefixes
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
--- Sets the engagement range of the SAMs. Defaults to 75% to make it more deadly. Feature Request #1355
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param #number range Set the engagement range in percent, e.g. 50
|
||||||
|
-- @return self
|
||||||
|
function SEAD:SetEngagementRange(range)
|
||||||
|
self:F( { range } )
|
||||||
|
range = range or 75
|
||||||
|
if range < 0 or range > 100 then
|
||||||
|
range = 75
|
||||||
|
end
|
||||||
|
self.EngagementRange = range
|
||||||
|
self:T(string.format("*** SEAD - Engagement range set to %s",range))
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a known HARM was fired
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param #string WeaponName
|
||||||
|
-- @return #boolean Returns true for a match
|
||||||
|
function SEAD:_CheckHarms(WeaponName)
|
||||||
|
self:F( { WeaponName } )
|
||||||
|
local hit = false
|
||||||
|
for _,_name in pairs (SEAD.Harms) do
|
||||||
|
if string.find(WeaponName,_name,1) then hit = true end
|
||||||
|
end
|
||||||
|
return hit
|
||||||
|
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.
|
||||||
-- @see SEAD
|
-- @see SEAD
|
||||||
-- @param #SEAD
|
-- @param #SEAD
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SEAD:OnEventShot( EventData )
|
function SEAD:OnEventShot( EventData )
|
||||||
self:F( { EventData } )
|
self:T( { EventData } )
|
||||||
|
|
||||||
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
|
||||||
-- Start of the 2nd loop
|
|
||||||
self:T( "Missile Launched = " .. SEADWeaponName )
|
|
||||||
|
|
||||||
--if SEADWeaponName == "KH-58" or SEADWeaponName == "KH-25MPU" or SEADWeaponName == "AGM-88" or SEADWeaponName == "KH-31A" or SEADWeaponName == "KH-31P" then -- Check if the missile is a SEAD
|
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||||
|
self:T({ SEADWeapon })
|
||||||
|
|
||||||
|
--[[check for SEAD missiles
|
||||||
if SEADWeaponName == "weapons.missiles.X_58" --Kh-58U anti-radiation missiles fired
|
if SEADWeaponName == "weapons.missiles.X_58" --Kh-58U anti-radiation missiles fired
|
||||||
or
|
or
|
||||||
SEADWeaponName == "weapons.missiles.Kh25MP_PRGS1VP" --Kh-25MP anti-radiation missiles fired
|
SEADWeaponName == "weapons.missiles.Kh25MP_PRGS1VP" --Kh-25MP anti-radiation missiles fired
|
||||||
@@ -107,27 +194,36 @@ function SEAD:OnEventShot( EventData )
|
|||||||
or
|
or
|
||||||
SEADWeaponName == "weapons.missiles.AGM_122" --AGM-122 Sidearm anti-radiation missiles fired
|
SEADWeaponName == "weapons.missiles.AGM_122" --AGM-122 Sidearm anti-radiation missiles fired
|
||||||
or
|
or
|
||||||
|
SEADWeaponName == "weapons.missiles.LD-10" --LD-10 anti-radiation missiles fired
|
||||||
|
or
|
||||||
SEADWeaponName == "weapons.missiles.ALARM" --ALARM anti-radiation missiles fired
|
SEADWeaponName == "weapons.missiles.ALARM" --ALARM anti-radiation missiles fired
|
||||||
then
|
or
|
||||||
|
SEADWeaponName == "weapons.missiles.AGM_84E" --AGM84 anti-radiation missiles fired
|
||||||
|
or
|
||||||
|
SEADWeaponName == "weapons.missiles.AGM_84A" --AGM84 anti-radiation missiles fired
|
||||||
|
or
|
||||||
|
SEADWeaponName == "weapons.missiles.AGM_84H" --AGM84 anti-radiation missiles fired
|
||||||
|
--]]
|
||||||
|
if self:_CheckHarms(SEADWeaponName) then
|
||||||
|
|
||||||
local _evade = math.random (1,100) -- random number for chance of evading action
|
local _evade = math.random (1,100) -- random number for chance of evading action
|
||||||
local _targetMim = EventData.Weapon:getTarget() -- Identify target
|
local _targetMim = EventData.Weapon:getTarget() -- Identify target
|
||||||
local _targetMimname = Unit.getName(_targetMim)
|
local _targetMimname = Unit.getName(_targetMim) -- Unit name
|
||||||
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
|
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) --targeted group
|
||||||
local _targetMimgroupName = _targetMimgroup:getName()
|
local _targetMimgroupName = _targetMimgroup:getName() -- group name
|
||||||
local _targetMimcont= _targetMimgroup:getController()
|
|
||||||
local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill
|
local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill
|
||||||
self:T( self.SEADGroupPrefixes )
|
self:T( self.SEADGroupPrefixes )
|
||||||
self:T( _targetMimgroupName )
|
self:T( _targetMimgroupName )
|
||||||
|
-- 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
|
||||||
if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then
|
if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then
|
||||||
SEADGroupFound = true
|
SEADGroupFound = true
|
||||||
self:T( 'Group Found' )
|
self:T( '*** SEAD - Group Found' )
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if SEADGroupFound == true then
|
if SEADGroupFound == true then -- yes we are being attacked
|
||||||
if _targetskill == "Random" then -- when skill is random, choose a skill
|
if _targetskill == "Random" then -- when skill is random, choose a skill
|
||||||
local Skills = { "Average", "Good", "High", "Excellent" }
|
local Skills = { "Average", "Good", "High", "Excellent" }
|
||||||
_targetskill = Skills[ math.random(1,4) ]
|
_targetskill = Skills[ math.random(1,4) ]
|
||||||
@@ -136,63 +232,36 @@ function SEAD:OnEventShot( EventData )
|
|||||||
if self.TargetSkill[_targetskill] then
|
if self.TargetSkill[_targetskill] then
|
||||||
if (_evade > self.TargetSkill[_targetskill].Evade) then
|
if (_evade > self.TargetSkill[_targetskill].Evade) then
|
||||||
|
|
||||||
self:T( string.format("Evading, target skill " ..string.format(_targetskill)) )
|
self:T( string.format("*** SEAD - Evading, target skill " ..string.format(_targetskill)) )
|
||||||
|
|
||||||
local _targetMim = Weapon.getTarget(SEADWeapon)
|
|
||||||
local _targetMimname = Unit.getName(_targetMim)
|
|
||||||
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
|
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
|
||||||
local _targetMimcont= _targetMimgroup:getController()
|
local _targetMimcont= _targetMimgroup:getController()
|
||||||
|
|
||||||
routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly
|
routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly
|
||||||
|
|
||||||
local SuppressedGroups1 = {} -- unit suppressed radar off for a random time
|
--tracker ID table to switch groups off and on again
|
||||||
|
|
||||||
local function SuppressionEnd1(id)
|
|
||||||
id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN)
|
|
||||||
SuppressedGroups1[id.groupName] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local id = {
|
local id = {
|
||||||
groupName = _targetMimgroup,
|
groupName = _targetMimgroup,
|
||||||
ctrl = _targetMimcont
|
ctrl = _targetMimcont
|
||||||
}
|
}
|
||||||
|
|
||||||
local delay1 = math.random(self.TargetSkill[_targetskill].DelayOff[1], self.TargetSkill[_targetskill].DelayOff[2])
|
local function SuppressionEnd(id) --switch group back on
|
||||||
|
local range = self.EngagementRange -- Feature Request #1355
|
||||||
if SuppressedGroups1[id.groupName] == nil then
|
self:T(string.format("*** SEAD - Engagement Range is %d", range))
|
||||||
|
|
||||||
SuppressedGroups1[id.groupName] = {
|
|
||||||
SuppressionEndTime1 = timer.getTime() + delay1,
|
|
||||||
SuppressionEndN1 = SuppressionEndCounter1 --Store instance of SuppressionEnd() scheduled function
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN)
|
|
||||||
timer.scheduleFunction(SuppressionEnd1, id, SuppressedGroups1[id.groupName].SuppressionEndTime1) --Schedule the SuppressionEnd() function
|
|
||||||
--trigger.action.outText( string.format("Radar Off " ..string.format(delay1)), 20)
|
|
||||||
end
|
|
||||||
|
|
||||||
local SuppressedGroups = {}
|
|
||||||
|
|
||||||
local function SuppressionEnd(id)
|
|
||||||
id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED)
|
id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED)
|
||||||
SuppressedGroups[id.groupName] = nil
|
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
|
||||||
local id = {
|
|
||||||
groupName = _targetMimgroup,
|
|
||||||
ctrl = _targetMimcont
|
|
||||||
}
|
|
||||||
|
|
||||||
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
|
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
|
||||||
|
local SuppressionEndTime = timer.getTime() + delay
|
||||||
if SuppressedGroups[id.groupName] == nil then
|
--create entry
|
||||||
SuppressedGroups[id.groupName] = {
|
if self.SuppressedGroups[id.groupName] == nil then --no timer entry for this group yet
|
||||||
SuppressionEndTime = timer.getTime() + delay,
|
self.SuppressedGroups[id.groupName] = {
|
||||||
SuppressionEndN = SuppressionEndCounter --Store instance of SuppressionEnd() scheduled function
|
SuppressionEndTime = delay
|
||||||
}
|
}
|
||||||
|
Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN)
|
||||||
timer.scheduleFunction(SuppressionEnd, id, SuppressedGroups[id.groupName].SuppressionEndTime) --Schedule the SuppressionEnd() function
|
timer.scheduleFunction(SuppressionEnd, id, SuppressionEndTime) --Schedule the SuppressionEnd() function
|
||||||
--trigger.action.outText( string.format("Radar On " ..string.format(delay)), 20)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
488
Moose Development/Moose/Functional/Shorad.lua
Normal file
488
Moose Development/Moose/Functional/Shorad.lua
Normal file
@@ -0,0 +1,488 @@
|
|||||||
|
--- **Functional** -- Short Range Air Defense System
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- **SHORAD** - Short Range Air Defense System
|
||||||
|
-- Controls a network of short range air/missile defense groups.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Missions:
|
||||||
|
--
|
||||||
|
-- ### [SHORAD - Short Range Air Defense](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SRD%20-%20SHORAD%20Defense)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author : **applevangelist **
|
||||||
|
--
|
||||||
|
-- @module Functional.Shorad
|
||||||
|
-- @image Functional.Shorad.jpg
|
||||||
|
--
|
||||||
|
-- Date: Feb 2021
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
--- **SHORAD** class, extends Core.Base#BASE
|
||||||
|
-- @type SHORAD
|
||||||
|
-- @field #string ClassName
|
||||||
|
-- @field #string name Name of this Shorad
|
||||||
|
-- @field #boolean debug Set the debug state
|
||||||
|
-- @field #string Prefixes String to be used to build the @{#Core.Set#SET_GROUP}
|
||||||
|
-- @field #number Radius Shorad defense radius in meters
|
||||||
|
-- @field Core.Set#SET_GROUP Groupset The set of Shorad groups
|
||||||
|
-- @field Core.Set#SET_GROUP Samset The set of SAM groups to defend
|
||||||
|
-- @field #string Coalition The coalition of this Shorad
|
||||||
|
-- @field #number ActiveTimer How long a Shorad stays active after wake-up in seconds
|
||||||
|
-- @field #table ActiveGroups Table for the timer function
|
||||||
|
-- @field #string lid The log ID for the dcs.log
|
||||||
|
-- @field #boolean DefendHarms Default true, intercept incoming HARMS
|
||||||
|
-- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles
|
||||||
|
-- @field #number DefenseLowProb Default 70, minimum detection limit
|
||||||
|
-- @field #number DefenseHighProb Default 90, maximim detection limit
|
||||||
|
-- @field #boolean UseAIOnOff Decide if we are using AI on/off (true) or AlarmState red/green (default).
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie)
|
||||||
|
--
|
||||||
|
-- Simple Class for a more intelligent Short Range Air Defense System
|
||||||
|
--
|
||||||
|
-- #SHORAD
|
||||||
|
-- Moose derived missile intercepting short range defense system.
|
||||||
|
-- Protects a network of SAM sites. Uses events to switch on the defense groups closest to the enemy.
|
||||||
|
-- Easily integrated with @{Functional.Mantis#MANTIS} to complete the defensive system setup.
|
||||||
|
--
|
||||||
|
-- ## Usage
|
||||||
|
--
|
||||||
|
-- Set up a #SET_GROUP for the SAM sites to be protected:
|
||||||
|
--
|
||||||
|
-- `local SamSet = SET_GROUP:New():FilterPrefixes("Red SAM"):FilterCoalitions("red"):FilterStart()`
|
||||||
|
--
|
||||||
|
-- By default, SHORAD will defense against both HARMs and AG-Missiles with short to medium range. The default defense probability is 70-90%.
|
||||||
|
-- When a missile is detected, SHORAD will activate defense groups in the given radius around the target for 10 minutes. It will *not* react to friendly fire.
|
||||||
|
--
|
||||||
|
-- ### Start a new SHORAD system, parameters are:
|
||||||
|
--
|
||||||
|
-- * Name: Name of this SHORAD.
|
||||||
|
-- * ShoradPrefix: Filter for the Shorad #SET_GROUP.
|
||||||
|
-- * Samset: The #SET_GROUP of SAM sites to defend.
|
||||||
|
-- * Radius: Defense radius in meters.
|
||||||
|
-- * ActiveTimer: Determines how many seconds the systems stay on red alert after wake-up call.
|
||||||
|
-- * Coalition: Coalition, i.e. "blue", "red", or "neutral".*
|
||||||
|
--
|
||||||
|
-- `myshorad = SHORAD:New("RedShorad", "Red SHORAD", SamSet, 25000, 600, "red")`
|
||||||
|
--
|
||||||
|
-- ## Customize options
|
||||||
|
--
|
||||||
|
-- * SHORAD:SwitchDebug(debug)
|
||||||
|
-- * SHORAD:SwitchHARMDefense(onoff)
|
||||||
|
-- * SHORAD:SwitchAGMDefense(onoff)
|
||||||
|
-- * SHORAD:SetDefenseLimits(low,high)
|
||||||
|
-- * SHORAD:SetActiveTimer(seconds)
|
||||||
|
-- * SHORAD:SetDefenseRadius(meters)
|
||||||
|
--
|
||||||
|
-- @field #SHORAD
|
||||||
|
SHORAD = {
|
||||||
|
ClassName = "SHORAD",
|
||||||
|
name = "MyShorad",
|
||||||
|
debug = false,
|
||||||
|
Prefixes = "",
|
||||||
|
Radius = 20000,
|
||||||
|
Groupset = nil,
|
||||||
|
Samset = nil,
|
||||||
|
Coalition = nil,
|
||||||
|
ActiveTimer = 600, --stay on 10 mins
|
||||||
|
ActiveGroups = {},
|
||||||
|
lid = "",
|
||||||
|
DefendHarms = true,
|
||||||
|
DefendMavs = true,
|
||||||
|
DefenseLowProb = 70,
|
||||||
|
DefenseHighProb = 90,
|
||||||
|
UseAIOnOff = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- SHORAD System
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
-- TODO Complete list?
|
||||||
|
--- Missile enumerators
|
||||||
|
-- @field Harms
|
||||||
|
SHORAD.Harms = {
|
||||||
|
--[[
|
||||||
|
["X58"] = "weapons.missiles.X_58", --Kh-58X anti-radiation missiles fired
|
||||||
|
["Kh25"] = "weapons.missiles.Kh25MP_PRGS1VP", --Kh-25MP anti-radiation missiles fired
|
||||||
|
["X25"] = "weapons.missiles.X_25MP", --Kh-25MPU anti-radiation missiles fired
|
||||||
|
["X28"] = "weapons.missiles.X_28", --Kh-28 anti-radiation missiles fired
|
||||||
|
["X31"] = "weapons.missiles.X_31P", --Kh-31P anti-radiation missiles fired
|
||||||
|
["AGM45A"] = "weapons.missiles.AGM_45A", --AGM-45A anti-radiation missiles fired
|
||||||
|
["AGM45"] = "weapons.missiles.AGM_45", --AGM-45B anti-radiation missiles fired
|
||||||
|
["AGM88"] = "weapons.missiles.AGM_88", --AGM-88C anti-radiation missiles fired
|
||||||
|
["AGM122"] = "weapons.missiles.AGM_122", --AGM-122 Sidearm anti-radiation missiles fired
|
||||||
|
["LD10"] = "weapons.missiles.LD-10", --LD-10 anti-radiation missiles fired
|
||||||
|
["ALARM"] = "weapons.missiles.ALARM", --ALARM anti-radiation missiles fired
|
||||||
|
["AGM84E"] = "weapons.missiles.AGM_84E", --AGM84 anti-radiation missiles fired
|
||||||
|
["AGM84A"] = "weapons.missiles.AGM_84A", --AGM84 anti-radiation missiles fired
|
||||||
|
["AGM84H"] = "weapons.missiles.AGM_84H", --AGM84 anti-radiation missiles fired
|
||||||
|
--]]
|
||||||
|
["AGM_88"] = "AGM_88",
|
||||||
|
["AGM_45"] = "AGM_45",
|
||||||
|
["AGM_122"] = "AGM_122",
|
||||||
|
["AGM_84"] = "AGM_84",
|
||||||
|
["AGM_45"] = "AGM_45",
|
||||||
|
["ALARN"] = "ALARM",
|
||||||
|
["LD-10"] = "LD-10",
|
||||||
|
["X_58"] = "X_58",
|
||||||
|
["X_28"] = "X_28",
|
||||||
|
["X_25"] = "X_25",
|
||||||
|
["X_31"] = "X_31",
|
||||||
|
["Kh25"] = "Kh25",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- TODO complete list?
|
||||||
|
-- @field Mavs
|
||||||
|
SHORAD.Mavs = {
|
||||||
|
["AGM"] = "AGM",
|
||||||
|
["C-701"] = "C-701",
|
||||||
|
["Kh25"] = "Kh25",
|
||||||
|
["Kh29"] = "Kh29",
|
||||||
|
["Kh31"] = "Kh31",
|
||||||
|
["Kh66"] = "Kh66",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Instantiates a new SHORAD object
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string Name Name of this SHORAD
|
||||||
|
-- @param #string ShoradPrefix Filter for the Shorad #SET_GROUP
|
||||||
|
-- @param Core.Set#SET_GROUP Samset The #SET_GROUP of SAM sites to defend
|
||||||
|
-- @param #number Radius Defense radius in meters, used to switch on groups
|
||||||
|
-- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call
|
||||||
|
-- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral"
|
||||||
|
function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition)
|
||||||
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
|
self:F({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
||||||
|
|
||||||
|
local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart()
|
||||||
|
|
||||||
|
self.name = Name or "MyShorad"
|
||||||
|
self.Prefixes = ShoradPrefix or "SAM SHORAD"
|
||||||
|
self.Radius = Radius or 20000
|
||||||
|
self.Coalition = Coalition or "blue"
|
||||||
|
self.Samset = Samset or GroupSet
|
||||||
|
self.ActiveTimer = ActiveTimer or 600
|
||||||
|
self.ActiveGroups = {}
|
||||||
|
self.Groupset = GroupSet
|
||||||
|
self:HandleEvent( EVENTS.Shot )
|
||||||
|
self.DefendHarms = true
|
||||||
|
self.DefendMavs = true
|
||||||
|
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
||||||
|
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
||||||
|
self.UseAIOnOff = false -- Decide if we are using AI on/off (true) or AlarmState red/green (default)
|
||||||
|
self:I("*** SHORAD - Started Version 0.1.0")
|
||||||
|
-- Set the string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("SHORAD %s | ", self.name)
|
||||||
|
self:_InitState()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initially set all groups to alarm state GREEN
|
||||||
|
-- @param #SHORAD self
|
||||||
|
function SHORAD:_InitState()
|
||||||
|
local table = {}
|
||||||
|
local set = self.Groupset
|
||||||
|
self:T({set = set})
|
||||||
|
local aliveset = set:GetAliveSet() --#table
|
||||||
|
for _,_group in pairs (aliveset) do
|
||||||
|
if self.UseAIOnOff then
|
||||||
|
_group:SetAIOff()
|
||||||
|
else
|
||||||
|
_group:OptionAlarmStateGreen() --Wrapper.Group#GROUP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- gather entropy
|
||||||
|
for i=1,10 do
|
||||||
|
math.random()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch debug state
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #boolean debug Switch debug on (true) or off (false)
|
||||||
|
function SHORAD:SwitchDebug(debug)
|
||||||
|
self:F( { debug } )
|
||||||
|
local onoff = debug or false
|
||||||
|
if debug then
|
||||||
|
self.debug = true
|
||||||
|
--tracing
|
||||||
|
BASE:TraceOn()
|
||||||
|
BASE:TraceClass("SHORAD")
|
||||||
|
else
|
||||||
|
self.debug = false
|
||||||
|
BASE:TraceOff()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch defense for HARMs
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #boolean onoff
|
||||||
|
function SHORAD:SwitchHARMDefense(onoff)
|
||||||
|
self:F( { onoff } )
|
||||||
|
local onoff = onoff or true
|
||||||
|
self.DefendHarms = onoff
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch defense for AGMs
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #boolean onoff
|
||||||
|
function SHORAD:SwitchAGMDefense(onoff)
|
||||||
|
self:F( { onoff } )
|
||||||
|
local onoff = onoff or true
|
||||||
|
self.DefendMavs = onoff
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set defense probability limits
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #number low Minimum detection limit, integer 1-100
|
||||||
|
-- @param #number high Maximum detection limit integer 1-100
|
||||||
|
function SHORAD:SetDefenseLimits(low,high)
|
||||||
|
self:F( { low, high } )
|
||||||
|
local low = low or 70
|
||||||
|
local high = high or 90
|
||||||
|
if (low < 0) or (low > 100) or (low > high) then
|
||||||
|
low = 70
|
||||||
|
end
|
||||||
|
if (high < 0) or (high > 100) or (high < low ) then
|
||||||
|
high = 90
|
||||||
|
end
|
||||||
|
self.DefenseLowProb = low
|
||||||
|
self.DefenseHighProb = high
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the number of seconds a SHORAD site will stay active
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #number seconds Number of seconds systems stay active
|
||||||
|
function SHORAD:SetActiveTimer(seconds)
|
||||||
|
local timer = seconds or 600
|
||||||
|
if timer < 0 then
|
||||||
|
timer = 600
|
||||||
|
end
|
||||||
|
self.ActiveTimer = timer
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the number of meters for the SHORAD defense zone
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #number meters Radius of the defense search zone in meters. #SHORADs in this range around a targeted group will go active
|
||||||
|
function SHORAD:SetDefenseRadius(meters)
|
||||||
|
local radius = meters or 20000
|
||||||
|
if radius < 0 then
|
||||||
|
radius = 20000
|
||||||
|
end
|
||||||
|
self.Radius = radius
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set using AI on/off instead of changing alarm state
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #boolean switch Decide if we are changing alarm state or AI state
|
||||||
|
function SHORAD:SetUsingAIOnOff(switch)
|
||||||
|
self.UseAIOnOff = switch or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a HARM was fired
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string WeaponName
|
||||||
|
-- @return #boolean Returns true for a match
|
||||||
|
function SHORAD:_CheckHarms(WeaponName)
|
||||||
|
self:F( { WeaponName } )
|
||||||
|
local hit = false
|
||||||
|
if self.DefendHarms then
|
||||||
|
for _,_name in pairs (SHORAD.Harms) do
|
||||||
|
if string.find(WeaponName,_name,1) then hit = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return hit
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if an AGM was fired
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string WeaponName
|
||||||
|
-- @return #boolean Returns true for a match
|
||||||
|
function SHORAD:_CheckMavs(WeaponName)
|
||||||
|
self:F( { WeaponName } )
|
||||||
|
local hit = false
|
||||||
|
if self.DefendMavs then
|
||||||
|
for _,_name in pairs (SHORAD.Mavs) do
|
||||||
|
if string.find(WeaponName,_name,1) then hit = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return hit
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check the coalition of the attacker
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string Coalition name
|
||||||
|
-- @return #boolean Returns false for a match
|
||||||
|
function SHORAD:_CheckCoalition(Coalition)
|
||||||
|
local owncoalition = self.Coalition
|
||||||
|
local othercoalition = ""
|
||||||
|
if Coalition == 0 then
|
||||||
|
othercoalition = "neutral"
|
||||||
|
elseif Coalition == 1 then
|
||||||
|
othercoalition = "red"
|
||||||
|
else
|
||||||
|
othercoalition = "blue"
|
||||||
|
end
|
||||||
|
self:T({owncoalition = owncoalition, othercoalition = othercoalition})
|
||||||
|
if owncoalition ~= othercoalition then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the missile is aimed at a SHORAD
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string TargetGroupName Name of the target group
|
||||||
|
-- @return #boolean Returns true for a match, else false
|
||||||
|
function SHORAD:_CheckShotAtShorad(TargetGroupName)
|
||||||
|
local tgtgrp = TargetGroupName
|
||||||
|
local shorad = self.Groupset
|
||||||
|
local shoradset = shorad:GetAliveSet() --#table
|
||||||
|
local returnname = false
|
||||||
|
for _,_groups in pairs (shoradset) do
|
||||||
|
local groupname = _groups:GetName()
|
||||||
|
if string.find(groupname, tgtgrp, 1) then
|
||||||
|
returnname = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return returnname
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the missile is aimed at a SAM site
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string TargetGroupName Name of the target group
|
||||||
|
-- @return #boolean Returns true for a match, else false
|
||||||
|
function SHORAD:_CheckShotAtSams(TargetGroupName)
|
||||||
|
local tgtgrp = TargetGroupName
|
||||||
|
local shorad = self.Samset
|
||||||
|
local shoradset = shorad:GetAliveSet() --#table
|
||||||
|
local returnname = false
|
||||||
|
for _,_groups in pairs (shoradset) do
|
||||||
|
local groupname = _groups:GetName()
|
||||||
|
if string.find(groupname, tgtgrp, 1) then
|
||||||
|
returnname = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return returnname
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculate if the missile shot is detected
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @return #boolean Returns true for a detection, else false
|
||||||
|
function SHORAD:_ShotIsDetected()
|
||||||
|
local IsDetected = false
|
||||||
|
local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value
|
||||||
|
local ActualDetection = math.random(1,100) -- value for this shot
|
||||||
|
if ActualDetection <= DetectionProb then
|
||||||
|
IsDetected = true
|
||||||
|
end
|
||||||
|
return IsDetected
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Wake up #SHORADs in a zone with diameter Radius for ActiveTimer seconds
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #string TargetGroup Name of the target group used to build the #ZONE
|
||||||
|
-- @param #number Radius Radius of the #ZONE
|
||||||
|
-- @param #number ActiveTimer Number of seconds to stay active
|
||||||
|
-- @usage Use this function to integrate with other systems, example
|
||||||
|
--
|
||||||
|
-- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()
|
||||||
|
-- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")
|
||||||
|
-- myshorad:SwitchDebug(true)
|
||||||
|
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||||
|
-- mymantis:AddShorad(myshorad,720)
|
||||||
|
-- mymantis:Start()
|
||||||
|
function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer)
|
||||||
|
self:F({TargetGroup, Radius, ActiveTimer})
|
||||||
|
local targetgroup = GROUP:FindByName(TargetGroup)
|
||||||
|
local targetzone = ZONE_GROUP:New("Shorad",targetgroup,Radius) -- create a defense zone to check
|
||||||
|
local groupset = self.Groupset --Core.Set#SET_GROUP
|
||||||
|
local shoradset = groupset:GetAliveSet() --#table
|
||||||
|
-- local function to switch off shorad again
|
||||||
|
local function SleepShorad(group)
|
||||||
|
local groupname = group:GetName()
|
||||||
|
self.ActiveGroups[groupname] = nil
|
||||||
|
if self.UseAIOnOff then
|
||||||
|
group:SetAIOff()
|
||||||
|
else
|
||||||
|
group:OptionAlarmStateGreen()
|
||||||
|
end
|
||||||
|
local text = string.format("Sleeping SHORAD %s", group:GetName())
|
||||||
|
self:T(text)
|
||||||
|
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||||
|
end
|
||||||
|
-- go through set and find the one(s) to activate
|
||||||
|
for _,_group in pairs (shoradset) do
|
||||||
|
if _group:IsAnyInZone(targetzone) then
|
||||||
|
local text = string.format("Waking up SHORAD %s", _group:GetName())
|
||||||
|
self:T(text)
|
||||||
|
local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug)
|
||||||
|
if self.UseAIOnOff then
|
||||||
|
_group:SetAIOn()
|
||||||
|
end
|
||||||
|
_group:OptionAlarmStateRed()
|
||||||
|
local groupname = _group:GetName()
|
||||||
|
if self.ActiveGroups[groupname] == nil then -- no timer yet for this group
|
||||||
|
self.ActiveGroups[groupname] = { Timing = ActiveTimer }
|
||||||
|
local endtime = timer.getTime() + (ActiveTimer * math.random(75,100) / 100 ) -- randomize wakeup a bit
|
||||||
|
timer.scheduleFunction(SleepShorad, _group, endtime)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Main function - work on the EventData
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
||||||
|
function SHORAD:OnEventShot( EventData )
|
||||||
|
self:F( { EventData } )
|
||||||
|
|
||||||
|
--local ShootingUnit = EventData.IniDCSUnit
|
||||||
|
--local ShootingUnitName = EventData.IniDCSUnitName
|
||||||
|
local ShootingWeapon = EventData.Weapon -- Identify the weapon fired
|
||||||
|
local ShootingWeaponName = EventData.WeaponName -- return weapon type
|
||||||
|
-- get firing coalition
|
||||||
|
local weaponcoalition = EventData.IniGroup:GetCoalition()
|
||||||
|
-- get detection probability
|
||||||
|
if self:_CheckCoalition(weaponcoalition) then --avoid overhead on friendly fire
|
||||||
|
local IsDetected = self:_ShotIsDetected()
|
||||||
|
-- convert to text
|
||||||
|
local DetectedText = "false"
|
||||||
|
if IsDetected then
|
||||||
|
DetectedText = "true"
|
||||||
|
end
|
||||||
|
local text = string.format("%s Missile Launched = %s | Detected probability state is %s", self.lid, ShootingWeaponName, DetectedText)
|
||||||
|
self:T( text )
|
||||||
|
local m = MESSAGE:New(text,15,"Info"):ToAllIf(self.debug)
|
||||||
|
--
|
||||||
|
if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then
|
||||||
|
-- get target data
|
||||||
|
local targetdata = EventData.Weapon:getTarget() -- Identify target
|
||||||
|
local targetunitname = Unit.getName(targetdata) -- Unit name
|
||||||
|
local targetgroup = Unit.getGroup(Weapon.getTarget(ShootingWeapon)) --targeted group
|
||||||
|
local targetgroupname = targetgroup:getName() -- group name
|
||||||
|
-- check if we or a SAM site are the target
|
||||||
|
--local TargetGroup = EventData.TgtGroup -- Wrapper.Group#GROUP
|
||||||
|
local shotatus = self:_CheckShotAtShorad(targetgroupname) --#boolean
|
||||||
|
local shotatsams = self:_CheckShotAtSams(targetgroupname) --#boolean
|
||||||
|
-- if being shot at, find closest SHORADs to activate
|
||||||
|
if shotatsams or shotatus then
|
||||||
|
self:T({shotatsams=shotatsams,shotatus=shotatus})
|
||||||
|
self:WakeUpShorad(targetgroupname, self.Radius, self.ActiveTimer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
end
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
-- SHORAD end
|
||||||
|
-----------------------------------------------------------------------
|
||||||
@@ -193,7 +193,13 @@
|
|||||||
-- warehouseBatumi:AddAsset("Huey", 5, WAREHOUSE.Attribute.AIR_TRANSPORTHELO)
|
-- warehouseBatumi:AddAsset("Huey", 5, WAREHOUSE.Attribute.AIR_TRANSPORTHELO)
|
||||||
--
|
--
|
||||||
-- This becomes important when assets are requested from other warehouses as described below. In this case, the five Hueys are now marked as transport helicopters and
|
-- This becomes important when assets are requested from other warehouses as described below. In this case, the five Hueys are now marked as transport helicopters and
|
||||||
-- not attack helicopters.
|
-- not attack helicopters. This is also particularly useful when adding assets to a warehouse with the intention of using them to transport other units that are part of
|
||||||
|
-- a subsequent request (see below). Setting the attribute will help to ensure that warehouse module can find the correct unit when attempting to service a request in its
|
||||||
|
-- queue. For example, if we want to add an Amphibious Landing Ship, even though most are indeed armed, it's recommended to do the following:
|
||||||
|
--
|
||||||
|
-- warehouseBatumi:AddAsset("Landing Ship", 1, WAREHOUSE.Attribute.NAVAL_UNARMEDSHIP)
|
||||||
|
--
|
||||||
|
-- Then when adding the request, you can simply specify WAREHOUSE.TransportType.SHIP (which corresponds to NAVAL_UNARMEDSHIP) as the TransportType.
|
||||||
--
|
--
|
||||||
-- ### Setting the Cargo Bay Weight Limit
|
-- ### Setting the Cargo Bay Weight Limit
|
||||||
-- You can ajust the cargo bay weight limit, in case it is not calculated correctly automatically. For example, the cargo bay of a C-17A is much smaller in DCS than that of a C-130, which is
|
-- You can ajust the cargo bay weight limit, in case it is not calculated correctly automatically. For example, the cargo bay of a C-17A is much smaller in DCS than that of a C-130, which is
|
||||||
@@ -1569,6 +1575,7 @@ WAREHOUSE = {
|
|||||||
delivered = {},
|
delivered = {},
|
||||||
defending = {},
|
defending = {},
|
||||||
portzone = nil,
|
portzone = nil,
|
||||||
|
harborzone = nil,
|
||||||
shippinglanes = {},
|
shippinglanes = {},
|
||||||
offroadpaths = {},
|
offroadpaths = {},
|
||||||
autodefence = false,
|
autodefence = false,
|
||||||
@@ -1731,6 +1738,9 @@ WAREHOUSE.TransportType = {
|
|||||||
APC = "Ground_APC",
|
APC = "Ground_APC",
|
||||||
TRAIN = "Ground_Train",
|
TRAIN = "Ground_Train",
|
||||||
SHIP = "Naval_UnarmedShip",
|
SHIP = "Naval_UnarmedShip",
|
||||||
|
AIRCRAFTCARRIER = "Naval_AircraftCarrier",
|
||||||
|
WARSHIP = "Naval_WarShip",
|
||||||
|
ARMEDSHIP = "Naval_ArmedShip",
|
||||||
SELFPROPELLED = "Selfpropelled",
|
SELFPROPELLED = "Selfpropelled",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1776,7 +1786,7 @@ WAREHOUSE.version="1.0.2"
|
|||||||
-- TODO: Make more examples: ARTY, CAP, ...
|
-- TODO: Make more examples: ARTY, CAP, ...
|
||||||
-- TODO: Check also general requests like all ground. Is this a problem for self propelled if immobile units are among the assets? Check if transport.
|
-- TODO: Check also general requests like all ground. Is this a problem for self propelled if immobile units are among the assets? Check if transport.
|
||||||
-- TODO: Handle the case when units of a group die during the transfer.
|
-- TODO: Handle the case when units of a group die during the transfer.
|
||||||
-- TODO: Added habours as interface for transport to from warehouses? Could make a rudimentary shipping dispatcher.
|
-- DONE: Added harbours as interface for transport to/from warehouses. Simplifies process of spawning units near the ship, especially if cargo not self-propelled.
|
||||||
-- DONE: Test capturing a neutral warehouse.
|
-- DONE: Test capturing a neutral warehouse.
|
||||||
-- DONE: Add save/load capability of warehouse <==> persistance after mission restart. Difficult in lua!
|
-- DONE: Add save/load capability of warehouse <==> persistance after mission restart. Difficult in lua!
|
||||||
-- DONE: Get cargo bay and weight from CARGO_GROUP and GROUP. No necessary any more!
|
-- DONE: Get cargo bay and weight from CARGO_GROUP and GROUP. No necessary any more!
|
||||||
@@ -1829,7 +1839,6 @@ WAREHOUSE.version="1.0.2"
|
|||||||
-- @param #string alias (Optional) Alias of the warehouse, i.e. the name it will be called when sending messages etc. Default is the name of the static
|
-- @param #string alias (Optional) Alias of the warehouse, i.e. the name it will be called when sending messages etc. Default is the name of the static
|
||||||
-- @return #WAREHOUSE self
|
-- @return #WAREHOUSE self
|
||||||
function WAREHOUSE:New(warehouse, alias)
|
function WAREHOUSE:New(warehouse, alias)
|
||||||
BASE:T({warehouse=warehouse})
|
|
||||||
|
|
||||||
-- Check if just a string was given and convert to static.
|
-- Check if just a string was given and convert to static.
|
||||||
if type(warehouse)=="string" then
|
if type(warehouse)=="string" then
|
||||||
@@ -2602,8 +2611,10 @@ end
|
|||||||
--- Check parking ID.
|
--- Check parking ID.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot Parking spot.
|
-- @param Wrapper.Airbase#AIRBASE.ParkingSpot spot Parking spot.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE airbase The airbase.
|
||||||
-- @return #boolean If true, parking is valid.
|
-- @return #boolean If true, parking is valid.
|
||||||
function WAREHOUSE:_CheckParkingValid(spot)
|
function WAREHOUSE:_CheckParkingValid(spot, airbase)
|
||||||
|
|
||||||
if self.parkingIDs==nil then
|
if self.parkingIDs==nil then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -2709,6 +2720,18 @@ function WAREHOUSE:SetPortZone(zone)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add a Harbor Zone for this warehouse where naval cargo units will spawn and be received.
|
||||||
|
-- Both warehouses must have the harbor zone defined for units to properly spawn on both the
|
||||||
|
-- sending and receiving side. The harbor zone should be within 3km of the port zone used for
|
||||||
|
-- warehouse in order to facilitate the boarding process.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param Core.Zone#ZONE zone The zone defining the naval embarcation/debarcation point for cargo units
|
||||||
|
-- @return #WAREHOUSE self
|
||||||
|
function WAREHOUSE:SetHarborZone(zone)
|
||||||
|
self.harborzone=zone
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Add a shipping lane from this warehouse to another remote warehouse.
|
--- Add a shipping lane from this warehouse to another remote warehouse.
|
||||||
-- Note that both warehouses must have a port zone defined before a shipping lane can be added!
|
-- Note that both warehouses must have a port zone defined before a shipping lane can be added!
|
||||||
-- Shipping lane is taken from the waypoints of a (late activated) template group. So set up a group, e.g. a ship or a helicopter, and place its
|
-- Shipping lane is taken from the waypoints of a (late activated) template group. So set up a group, e.g. a ship or a helicopter, and place its
|
||||||
@@ -4340,10 +4363,10 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request)
|
|||||||
self:_ErrorMessage("ERROR: Cargo transport by train not supported yet!")
|
self:_ErrorMessage("ERROR: Cargo transport by train not supported yet!")
|
||||||
return
|
return
|
||||||
|
|
||||||
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP then
|
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.NAVALCARRIER then
|
||||||
|
|
||||||
self:_ErrorMessage("ERROR: Cargo transport by ship not supported yet!")
|
-- Spawn Ship in port zone
|
||||||
return
|
spawngroup=self:_SpawnAssetGroundNaval(_alias, _assetitem, Request, self.portzone)
|
||||||
|
|
||||||
elseif Request.transporttype==WAREHOUSE.TransportType.SELFPROPELLED then
|
elseif Request.transporttype==WAREHOUSE.TransportType.SELFPROPELLED then
|
||||||
|
|
||||||
@@ -4471,6 +4494,9 @@ function WAREHOUSE:onafterRequestSpawned(From, Event, To, Request, CargoGroupSet
|
|||||||
--_boardradius=nil
|
--_boardradius=nil
|
||||||
elseif Request.transporttype==WAREHOUSE.TransportType.APC then
|
elseif Request.transporttype==WAREHOUSE.TransportType.APC then
|
||||||
--_boardradius=nil
|
--_boardradius=nil
|
||||||
|
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER
|
||||||
|
or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then
|
||||||
|
_boardradius=6000
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Empty cargo group set.
|
-- Empty cargo group set.
|
||||||
@@ -4481,7 +4507,6 @@ function WAREHOUSE:onafterRequestSpawned(From, Event, To, Request, CargoGroupSet
|
|||||||
|
|
||||||
-- Find asset belonging to this group.
|
-- Find asset belonging to this group.
|
||||||
local asset=self:FindAssetInDB(_group)
|
local asset=self:FindAssetInDB(_group)
|
||||||
|
|
||||||
-- New cargo group object.
|
-- New cargo group object.
|
||||||
local cargogroup=CARGO_GROUP:New(_group, _cargotype,_group:GetName(),_boardradius, asset.loadradius)
|
local cargogroup=CARGO_GROUP:New(_group, _cargotype,_group:GetName(),_boardradius, asset.loadradius)
|
||||||
|
|
||||||
@@ -4490,6 +4515,7 @@ function WAREHOUSE:onafterRequestSpawned(From, Event, To, Request, CargoGroupSet
|
|||||||
|
|
||||||
-- Add group to group set.
|
-- Add group to group set.
|
||||||
CargoGroups:AddCargo(cargogroup)
|
CargoGroups:AddCargo(cargogroup)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
@@ -4535,24 +4561,55 @@ function WAREHOUSE:onafterRequestSpawned(From, Event, To, Request, CargoGroupSet
|
|||||||
-- Set home zone.
|
-- Set home zone.
|
||||||
CargoTransport:SetHomeZone(self.spawnzone)
|
CargoTransport:SetHomeZone(self.spawnzone)
|
||||||
|
|
||||||
|
elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER
|
||||||
|
or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then
|
||||||
|
|
||||||
|
-- Pickup and deploy zones.
|
||||||
|
local PickupZoneSet = SET_ZONE:New():AddZone(self.portzone)
|
||||||
|
PickupZoneSet:AddZone(self.harborzone)
|
||||||
|
local DeployZoneSet = SET_ZONE:New():AddZone(Request.warehouse.harborzone)
|
||||||
|
|
||||||
|
|
||||||
|
-- Get the shipping lane to use and pass it to the Dispatcher
|
||||||
|
local remotename = Request.warehouse.warehouse:GetName()
|
||||||
|
local ShippingLane = self.shippinglanes[remotename][math.random(#self.shippinglanes[remotename])]
|
||||||
|
|
||||||
|
-- Define dispatcher for this task.
|
||||||
|
CargoTransport = AI_CARGO_DISPATCHER_SHIP:New(TransportGroupSet, CargoGroups, PickupZoneSet, DeployZoneSet, ShippingLane)
|
||||||
|
|
||||||
|
-- Set home zone
|
||||||
|
CargoTransport:SetHomeZone(self.portzone)
|
||||||
|
|
||||||
else
|
else
|
||||||
self:E(self.lid.."ERROR: Unknown transporttype!")
|
self:E(self.lid.."ERROR: Unknown transporttype!")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set pickup and deploy radii.
|
-- Set pickup and deploy radii.
|
||||||
-- The 20 m inner radius are to ensure that the helo does not land on the warehouse itself in the middle of the default spawn zone.
|
-- The 20 m inner radius are to ensure that the helo does not land on the warehouse itself in the middle of the default spawn zone.
|
||||||
local pickupouter=200
|
local pickupouter = 200
|
||||||
local pickupinner=0
|
local pickupinner = 0
|
||||||
|
local deployouter = 200
|
||||||
|
local deployinner = 0
|
||||||
|
if Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER
|
||||||
|
or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then
|
||||||
|
pickupouter=1000
|
||||||
|
pickupinner=20
|
||||||
|
deployouter=1000
|
||||||
|
deployinner=0
|
||||||
|
else
|
||||||
|
pickupouter=200
|
||||||
|
pickupinner=0
|
||||||
if self.spawnzone.Radius~=nil then
|
if self.spawnzone.Radius~=nil then
|
||||||
pickupouter=self.spawnzone.Radius
|
pickupouter=self.spawnzone.Radius
|
||||||
pickupinner=20
|
pickupinner=20
|
||||||
end
|
end
|
||||||
local deployouter=200
|
deployouter=200
|
||||||
local deployinner=0
|
deployinner=0
|
||||||
if self.spawnzone.Radius~=nil then
|
if self.spawnzone.Radius~=nil then
|
||||||
deployouter=Request.warehouse.spawnzone.Radius
|
deployouter=Request.warehouse.spawnzone.Radius
|
||||||
deployinner=20
|
deployinner=20
|
||||||
end
|
end
|
||||||
|
end
|
||||||
CargoTransport:SetPickupRadius(pickupouter, pickupinner)
|
CargoTransport:SetPickupRadius(pickupouter, pickupinner)
|
||||||
CargoTransport:SetDeployRadius(deployouter, deployinner)
|
CargoTransport:SetDeployRadius(deployouter, deployinner)
|
||||||
|
|
||||||
@@ -6925,11 +6982,16 @@ function WAREHOUSE:_CheckRequestValid(request)
|
|||||||
valid=false
|
valid=false
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif request.transporttype==WAREHOUSE.TransportType.SHIP then
|
elseif request.transporttype==WAREHOUSE.TransportType.SHIP or request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER
|
||||||
|
or request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or request.transporttype==WAREHOUSE.TransportType.WARSHIP then
|
||||||
|
|
||||||
-- Transport by ship.
|
-- Transport by ship.
|
||||||
self:E("ERROR: Incorrect request. Transport by SHIP not implemented yet!")
|
local shippinglane=self:HasConnectionNaval(request.warehouse)
|
||||||
|
|
||||||
|
if not shippinglane then
|
||||||
|
self:E("ERROR: Incorrect request. No shipping lane has been defined between warehouses!")
|
||||||
valid=false
|
valid=false
|
||||||
|
end
|
||||||
|
|
||||||
elseif request.transporttype==WAREHOUSE.TransportType.TRAIN then
|
elseif request.transporttype==WAREHOUSE.TransportType.TRAIN then
|
||||||
|
|
||||||
@@ -7025,7 +7087,7 @@ function WAREHOUSE:_CheckRequestNow(request)
|
|||||||
|
|
||||||
-- If no transport is requested, assets need to be mobile unless it is a self request.
|
-- If no transport is requested, assets need to be mobile unless it is a self request.
|
||||||
local onlymobile=false
|
local onlymobile=false
|
||||||
if type(request.transport)=="number" and request.ntransport==0 and not request.toself then
|
if type(request.ntransport)=="number" and request.ntransport==0 and not request.toself then
|
||||||
onlymobile=true
|
onlymobile=true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -7607,7 +7669,7 @@ function WAREHOUSE:_FindParkingForAssets(airbase, assets)
|
|||||||
local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot
|
local parkingspot=_parkingspot --Wrapper.Airbase#AIRBASE.ParkingSpot
|
||||||
|
|
||||||
-- Check correct terminal type for asset. We don't want helos in shelters etc.
|
-- Check correct terminal type for asset. We don't want helos in shelters etc.
|
||||||
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) and self:_CheckParkingValid(parkingspot) then
|
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) and self:_CheckParkingValid(parkingspot, airbase) and airbase:_CheckParkingLists(parkingspot.TerminalID) then
|
||||||
|
|
||||||
-- Coordinate of the parking spot.
|
-- Coordinate of the parking spot.
|
||||||
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
||||||
@@ -8052,10 +8114,9 @@ function WAREHOUSE:_GetAttribute(group)
|
|||||||
-- Ships
|
-- Ships
|
||||||
local aircraftcarrier=group:HasAttribute("Aircraft Carriers")
|
local aircraftcarrier=group:HasAttribute("Aircraft Carriers")
|
||||||
local warship=group:HasAttribute("Heavy armed ships")
|
local warship=group:HasAttribute("Heavy armed ships")
|
||||||
local armedship=group:HasAttribute("Armed ships")
|
local armedship=group:HasAttribute("Armed ships") or group:HasAttribute("Armed Ship")
|
||||||
local unarmedship=group:HasAttribute("Unarmed ships")
|
local unarmedship=group:HasAttribute("Unarmed ships")
|
||||||
|
|
||||||
|
|
||||||
-- Define attribute. Order is important.
|
-- Define attribute. Order is important.
|
||||||
if transportplane then
|
if transportplane then
|
||||||
attribute=WAREHOUSE.Attribute.AIR_TRANSPORTPLANE
|
attribute=WAREHOUSE.Attribute.AIR_TRANSPORTPLANE
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
__Moose.Include( 'Scripts/Moose/Utilities/Enums.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Enums.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/Routines.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Routines.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' )
|
||||||
@@ -24,6 +25,7 @@ __Moose.Include( 'Scripts/Moose/Core/RadioQueue.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Core/RadioSpeech.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/RadioSpeech.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Spawn.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Spawn.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/Timer.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@ __Moose.Include( 'Scripts/Moose/Wrapper/Client.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Static.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Static.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Airbase.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Airbase.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Scenery.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Scenery.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Wrapper/Marker.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Cargo/Cargo.lua' )
|
__Moose.Include( 'Scripts/Moose/Cargo/Cargo.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Cargo/CargoUnit.lua' )
|
__Moose.Include( 'Scripts/Moose/Cargo/CargoUnit.lua' )
|
||||||
@@ -64,6 +67,8 @@ __Moose.Include( 'Scripts/Moose/Functional/Suppression.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Functional/PseudoATC.lua' )
|
__Moose.Include( 'Scripts/Moose/Functional/PseudoATC.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Functional/Warehouse.lua' )
|
__Moose.Include( 'Scripts/Moose/Functional/Warehouse.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Functional/Fox.lua' )
|
__Moose.Include( 'Scripts/Moose/Functional/Fox.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Functional/Mantis.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Functional/Shorad.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' )
|
__Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' )
|
||||||
@@ -95,10 +100,12 @@ __Moose.Include( 'Scripts/Moose/AI/AI_Cargo.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_APC.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_APC.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Helicopter.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Helicopter.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Airplane.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Airplane.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Ship.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher_APC.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher_APC.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua' )
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/AI/AI_Cargo_Dispatcher_Ship.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Actions/Act_Assign.lua' )
|
__Moose.Include( 'Scripts/Moose/Actions/Act_Assign.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Actions/Act_Route.lua' )
|
__Moose.Include( 'Scripts/Moose/Actions/Act_Route.lua' )
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-- * Wind direction and speed
|
-- * Wind direction and speed
|
||||||
-- * Visibility
|
-- * Visibility
|
||||||
-- * Cloud coverage, base and ceiling
|
-- * Cloud coverage, base and ceiling
|
||||||
-- * Temprature
|
-- * Temperature
|
||||||
-- * Dew point (approximate as there is no relative humidity in DCS yet)
|
-- * Dew point (approximate as there is no relative humidity in DCS yet)
|
||||||
-- * Pressure QNH/QFE
|
-- * Pressure QNH/QFE
|
||||||
-- * Weather phenomena: rain, thunderstorm, fog, dust
|
-- * Weather phenomena: rain, thunderstorm, fog, dust
|
||||||
@@ -67,8 +67,10 @@
|
|||||||
-- @field #number subduration Duration how long subtitles are displayed in seconds.
|
-- @field #number subduration Duration how long subtitles are displayed in seconds.
|
||||||
-- @field #boolean metric If true, use metric units. If false, use imperial (default).
|
-- @field #boolean metric If true, use metric units. If false, use imperial (default).
|
||||||
-- @field #boolean PmmHg If true, give pressure in millimeters of Mercury. Default is inHg for imperial and hecto Pascal (=mili Bars) for metric units.
|
-- @field #boolean PmmHg If true, give pressure in millimeters of Mercury. Default is inHg for imperial and hecto Pascal (=mili Bars) for metric units.
|
||||||
|
-- @field #boolean qnhonly If true, suppresses reporting QFE. Default is to report both QNH and QFE.
|
||||||
-- @field #boolean TDegF If true, give temperature in degrees Fahrenheit. Default is in degrees Celsius independent of chosen unit system.
|
-- @field #boolean TDegF If true, give temperature in degrees Fahrenheit. Default is in degrees Celsius independent of chosen unit system.
|
||||||
-- @field #number zuludiff Time difference local vs. zulu in hours.
|
-- @field #number zuludiff Time difference local vs. zulu in hours.
|
||||||
|
-- @field #boolean zulutimeonly If true, suppresses report of local time, sunrise, and sunset.
|
||||||
-- @field #number magvar Magnetic declination/variation at the airport in degrees.
|
-- @field #number magvar Magnetic declination/variation at the airport in degrees.
|
||||||
-- @field #table ils Table of ILS frequencies (can be runway specific).
|
-- @field #table ils Table of ILS frequencies (can be runway specific).
|
||||||
-- @field #table ndbinner Table of inner NDB frequencies (can be runway specific).
|
-- @field #table ndbinner Table of inner NDB frequencies (can be runway specific).
|
||||||
@@ -302,8 +304,10 @@ ATIS = {
|
|||||||
subduration = nil,
|
subduration = nil,
|
||||||
metric = nil,
|
metric = nil,
|
||||||
PmmHg = nil,
|
PmmHg = nil,
|
||||||
|
qnhonly = false,
|
||||||
TDegF = nil,
|
TDegF = nil,
|
||||||
zuludiff = nil,
|
zuludiff = nil,
|
||||||
|
zulutimeonly = false,
|
||||||
magvar = nil,
|
magvar = nil,
|
||||||
ils = {},
|
ils = {},
|
||||||
ndbinner = {},
|
ndbinner = {},
|
||||||
@@ -362,11 +366,32 @@ ATIS.Alphabet = {
|
|||||||
-- @field #number Nevada +12° (East).
|
-- @field #number Nevada +12° (East).
|
||||||
-- @field #number Normandy -10° (West).
|
-- @field #number Normandy -10° (West).
|
||||||
-- @field #number PersianGulf +2° (East).
|
-- @field #number PersianGulf +2° (East).
|
||||||
|
-- @field #number TheChannel -10° (West).
|
||||||
|
-- @field #number Syria +5° (East).
|
||||||
ATIS.RunwayM2T={
|
ATIS.RunwayM2T={
|
||||||
Caucasus=0,
|
Caucasus=0,
|
||||||
Nevada=12,
|
Nevada=12,
|
||||||
Normany=-10,
|
Normandy=-10,
|
||||||
PersianGulf=2,
|
PersianGulf=2,
|
||||||
|
TheChannel=-10,
|
||||||
|
Syria=5,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Whether ICAO phraseology is used for ATIS broadcasts.
|
||||||
|
-- @type ATIS.ICAOPhraseology
|
||||||
|
-- @field #boolean Caucasus true.
|
||||||
|
-- @field #boolean Nevada false.
|
||||||
|
-- @field #boolean Normandy true.
|
||||||
|
-- @field #boolean PersianGulf true.
|
||||||
|
-- @field #boolean TheChannel true.
|
||||||
|
-- @field #boolean Syria true.
|
||||||
|
ATIS.ICAOPhraseology={
|
||||||
|
Caucasus=true,
|
||||||
|
Nevada=false,
|
||||||
|
Normandy=true,
|
||||||
|
PersianGulf=true,
|
||||||
|
TheChannel=true,
|
||||||
|
Syria=true,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Nav point data.
|
--- Nav point data.
|
||||||
@@ -415,6 +440,7 @@ ATIS.RunwayM2T={
|
|||||||
-- @field #ATIS.Soundfile MegaHertz
|
-- @field #ATIS.Soundfile MegaHertz
|
||||||
-- @field #ATIS.Soundfile Meters
|
-- @field #ATIS.Soundfile Meters
|
||||||
-- @field #ATIS.Soundfile MetersPerSecond
|
-- @field #ATIS.Soundfile MetersPerSecond
|
||||||
|
-- @field #ATIS.Soundfile Miles
|
||||||
-- @field #ATIS.Soundfile MillimetersOfMercury
|
-- @field #ATIS.Soundfile MillimetersOfMercury
|
||||||
-- @field #ATIS.Soundfile N0
|
-- @field #ATIS.Soundfile N0
|
||||||
-- @field #ATIS.Soundfile N1
|
-- @field #ATIS.Soundfile N1
|
||||||
@@ -434,6 +460,8 @@ ATIS.RunwayM2T={
|
|||||||
-- @field #ATIS.Soundfile Right
|
-- @field #ATIS.Soundfile Right
|
||||||
-- @field #ATIS.Soundfile Snow
|
-- @field #ATIS.Soundfile Snow
|
||||||
-- @field #ATIS.Soundfile SnowStorm
|
-- @field #ATIS.Soundfile SnowStorm
|
||||||
|
-- @field #ATIS.Soundfile SunriseAt
|
||||||
|
-- @field #ATIS.Soundfile SunsetAt
|
||||||
-- @field #ATIS.Soundfile Temperature
|
-- @field #ATIS.Soundfile Temperature
|
||||||
-- @field #ATIS.Soundfile Thousand
|
-- @field #ATIS.Soundfile Thousand
|
||||||
-- @field #ATIS.Soundfile ThunderStorm
|
-- @field #ATIS.Soundfile ThunderStorm
|
||||||
@@ -485,6 +513,7 @@ ATIS.Sound = {
|
|||||||
MegaHertz={filename="MegaHertz.ogg", duration=0.87},
|
MegaHertz={filename="MegaHertz.ogg", duration=0.87},
|
||||||
Meters={filename="Meters.ogg", duration=0.59},
|
Meters={filename="Meters.ogg", duration=0.59},
|
||||||
MetersPerSecond={filename="MetersPerSecond.ogg", duration=1.14},
|
MetersPerSecond={filename="MetersPerSecond.ogg", duration=1.14},
|
||||||
|
Miles={filename="Miles.ogg", duration=0.60},
|
||||||
MillimetersOfMercury={filename="MillimetersOfMercury.ogg", duration=1.53},
|
MillimetersOfMercury={filename="MillimetersOfMercury.ogg", duration=1.53},
|
||||||
Minus={filename="Minus.ogg", duration=0.64},
|
Minus={filename="Minus.ogg", duration=0.64},
|
||||||
N0={filename="N-0.ogg", duration=0.55},
|
N0={filename="N-0.ogg", duration=0.55},
|
||||||
@@ -505,6 +534,9 @@ ATIS.Sound = {
|
|||||||
Right={filename="Right.ogg", duration=0.44},
|
Right={filename="Right.ogg", duration=0.44},
|
||||||
Snow={filename="Snow.ogg", duration=0.48},
|
Snow={filename="Snow.ogg", duration=0.48},
|
||||||
SnowStorm={filename="SnowStorm.ogg", duration=0.82},
|
SnowStorm={filename="SnowStorm.ogg", duration=0.82},
|
||||||
|
StatuteMiles={filename="StatuteMiles.ogg", duration=1.15},
|
||||||
|
SunriseAt={filename="SunriseAt.ogg", duration=0.92},
|
||||||
|
SunsetAt={filename="SunsetAt.ogg", duration=0.95},
|
||||||
Temperature={filename="Temperature.ogg", duration=0.64},
|
Temperature={filename="Temperature.ogg", duration=0.64},
|
||||||
Thousand={filename="Thousand.ogg", duration=0.55},
|
Thousand={filename="Thousand.ogg", duration=0.55},
|
||||||
ThunderStorm={filename="ThunderStorm.ogg", duration=0.81},
|
ThunderStorm={filename="ThunderStorm.ogg", duration=0.81},
|
||||||
@@ -522,6 +554,7 @@ ATIS.Sound = {
|
|||||||
TACANChannel={filename="TACANChannel.ogg", duration=0.88},
|
TACANChannel={filename="TACANChannel.ogg", duration=0.88},
|
||||||
PRMGChannel={filename="PRMGChannel.ogg", duration=1.18},
|
PRMGChannel={filename="PRMGChannel.ogg", duration=1.18},
|
||||||
RSBNChannel={filename="RSBNChannel.ogg", duration=1.14},
|
RSBNChannel={filename="RSBNChannel.ogg", duration=1.14},
|
||||||
|
Zulu={filename="Zulu.ogg", duration=0.62},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -531,7 +564,7 @@ _ATIS={}
|
|||||||
|
|
||||||
--- ATIS class version.
|
--- ATIS class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ATIS.version="0.7.1"
|
ATIS.version="0.9.1"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -547,6 +580,8 @@ ATIS.version="0.7.1"
|
|||||||
-- DONE: Metric units.
|
-- DONE: Metric units.
|
||||||
-- DONE: Set UTC correction.
|
-- DONE: Set UTC correction.
|
||||||
-- DONE: Set magnetic variation.
|
-- DONE: Set magnetic variation.
|
||||||
|
-- DONE: New DCS 2.7 weather presets.
|
||||||
|
-- DONE: whatever
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
@@ -894,6 +929,14 @@ function ATIS:SetAltimeterQNH(switch)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Suppresses QFE readout. Default is to report both QNH and QFE.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:ReportQNHOnly()
|
||||||
|
self.qnhonly=true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set magnetic declination/variation at the airport.
|
--- Set magnetic declination/variation at the airport.
|
||||||
--
|
--
|
||||||
-- Default is per map:
|
-- Default is per map:
|
||||||
@@ -943,9 +986,10 @@ end
|
|||||||
-- Default is per map:
|
-- Default is per map:
|
||||||
--
|
--
|
||||||
-- * Caucasus +4
|
-- * Caucasus +4
|
||||||
-- * Nevada -7
|
-- * Nevada -8
|
||||||
-- * Normandy +1
|
-- * Normandy 0
|
||||||
-- * Persian Gulf +4
|
-- * Persian Gulf +4
|
||||||
|
-- * The Channel +2 (should be 0)
|
||||||
--
|
--
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @param #number delta Time difference in hours.
|
-- @param #number delta Time difference in hours.
|
||||||
@@ -955,6 +999,14 @@ function ATIS:SetZuluTimeDifference(delta)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Suppresses local time, sunrise, and sunset. Default is to report all these times.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:ReportZuluTimeOnly()
|
||||||
|
self.zulutimeonly=true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Add ILS station. Note that this can be runway specific.
|
--- Add ILS station. Note that this can be runway specific.
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @param #number frequency ILS frequency in MHz.
|
-- @param #number frequency ILS frequency in MHz.
|
||||||
@@ -1245,8 +1297,6 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
WINDFROM="360"
|
WINDFROM="360"
|
||||||
end
|
end
|
||||||
|
|
||||||
env.info(string.format("FF WINDFROM = %s", tostring(WINDFROM)))
|
|
||||||
|
|
||||||
if self.metric then
|
if self.metric then
|
||||||
WINDSPEED=string.format("%d", windSpeed)
|
WINDSPEED=string.format("%d", windSpeed)
|
||||||
end
|
end
|
||||||
@@ -1267,15 +1317,11 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
-- User specified.
|
-- User specified.
|
||||||
time=time-self.zuludiff*60*60
|
time=time-self.zuludiff*60*60
|
||||||
else
|
else
|
||||||
if self.theatre==DCSMAP.Caucasus then
|
time=time-UTILS.GMTToLocalTimeDifference()*60*60
|
||||||
time=time-4*60*60 -- Caucasus UTC+4 hours
|
|
||||||
elseif self.theatre==DCSMAP.PersianGulf then
|
|
||||||
time=time-4*60*60 -- Abu Dhabi UTC+4 hours
|
|
||||||
elseif self.theatre==DCSMAP.NTTR then
|
|
||||||
time=time+7*60*60 -- Las Vegas UTC-7 hours
|
|
||||||
elseif self.theatre==DCSMAP.Normandy then
|
|
||||||
time=time-1*60*60 -- Calais UTC+1 hour
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if time < 0 then
|
||||||
|
time = 24*60*60 + time --avoid negative time around midnight
|
||||||
end
|
end
|
||||||
|
|
||||||
local clock=UTILS.SecondsToClock(time)
|
local clock=UTILS.SecondsToClock(time)
|
||||||
@@ -1293,6 +1339,18 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
self:T3(string.format("ZULU =%s", tostring(ZULU)))
|
self:T3(string.format("ZULU =%s", tostring(ZULU)))
|
||||||
self:T3(string.format("NATO =%s", tostring(NATO)))
|
self:T3(string.format("NATO =%s", tostring(NATO)))
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
--- Sunrise and Sunset ---
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
local sunrise=coord:GetSunrise()
|
||||||
|
sunrise=UTILS.Split(sunrise, ":")
|
||||||
|
local SUNRISE=string.format("%s%s", sunrise[1], sunrise[2])
|
||||||
|
|
||||||
|
local sunset=coord:GetSunset()
|
||||||
|
sunset=UTILS.Split(sunset, ":")
|
||||||
|
local SUNSET=string.format("%s%s", sunset[1], sunset[2])
|
||||||
|
|
||||||
---------------------------------
|
---------------------------------
|
||||||
--- Temperature and Dew Point ---
|
--- Temperature and Dew Point ---
|
||||||
---------------------------------
|
---------------------------------
|
||||||
@@ -1348,12 +1406,23 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Visibility in NM.
|
local VISIBILITY=""
|
||||||
local VISIBILITY=string.format("%d", UTILS.Round(UTILS.MetersToNM(visibilitymin)))
|
|
||||||
|
|
||||||
-- Visibility in km.
|
|
||||||
if self.metric then
|
if self.metric then
|
||||||
VISIBILITY=string.format("%d", UTILS.Round(visibilitymin/1000))
|
-- Visibility in km.
|
||||||
|
local reportedviz=UTILS.Round(visibilitymin/1000)
|
||||||
|
-- max reported visibility 9999 m
|
||||||
|
if reportedviz > 10 then
|
||||||
|
reportedviz=10
|
||||||
|
end
|
||||||
|
VISIBILITY=string.format("%d", reportedviz)
|
||||||
|
else
|
||||||
|
-- max reported visibility 10 NM
|
||||||
|
local reportedviz=UTILS.Round(UTILS.MetersToSM(visibilitymin))
|
||||||
|
if reportedviz > 10 then
|
||||||
|
reportedviz=10
|
||||||
|
end
|
||||||
|
VISIBILITY=string.format("%d", reportedviz)
|
||||||
end
|
end
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
@@ -1364,8 +1433,102 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
local cloudceil=clouds.base+clouds.thickness
|
local cloudceil=clouds.base+clouds.thickness
|
||||||
local clouddens=clouds.density
|
local clouddens=clouds.density
|
||||||
|
|
||||||
|
-- Cloud preset (DCS 2.7)
|
||||||
|
local cloudspreset=clouds.preset or "Nothing"
|
||||||
|
|
||||||
-- Precepitation: 0=None, 1=Rain, 2=Thunderstorm, 3=Snow, 4=Snowstorm.
|
-- Precepitation: 0=None, 1=Rain, 2=Thunderstorm, 3=Snow, 4=Snowstorm.
|
||||||
local precepitation=tonumber(clouds.iprecptns)
|
local precepitation=0
|
||||||
|
|
||||||
|
if cloudspreset:find("Preset10") then
|
||||||
|
-- Scattered 5
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset11") then
|
||||||
|
-- Scattered 6
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset12") then
|
||||||
|
-- Scattered 7
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset13") then
|
||||||
|
-- Broken 1
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset14") then
|
||||||
|
-- Broken 2
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset15") then
|
||||||
|
-- Broken 3
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset16") then
|
||||||
|
-- Broken 4
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset17") then
|
||||||
|
-- Broken 5
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset18") then
|
||||||
|
-- Broken 6
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset19") then
|
||||||
|
-- Broken 7
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset20") then
|
||||||
|
-- Broken 8
|
||||||
|
clouddens=7
|
||||||
|
elseif cloudspreset:find("Preset21") then
|
||||||
|
-- Overcast 1
|
||||||
|
clouddens=9
|
||||||
|
elseif cloudspreset:find("Preset22") then
|
||||||
|
-- Overcast 2
|
||||||
|
clouddens=9
|
||||||
|
elseif cloudspreset:find("Preset23") then
|
||||||
|
-- Overcast 3
|
||||||
|
clouddens=9
|
||||||
|
elseif cloudspreset:find("Preset24") then
|
||||||
|
-- Overcast 4
|
||||||
|
clouddens=9
|
||||||
|
elseif cloudspreset:find("Preset25") then
|
||||||
|
-- Overcast 5
|
||||||
|
clouddens=9
|
||||||
|
elseif cloudspreset:find("Preset26") then
|
||||||
|
-- Overcast 6
|
||||||
|
clouddens=9
|
||||||
|
elseif cloudspreset:find("Preset27") then
|
||||||
|
-- Overcast 7
|
||||||
|
clouddens=9
|
||||||
|
elseif cloudspreset:find("Preset1") then
|
||||||
|
-- Light Scattered 1
|
||||||
|
clouddens=1
|
||||||
|
elseif cloudspreset:find("Preset2") then
|
||||||
|
-- Light Scattered 2
|
||||||
|
clouddens=1
|
||||||
|
elseif cloudspreset:find("Preset3") then
|
||||||
|
-- High Scattered 1
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset4") then
|
||||||
|
-- High Scattered 2
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset5") then
|
||||||
|
-- Scattered 1
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset6") then
|
||||||
|
-- Scattered 2
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset7") then
|
||||||
|
-- Scattered 3
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset8") then
|
||||||
|
-- High Scattered 3
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("Preset9") then
|
||||||
|
-- Scattered 4
|
||||||
|
clouddens=4
|
||||||
|
elseif cloudspreset:find("RainyPreset") then
|
||||||
|
-- Overcast + Rain
|
||||||
|
clouddens=9
|
||||||
|
if temperature>5 then
|
||||||
|
precepitation=1 -- rain
|
||||||
|
else
|
||||||
|
precepitation=3 -- snow
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local CLOUDBASE=string.format("%d", UTILS.MetersToFeet(cloudbase))
|
local CLOUDBASE=string.format("%d", UTILS.MetersToFeet(cloudbase))
|
||||||
local CLOUDCEIL=string.format("%d", UTILS.MetersToFeet(cloudceil))
|
local CLOUDCEIL=string.format("%d", UTILS.MetersToFeet(cloudceil))
|
||||||
@@ -1441,57 +1604,62 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
-- Zulu Time
|
-- Zulu Time
|
||||||
subtitle=string.format("%s Zulu", ZULU)
|
subtitle=string.format("%s Zulu", ZULU)
|
||||||
self.radioqueue:Number2Transmission(ZULU, nil, 0.5)
|
self.radioqueue:Number2Transmission(ZULU, nil, 0.5)
|
||||||
self:Transmission(ATIS.Sound.TimeZulu, 0.2, subtitle)
|
self:Transmission(ATIS.Sound.Zulu, 0.2, subtitle)
|
||||||
|
alltext=alltext..";\n"..subtitle
|
||||||
|
|
||||||
|
if not self.zulutimeonly then
|
||||||
|
|
||||||
|
-- Sunrise Time
|
||||||
|
subtitle=string.format("Sunrise at %s local time", SUNRISE)
|
||||||
|
self:Transmission(ATIS.Sound.SunriseAt, 0.5, subtitle)
|
||||||
|
self.radioqueue:Number2Transmission(SUNRISE, nil, 0.2)
|
||||||
|
self:Transmission(ATIS.Sound.TimeLocal, 0.2)
|
||||||
|
alltext=alltext..";\n"..subtitle
|
||||||
|
|
||||||
|
-- Sunset Time
|
||||||
|
subtitle=string.format("Sunset at %s local time", SUNSET)
|
||||||
|
self:Transmission(ATIS.Sound.SunsetAt, 0.5, subtitle)
|
||||||
|
self.radioqueue:Number2Transmission(SUNSET, nil, 0.5)
|
||||||
|
self:Transmission(ATIS.Sound.TimeLocal, 0.2)
|
||||||
|
alltext=alltext..";\n"..subtitle
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wind
|
||||||
|
if self.metric then
|
||||||
|
subtitle=string.format("Wind from %s at %s m/s", WINDFROM, WINDSPEED)
|
||||||
|
else
|
||||||
|
subtitle=string.format("Wind from %s at %s knots", WINDFROM, WINDSPEED)
|
||||||
|
end
|
||||||
|
if turbulence>0 then
|
||||||
|
subtitle=subtitle..", gusting"
|
||||||
|
end
|
||||||
|
local _WIND=subtitle
|
||||||
|
self:Transmission(ATIS.Sound.WindFrom, 1.0, subtitle)
|
||||||
|
self.radioqueue:Number2Transmission(WINDFROM)
|
||||||
|
self:Transmission(ATIS.Sound.At, 0.2)
|
||||||
|
self.radioqueue:Number2Transmission(WINDSPEED)
|
||||||
|
if self.metric then
|
||||||
|
self:Transmission(ATIS.Sound.MetersPerSecond, 0.2)
|
||||||
|
else
|
||||||
|
self:Transmission(ATIS.Sound.Knots, 0.2)
|
||||||
|
end
|
||||||
|
if turbulence>0 then
|
||||||
|
self:Transmission(ATIS.Sound.Gusting, 0.2)
|
||||||
|
end
|
||||||
alltext=alltext..";\n"..subtitle
|
alltext=alltext..";\n"..subtitle
|
||||||
|
|
||||||
-- Visibility
|
-- Visibility
|
||||||
if self.metric then
|
if self.metric then
|
||||||
subtitle=string.format("Visibility %s km", VISIBILITY)
|
subtitle=string.format("Visibility %s km", VISIBILITY)
|
||||||
else
|
else
|
||||||
subtitle=string.format("Visibility %s NM", VISIBILITY)
|
subtitle=string.format("Visibility %s SM", VISIBILITY)
|
||||||
end
|
end
|
||||||
self:Transmission(ATIS.Sound.Visibilty, 1.0, subtitle)
|
self:Transmission(ATIS.Sound.Visibilty, 1.0, subtitle)
|
||||||
self.radioqueue:Number2Transmission(VISIBILITY)
|
self.radioqueue:Number2Transmission(VISIBILITY)
|
||||||
if self.metric then
|
if self.metric then
|
||||||
self:Transmission(ATIS.Sound.Kilometers, 0.2)
|
self:Transmission(ATIS.Sound.Kilometers, 0.2)
|
||||||
else
|
else
|
||||||
self:Transmission(ATIS.Sound.NauticalMiles, 0.2)
|
self:Transmission(ATIS.Sound.StatuteMiles, 0.2)
|
||||||
end
|
|
||||||
alltext=alltext..";\n"..subtitle
|
|
||||||
|
|
||||||
-- Cloud base
|
|
||||||
self:Transmission(CloudCover, 1.0, CLOUDSsub)
|
|
||||||
if CLOUDBASE and static then
|
|
||||||
-- Base
|
|
||||||
if self.metric then
|
|
||||||
subtitle=string.format("Cloudbase %s, ceiling %s meters", CLOUDBASE, CLOUDCEIL)
|
|
||||||
else
|
|
||||||
subtitle=string.format("Cloudbase %s, ceiling %s ft", CLOUDBASE, CLOUDCEIL)
|
|
||||||
end
|
|
||||||
self:Transmission(ATIS.Sound.CloudBase, 1.0, subtitle)
|
|
||||||
if tonumber(CLOUDBASE1000)>0 then
|
|
||||||
self.radioqueue:Number2Transmission(CLOUDBASE1000)
|
|
||||||
self:Transmission(ATIS.Sound.Thousand, 0.1)
|
|
||||||
end
|
|
||||||
if tonumber(CLOUDBASE0100)>0 then
|
|
||||||
self.radioqueue:Number2Transmission(CLOUDBASE0100)
|
|
||||||
self:Transmission(ATIS.Sound.Hundred, 0.1)
|
|
||||||
end
|
|
||||||
-- Ceiling
|
|
||||||
self:Transmission(ATIS.Sound.CloudCeiling, 0.5)
|
|
||||||
if tonumber(CLOUDCEIL1000)>0 then
|
|
||||||
self.radioqueue:Number2Transmission(CLOUDCEIL1000)
|
|
||||||
self:Transmission(ATIS.Sound.Thousand, 0.1)
|
|
||||||
end
|
|
||||||
if tonumber(CLOUDCEIL0100)>0 then
|
|
||||||
self.radioqueue:Number2Transmission(CLOUDCEIL0100)
|
|
||||||
self:Transmission(ATIS.Sound.Hundred, 0.1)
|
|
||||||
end
|
|
||||||
if self.metric then
|
|
||||||
self:Transmission(ATIS.Sound.Meters, 0.1)
|
|
||||||
else
|
|
||||||
self:Transmission(ATIS.Sound.Feet, 0.1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
alltext=alltext..";\n"..subtitle
|
alltext=alltext..";\n"..subtitle
|
||||||
|
|
||||||
@@ -1550,33 +1718,38 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
alltext=alltext..";\n"..subtitle
|
alltext=alltext..";\n"..subtitle
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Altimeter QNH/QFE.
|
-- Cloud base
|
||||||
if self.PmmHg then
|
self:Transmission(CloudCover, 1.0, CLOUDSsub)
|
||||||
subtitle=string.format("Altimeter QNH %s.%s, QFE %s.%s mmHg", QNH[1], QNH[2], QFE[1], QFE[2])
|
if CLOUDBASE and static then
|
||||||
else
|
-- Base
|
||||||
if self.metric then
|
if self.metric then
|
||||||
subtitle=string.format("Altimeter QNH %s.%s, QFE %s.%s hPa", QNH[1], QNH[2], QFE[1], QFE[2])
|
subtitle=string.format("Cloudbase %s, ceiling %s meters", CLOUDBASE, CLOUDCEIL)
|
||||||
else
|
else
|
||||||
subtitle=string.format("Altimeter QNH %s.%s, QFE %s.%s inHg", QNH[1], QNH[2], QFE[1], QFE[2])
|
subtitle=string.format("Cloudbase %s, ceiling %s ft", CLOUDBASE, CLOUDCEIL)
|
||||||
end
|
end
|
||||||
|
self:Transmission(ATIS.Sound.CloudBase, 1.0, subtitle)
|
||||||
|
if tonumber(CLOUDBASE1000)>0 then
|
||||||
|
self.radioqueue:Number2Transmission(CLOUDBASE1000)
|
||||||
|
self:Transmission(ATIS.Sound.Thousand, 0.1)
|
||||||
|
end
|
||||||
|
if tonumber(CLOUDBASE0100)>0 then
|
||||||
|
self.radioqueue:Number2Transmission(CLOUDBASE0100)
|
||||||
|
self:Transmission(ATIS.Sound.Hundred, 0.1)
|
||||||
|
end
|
||||||
|
-- Ceiling
|
||||||
|
self:Transmission(ATIS.Sound.CloudCeiling, 0.5)
|
||||||
|
if tonumber(CLOUDCEIL1000)>0 then
|
||||||
|
self.radioqueue:Number2Transmission(CLOUDCEIL1000)
|
||||||
|
self:Transmission(ATIS.Sound.Thousand, 0.1)
|
||||||
|
end
|
||||||
|
if tonumber(CLOUDCEIL0100)>0 then
|
||||||
|
self.radioqueue:Number2Transmission(CLOUDCEIL0100)
|
||||||
|
self:Transmission(ATIS.Sound.Hundred, 0.1)
|
||||||
end
|
end
|
||||||
local _ALTIMETER=subtitle
|
|
||||||
self:Transmission(ATIS.Sound.Altimeter, 1.0, subtitle)
|
|
||||||
self:Transmission(ATIS.Sound.QNH, 0.5)
|
|
||||||
self.radioqueue:Number2Transmission(QNH[1])
|
|
||||||
self:Transmission(ATIS.Sound.Decimal, 0.2)
|
|
||||||
self.radioqueue:Number2Transmission(QNH[2])
|
|
||||||
self:Transmission(ATIS.Sound.QFE, 0.75)
|
|
||||||
self.radioqueue:Number2Transmission(QFE[1])
|
|
||||||
self:Transmission(ATIS.Sound.Decimal, 0.2)
|
|
||||||
self.radioqueue:Number2Transmission(QFE[2])
|
|
||||||
if self.PmmHg then
|
|
||||||
self:Transmission(ATIS.Sound.MillimetersOfMercury, 0.1)
|
|
||||||
else
|
|
||||||
if self.metric then
|
if self.metric then
|
||||||
self:Transmission(ATIS.Sound.HectoPascal, 0.1)
|
self:Transmission(ATIS.Sound.Meters, 0.1)
|
||||||
else
|
else
|
||||||
self:Transmission(ATIS.Sound.InchesOfMercury, 0.1)
|
self:Transmission(ATIS.Sound.Feet, 0.1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alltext=alltext..";\n"..subtitle
|
alltext=alltext..";\n"..subtitle
|
||||||
@@ -1635,27 +1808,57 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
end
|
end
|
||||||
alltext=alltext..";\n"..subtitle
|
alltext=alltext..";\n"..subtitle
|
||||||
|
|
||||||
-- Wind
|
-- Altimeter QNH/QFE.
|
||||||
if self.metric then
|
if self.PmmHg then
|
||||||
subtitle=string.format("Wind from %s at %s m/s", WINDFROM, WINDSPEED)
|
if self.qnhonly then
|
||||||
|
subtitle=string.format("Altimeter %s.%s mmHg", QNH[1], QNH[2])
|
||||||
else
|
else
|
||||||
subtitle=string.format("Wind from %s at %s knots", WINDFROM, WINDSPEED)
|
subtitle=string.format("Altimeter QNH %s.%s, QFE %s.%s mmHg", QNH[1], QNH[2], QFE[1], QFE[2])
|
||||||
end
|
end
|
||||||
if turbulence>0 then
|
|
||||||
subtitle=subtitle..", gusting"
|
|
||||||
end
|
|
||||||
local _WIND=subtitle
|
|
||||||
self:Transmission(ATIS.Sound.WindFrom, 1.0, subtitle)
|
|
||||||
self.radioqueue:Number2Transmission(WINDFROM)
|
|
||||||
self:Transmission(ATIS.Sound.At, 0.2)
|
|
||||||
self.radioqueue:Number2Transmission(WINDSPEED)
|
|
||||||
if self.metric then
|
|
||||||
self:Transmission(ATIS.Sound.MetersPerSecond, 0.2)
|
|
||||||
else
|
else
|
||||||
self:Transmission(ATIS.Sound.Knots, 0.2)
|
if self.metric then
|
||||||
|
if self.qnhonly then
|
||||||
|
subtitle=string.format("Altimeter %s.%s hPa", QNH[1], QNH[2])
|
||||||
|
else
|
||||||
|
subtitle=string.format("Altimeter QNH %s.%s, QFE %s.%s hPa", QNH[1], QNH[2], QFE[1], QFE[2])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if self.qnhonly then
|
||||||
|
subtitle=string.format("Altimeter %s.%s inHg", QNH[1], QNH[2])
|
||||||
|
else
|
||||||
|
subtitle=string.format("Altimeter QNH %s.%s, QFE %s.%s inHg", QNH[1], QNH[2], QFE[1], QFE[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local _ALTIMETER=subtitle
|
||||||
|
self:Transmission(ATIS.Sound.Altimeter, 1.0, subtitle)
|
||||||
|
if not self.qnhonly then
|
||||||
|
self:Transmission(ATIS.Sound.QNH, 0.5)
|
||||||
|
end
|
||||||
|
self.radioqueue:Number2Transmission(QNH[1])
|
||||||
|
|
||||||
|
if ATIS.ICAOPhraseology[UTILS.GetDCSMap()] then
|
||||||
|
self:Transmission(ATIS.Sound.Decimal, 0.2)
|
||||||
|
end
|
||||||
|
self.radioqueue:Number2Transmission(QNH[2])
|
||||||
|
|
||||||
|
if not self.qnhonly then
|
||||||
|
self:Transmission(ATIS.Sound.QFE, 0.75)
|
||||||
|
self.radioqueue:Number2Transmission(QFE[1])
|
||||||
|
if ATIS.ICAOPhraseology[UTILS.GetDCSMap()] then
|
||||||
|
self:Transmission(ATIS.Sound.Decimal, 0.2)
|
||||||
|
end
|
||||||
|
self.radioqueue:Number2Transmission(QFE[2])
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.PmmHg then
|
||||||
|
self:Transmission(ATIS.Sound.MillimetersOfMercury, 0.1)
|
||||||
|
else
|
||||||
|
if self.metric then
|
||||||
|
self:Transmission(ATIS.Sound.HectoPascal, 0.1)
|
||||||
|
else
|
||||||
|
self:Transmission(ATIS.Sound.InchesOfMercury, 0.1)
|
||||||
end
|
end
|
||||||
if turbulence>0 then
|
|
||||||
self:Transmission(ATIS.Sound.Gusting, 0.2)
|
|
||||||
end
|
end
|
||||||
alltext=alltext..";\n"..subtitle
|
alltext=alltext..";\n"..subtitle
|
||||||
|
|
||||||
@@ -1874,13 +2077,6 @@ function ATIS:onafterBroadcast(From, Event, To)
|
|||||||
alltext=alltext..";\n"..subtitle
|
alltext=alltext..";\n"..subtitle
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
|
||||||
-- End of Information Alpha, Bravo, ...
|
|
||||||
subtitle=string.format("End of information %s", NATO)
|
|
||||||
self:Transmission(ATIS.Sound.EndOfInformation, 0.5, subtitle)
|
|
||||||
self.radioqueue:NewTransmission(string.format("NATO Alphabet/%s.ogg", NATO), 0.75, self.soundpath)
|
|
||||||
--]]
|
|
||||||
|
|
||||||
-- Advice on initial...
|
-- Advice on initial...
|
||||||
subtitle=string.format("Advise on initial contact, you have information %s", NATO)
|
subtitle=string.format("Advise on initial contact, you have information %s", NATO)
|
||||||
self:Transmission(ATIS.Sound.AdviceOnInitial, 0.5, subtitle)
|
self:Transmission(ATIS.Sound.AdviceOnInitial, 0.5, subtitle)
|
||||||
|
|||||||
@@ -27,12 +27,16 @@
|
|||||||
-- **Supported Carriers:**
|
-- **Supported Carriers:**
|
||||||
--
|
--
|
||||||
-- * [USS John C. Stennis](https://en.wikipedia.org/wiki/USS_John_C._Stennis) (CVN-74)
|
-- * [USS John C. Stennis](https://en.wikipedia.org/wiki/USS_John_C._Stennis) (CVN-74)
|
||||||
|
-- * [USS Theodore Roosevelt](https://en.wikipedia.org/wiki/USS_Theodore_Roosevelt_(CVN-71)) (CVN-71) [Super Carrier Module]
|
||||||
|
-- * [USS Abraham Lincoln](https://en.wikipedia.org/wiki/USS_Abraham_Lincoln_(CVN-72)) (CVN-72) [Super Carrier Module]
|
||||||
|
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_(CVN-73)) (CVN-73) [Super Carrier Module]
|
||||||
|
-- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module]
|
||||||
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1)) (LHA-1) [**WIP**]
|
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1)) (LHA-1) [**WIP**]
|
||||||
--
|
--
|
||||||
-- **Supported Aircraft:**
|
-- **Supported Aircraft:**
|
||||||
--
|
--
|
||||||
-- * [F/A-18C Hornet Lot 20](https://forums.eagle.ru/forumdisplay.php?f=557) (Player & AI)
|
-- * [F/A-18C Hornet Lot 20](https://forums.eagle.ru/forumdisplay.php?f=557) (Player & AI)
|
||||||
-- * [F-14B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
|
-- * [F-14A/B Tomcat](https://forums.eagle.ru/forumdisplay.php?f=395) (Player & AI)
|
||||||
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
|
-- * [A-4E Skyhawk Community Mod](https://forums.eagle.ru/showthread.php?t=224989) (Player & AI)
|
||||||
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) [**WIP**]
|
-- * [AV-8B N/A Harrier](https://forums.eagle.ru/forumdisplay.php?f=555) (Player & AI) [**WIP**]
|
||||||
-- * F/A-18C Hornet (AI)
|
-- * F/A-18C Hornet (AI)
|
||||||
@@ -47,7 +51,9 @@
|
|||||||
-- the no other fixed wing aircraft (human or AI controlled) are supposed to land on the Tarawa. Currently only Case I is supported. Case II/III take slightly steps from the CVN carrier.
|
-- the no other fixed wing aircraft (human or AI controlled) are supposed to land on the Tarawa. Currently only Case I is supported. Case II/III take slightly steps from the CVN carrier.
|
||||||
-- However, the two Case II/III pattern are very similar so this is not a big drawback.
|
-- However, the two Case II/III pattern are very similar so this is not a big drawback.
|
||||||
--
|
--
|
||||||
-- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well.
|
-- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well. Same goes for the A version.
|
||||||
|
--
|
||||||
|
-- The [DCS Supercarriers](https://forums.eagle.ru/forum/151-dcs-supercarrier/) are also supported.
|
||||||
--
|
--
|
||||||
-- ## Discussion
|
-- ## Discussion
|
||||||
--
|
--
|
||||||
@@ -1261,7 +1267,7 @@ AIRBOSS.AircraftCarrier={
|
|||||||
AV8B="AV8BNA",
|
AV8B="AV8BNA",
|
||||||
HORNET="FA-18C_hornet",
|
HORNET="FA-18C_hornet",
|
||||||
A4EC="A-4E-C",
|
A4EC="A-4E-C",
|
||||||
F14A="F-14A_tomcat",
|
F14A="F-14A-135-GR",
|
||||||
F14B="F-14B",
|
F14B="F-14B",
|
||||||
F14A_AI="F-14A",
|
F14A_AI="F-14A",
|
||||||
FA18C="F/A-18C",
|
FA18C="F/A-18C",
|
||||||
@@ -1273,17 +1279,19 @@ AIRBOSS.AircraftCarrier={
|
|||||||
|
|
||||||
--- Carrier types.
|
--- Carrier types.
|
||||||
-- @type AIRBOSS.CarrierType
|
-- @type AIRBOSS.CarrierType
|
||||||
-- @field #string ROOSEVELT USS Theodore Roosevelt (CVN-71)
|
-- @field #string ROOSEVELT USS Theodore Roosevelt (CVN-71) [Super Carrier Module]
|
||||||
-- @field #string LINCOLN USS Abraham Lincoln (CVN-72)
|
-- @field #string LINCOLN USS Abraham Lincoln (CVN-72) [Super Carrier Module]
|
||||||
-- @field #string WASHINGTON USS George Washington (CVN-73)
|
-- @field #string WASHINGTON USS George Washington (CVN-73) [Super Carrier Module]
|
||||||
-- @field #string STENNIS USS John C. Stennis (CVN-74)
|
-- @field #string STENNIS USS John C. Stennis (CVN-74)
|
||||||
-- @field #string VINSON USS Carl Vinson (CVN-70)
|
-- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module]
|
||||||
|
-- @field #string VINSON USS Carl Vinson (CVN-70) [Obsolete]
|
||||||
-- @field #string TARAWA USS Tarawa (LHA-1)
|
-- @field #string TARAWA USS Tarawa (LHA-1)
|
||||||
-- @field #string KUZNETSOV Admiral Kuznetsov (CV 1143.5)
|
-- @field #string KUZNETSOV Admiral Kuznetsov (CV 1143.5)
|
||||||
AIRBOSS.CarrierType={
|
AIRBOSS.CarrierType={
|
||||||
ROOSEVELT="CVN_71",
|
ROOSEVELT="CVN_71",
|
||||||
LINCOLN="CVN_72",
|
LINCOLN="CVN_72",
|
||||||
WASHINGTON="CVN_73",
|
WASHINGTON="CVN_73",
|
||||||
|
TRUMAN="CVN_75",
|
||||||
STENNIS="Stennis",
|
STENNIS="Stennis",
|
||||||
VINSON="VINSON",
|
VINSON="VINSON",
|
||||||
TARAWA="LHA_Tarawa",
|
TARAWA="LHA_Tarawa",
|
||||||
@@ -1697,7 +1705,7 @@ AIRBOSS.MenuF10Root=nil
|
|||||||
|
|
||||||
--- Airboss class version.
|
--- Airboss class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
AIRBOSS.version="1.1.3"
|
AIRBOSS.version="1.1.6"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -1936,11 +1944,13 @@ function AIRBOSS:New(carriername, alias)
|
|||||||
if self.carriertype==AIRBOSS.CarrierType.STENNIS then
|
if self.carriertype==AIRBOSS.CarrierType.STENNIS then
|
||||||
self:_InitStennis()
|
self:_InitStennis()
|
||||||
elseif self.carriertype==AIRBOSS.CarrierType.ROOSEVELT then
|
elseif self.carriertype==AIRBOSS.CarrierType.ROOSEVELT then
|
||||||
self:_InitStennis()
|
self:_InitNimitz()
|
||||||
elseif self.carriertype==AIRBOSS.CarrierType.LINCOLN then
|
elseif self.carriertype==AIRBOSS.CarrierType.LINCOLN then
|
||||||
self:_InitStennis()
|
self:_InitNimitz()
|
||||||
elseif self.carriertype==AIRBOSS.CarrierType.WASHINGTON then
|
elseif self.carriertype==AIRBOSS.CarrierType.WASHINGTON then
|
||||||
self:_InitStennis()
|
self:_InitNimitz()
|
||||||
|
elseif self.carriertype==AIRBOSS.CarrierType.TRUMAN then
|
||||||
|
self:_InitNimitz()
|
||||||
elseif self.carriertype==AIRBOSS.CarrierType.VINSON then
|
elseif self.carriertype==AIRBOSS.CarrierType.VINSON then
|
||||||
-- TODO: Carl Vinson parameters.
|
-- TODO: Carl Vinson parameters.
|
||||||
self:_InitStennis()
|
self:_InitStennis()
|
||||||
@@ -2464,7 +2474,7 @@ function AIRBOSS:AddRecoveryWindow(starttime, stoptime, case, holdingoffset, tur
|
|||||||
local Tstart=UTILS.ClockToSeconds(starttime)
|
local Tstart=UTILS.ClockToSeconds(starttime)
|
||||||
|
|
||||||
-- Set stop time.
|
-- Set stop time.
|
||||||
local Tstop=UTILS.ClockToSeconds(stoptime or Tstart+90*60)
|
local Tstop=stoptime and UTILS.ClockToSeconds(stoptime) or Tstart+90*60
|
||||||
|
|
||||||
-- Consistancy check for timing.
|
-- Consistancy check for timing.
|
||||||
if Tstart>Tstop then
|
if Tstart>Tstop then
|
||||||
@@ -2624,10 +2634,19 @@ end
|
|||||||
|
|
||||||
--- Set time before carrier turns and recovery window opens.
|
--- Set time before carrier turns and recovery window opens.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number interval Time interval in seconds. Default 600 sec.
|
-- @param #number interval Time interval in seconds. Default 300 sec.
|
||||||
-- @return #AIRBOSS self
|
-- @return #AIRBOSS self
|
||||||
function AIRBOSS:SetRecoveryTurnTime(interval)
|
function AIRBOSS:SetRecoveryTurnTime(interval)
|
||||||
self.dTturn=interval or 600
|
self.dTturn=interval or 300
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set multiplayer environment wire correction.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
-- @param #number Dcorr Correction distance in meters. Default 8.7 m.
|
||||||
|
-- @return #AIRBOSS self
|
||||||
|
function AIRBOSS:SetMPWireCorrection(Dcorr)
|
||||||
|
self.mpWireCorrection=Dcorr or 8.7
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4094,7 +4113,7 @@ function AIRBOSS:onafterRecoveryUnpause(From, Event, To)
|
|||||||
self:T(self.lid..string.format("Unpausing aircraft recovery."))
|
self:T(self.lid..string.format("Unpausing aircraft recovery."))
|
||||||
|
|
||||||
-- Resume recovery.
|
-- Resume recovery.
|
||||||
self:_MarshalCallRecoveryResume()
|
self:_MarshalCallResumeRecovery()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4150,7 +4169,7 @@ function AIRBOSS:_InitStennis()
|
|||||||
|
|
||||||
-- Carrier Parameters.
|
-- Carrier Parameters.
|
||||||
self.carrierparam.sterndist =-153
|
self.carrierparam.sterndist =-153
|
||||||
self.carrierparam.deckheight = 19
|
self.carrierparam.deckheight = 19.06
|
||||||
|
|
||||||
-- Total size of the carrier (approx as rectangle).
|
-- Total size of the carrier (approx as rectangle).
|
||||||
self.carrierparam.totlength=310 -- Wiki says 332.8 meters overall length.
|
self.carrierparam.totlength=310 -- Wiki says 332.8 meters overall length.
|
||||||
@@ -4158,7 +4177,7 @@ function AIRBOSS:_InitStennis()
|
|||||||
self.carrierparam.totwidthstarboard=30
|
self.carrierparam.totwidthstarboard=30
|
||||||
|
|
||||||
-- Landing runway.
|
-- Landing runway.
|
||||||
self.carrierparam.rwyangle = -9
|
self.carrierparam.rwyangle = -9.1359
|
||||||
self.carrierparam.rwylength = 225
|
self.carrierparam.rwylength = 225
|
||||||
self.carrierparam.rwywidth = 20
|
self.carrierparam.rwywidth = 20
|
||||||
|
|
||||||
@@ -4292,7 +4311,36 @@ function AIRBOSS:_InitStennis()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Init parameters for USS Stennis carrier.
|
--- Init parameters for Nimitz class super carriers.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitNimitz()
|
||||||
|
|
||||||
|
-- Init Stennis as default.
|
||||||
|
self:_InitStennis()
|
||||||
|
|
||||||
|
-- Carrier Parameters.
|
||||||
|
self.carrierparam.sterndist =-164
|
||||||
|
self.carrierparam.deckheight = 20.1494 --DCS World OpenBeta\CoreMods\tech\USS_Nimitz\Database\USS_CVN_7X.lua
|
||||||
|
|
||||||
|
-- Total size of the carrier (approx as rectangle).
|
||||||
|
self.carrierparam.totlength=332.8 -- Wiki says 332.8 meters overall length.
|
||||||
|
self.carrierparam.totwidthport=45 -- Wiki says 76.8 meters overall beam.
|
||||||
|
self.carrierparam.totwidthstarboard=35
|
||||||
|
|
||||||
|
-- Landing runway.
|
||||||
|
self.carrierparam.rwyangle = -9.1359 --DCS World OpenBeta\CoreMods\tech\USS_Nimitz\scripts\USS_Nimitz_RunwaysAndRoutes.lua
|
||||||
|
self.carrierparam.rwylength = 250
|
||||||
|
self.carrierparam.rwywidth = 25
|
||||||
|
|
||||||
|
-- Wires.
|
||||||
|
self.carrierparam.wire1 = 55 -- Distance from stern to first wire.
|
||||||
|
self.carrierparam.wire2 = 67
|
||||||
|
self.carrierparam.wire3 = 79
|
||||||
|
self.carrierparam.wire4 = 92
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Init parameters for LHA-1 Tarawa carrier.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_InitTarawa()
|
function AIRBOSS:_InitTarawa()
|
||||||
|
|
||||||
@@ -7866,7 +7914,7 @@ end
|
|||||||
function AIRBOSS:_RemoveUnitFromFlight(unit)
|
function AIRBOSS:_RemoveUnitFromFlight(unit)
|
||||||
|
|
||||||
-- Check if unit exists.
|
-- Check if unit exists.
|
||||||
if unit then
|
if unit and unit:IsInstanceOf("UNIT") then
|
||||||
|
|
||||||
-- Get group.
|
-- Get group.
|
||||||
local group=unit:GetGroup()
|
local group=unit:GetGroup()
|
||||||
@@ -10297,9 +10345,12 @@ function AIRBOSS:_GetSternCoord()
|
|||||||
if self.carriertype==AIRBOSS.CarrierType.TARAWA then
|
if self.carriertype==AIRBOSS.CarrierType.TARAWA then
|
||||||
-- Tarawa: Translate 8 meters port.
|
-- Tarawa: Translate 8 meters port.
|
||||||
stern=stern:Translate(self.carrierparam.sterndist, hdg):Translate(8, FB-90)
|
stern=stern:Translate(self.carrierparam.sterndist, hdg):Translate(8, FB-90)
|
||||||
else
|
elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then
|
||||||
-- Stennis: translate 7 meters starboard wrt Final bearing.
|
-- Stennis: translate 7 meters starboard wrt Final bearing.
|
||||||
stern=stern:Translate(self.carrierparam.sterndist, hdg):Translate(7, FB+90)
|
stern=stern:Translate(self.carrierparam.sterndist, hdg):Translate(7, FB+90)
|
||||||
|
else
|
||||||
|
-- Nimitz SC: translate 8 meters starboard wrt Final bearing.
|
||||||
|
stern=stern:Translate(self.carrierparam.sterndist, hdg):Translate(9.5, FB+90)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set altitude.
|
-- Set altitude.
|
||||||
@@ -10330,6 +10381,11 @@ function AIRBOSS:_GetWire(Lcoord, dc)
|
|||||||
-- Corrected landing distance wrt to stern. Landing distance needs to be reduced due to delayed landing event for human players.
|
-- Corrected landing distance wrt to stern. Landing distance needs to be reduced due to delayed landing event for human players.
|
||||||
local d=Ldist-dc
|
local d=Ldist-dc
|
||||||
|
|
||||||
|
-- Multiplayer wire correction.
|
||||||
|
if self.mpWireCorrection then
|
||||||
|
d=d-self.mpWireCorrection
|
||||||
|
end
|
||||||
|
|
||||||
-- Shift wires from stern to their correct position.
|
-- Shift wires from stern to their correct position.
|
||||||
local w1=self.carrierparam.wire1
|
local w1=self.carrierparam.wire1
|
||||||
local w2=self.carrierparam.wire2
|
local w2=self.carrierparam.wire2
|
||||||
@@ -14016,10 +14072,10 @@ function AIRBOSS:_GetOnboardNumbers(group, playeronly)
|
|||||||
-- Onboard number and unit name.
|
-- Onboard number and unit name.
|
||||||
local n=tostring(unit.onboard_num)
|
local n=tostring(unit.onboard_num)
|
||||||
local name=unit.name
|
local name=unit.name
|
||||||
local skill=unit.skill
|
local skill=unit.skill or "Unknown"
|
||||||
|
|
||||||
-- Debug text.
|
-- Debug text.
|
||||||
text=text..string.format("\n- unit %s: onboard #=%s skill=%s", name, n, skill)
|
text=text..string.format("\n- unit %s: onboard #=%s skill=%s", name, n, tostring(skill))
|
||||||
|
|
||||||
if playeronly and skill=="Client" or skill=="Player" then
|
if playeronly and skill=="Client" or skill=="Player" then
|
||||||
-- There can be only one player in the group, so we skip everything else.
|
-- There can be only one player in the group, so we skip everything else.
|
||||||
@@ -17609,7 +17665,8 @@ function AIRBOSS:_SaveTrapSheet(playerData, grade)
|
|||||||
if self.trapprefix then
|
if self.trapprefix then
|
||||||
filename=string.format("%s_%s-%04d.csv", self.trapprefix, playerData.actype, i)
|
filename=string.format("%s_%s-%04d.csv", self.trapprefix, playerData.actype, i)
|
||||||
else
|
else
|
||||||
filename=string.format("AIRBOSS-%s_Trapsheet-%s_%s-%04d.csv", self.alias, playerData.name, playerData.actype, i)
|
local name=UTILS.ReplaceIllegalCharacters(playerData.name, "_")
|
||||||
|
filename=string.format("AIRBOSS-%s_Trapsheet-%s_%s-%04d.csv", self.alias, name, playerData.actype, i)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set path.
|
-- Set path.
|
||||||
@@ -17682,7 +17739,7 @@ function AIRBOSS:onbeforeSave(From, Event, To, path, filename)
|
|||||||
|
|
||||||
-- Check default path.
|
-- Check default path.
|
||||||
if path==nil and not lfs then
|
if path==nil and not lfs then
|
||||||
self:E(self.lid.."WARNING: lfs not desanitized. Results will be saved in DCS installation root directory rather than your \"Saved Games\DCS\" folder.")
|
self:E(self.lid.."WARNING: lfs not desanitized. Results will be saved in DCS installation root directory rather than your \"Saved Games\\DCS\" folder.")
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -17789,7 +17846,7 @@ function AIRBOSS:onbeforeLoad(From, Event, To, path, filename)
|
|||||||
|
|
||||||
-- Check default path.
|
-- Check default path.
|
||||||
if path==nil and not lfs then
|
if path==nil and not lfs then
|
||||||
self:E(self.lid.."WARNING: lfs not desanitized. Results will be saved in DCS installation root directory rather than your \"Saved Games\DCS\" folder.")
|
self:E(self.lid.."WARNING: lfs not desanitized. Results will be saved in DCS installation root directory rather than your \"Saved Games\\DCS\" folder.")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set path or default.
|
-- Set path or default.
|
||||||
|
|||||||
@@ -1345,7 +1345,6 @@ function RECOVERYTANKER:OnEventEngineShutdown(EventData)
|
|||||||
group:InitModex(self.modex)
|
group:InitModex(self.modex)
|
||||||
|
|
||||||
-- Respawn tanker. Delaying respawn due to DCS bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
-- Respawn tanker. Delaying respawn due to DCS bug https://github.com/FlightControl-Master/MOOSE/issues/1076
|
||||||
--SCHEDULER:New(nil , group.RespawnAtCurrentAirbase, {group}, 1)
|
|
||||||
self:ScheduleOnce(1, GROUP.RespawnAtCurrentAirbase, group)
|
self:ScheduleOnce(1, GROUP.RespawnAtCurrentAirbase, group)
|
||||||
|
|
||||||
-- Create tanker beacon and activate TACAN.
|
-- Create tanker beacon and activate TACAN.
|
||||||
@@ -1364,7 +1363,6 @@ function RECOVERYTANKER:OnEventEngineShutdown(EventData)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Initial route.
|
-- Initial route.
|
||||||
--SCHEDULER:New(nil, self._InitRoute, {self, -self.distStern+UTILS.NMToMeters(3)}, 2)
|
|
||||||
self:ScheduleOnce(2, RECOVERYTANKER._InitRoute, self, -self.distStern+UTILS.NMToMeters(3))
|
self:ScheduleOnce(2, RECOVERYTANKER._InitRoute, self, -self.distStern+UTILS.NMToMeters(3))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -881,6 +881,9 @@ do -- Group Assignment
|
|||||||
local Mission = self:GetMission()
|
local Mission = self:GetMission()
|
||||||
local CommandCenter = Mission:GetCommandCenter()
|
local CommandCenter = Mission:GetCommandCenter()
|
||||||
CommandCenter:SetMenu()
|
CommandCenter:SetMenu()
|
||||||
|
|
||||||
|
self:MenuFlashTaskStatus( TaskGroup, false ) -- stop message flashing, if any #1383 & #1312
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1252,7 +1255,7 @@ function TASK:MenuFlashTaskStatus( TaskGroup, Flash )
|
|||||||
self.FlashTaskStatus = Flash
|
self.FlashTaskStatus = Flash
|
||||||
|
|
||||||
if self.FlashTaskStatus then
|
if self.FlashTaskStatus then
|
||||||
self.FlashTaskScheduler, self.FlashTaskScheduleID = SCHEDULER:New( self, self.MenuTaskStatus, { TaskGroup }, 0, 60 )
|
self.FlashTaskScheduler, self.FlashTaskScheduleID = SCHEDULER:New( self, self.MenuTaskStatus, { TaskGroup }, 0, 60) --Issue #1383 never ending flash messages
|
||||||
else
|
else
|
||||||
if self.FlashTaskScheduler then
|
if self.FlashTaskScheduler then
|
||||||
self.FlashTaskScheduler:Stop( self.FlashTaskScheduleID )
|
self.FlashTaskScheduler:Stop( self.FlashTaskScheduleID )
|
||||||
|
|||||||
@@ -344,8 +344,10 @@ function TASKINFO:Report( Report, Detail, ReportGroup, Task )
|
|||||||
Text = DataText
|
Text = DataText
|
||||||
else
|
else
|
||||||
local DataText = Data.Data -- #string
|
local DataText = Data.Data -- #string
|
||||||
|
if type(DataText) == "string" then --Issue #1388 - don't just assume this is a string
|
||||||
Text = DataText
|
Text = DataText
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if Line < math.floor( Data.Order / 10 ) then
|
if Line < math.floor( Data.Order / 10 ) then
|
||||||
if Line == 0 then
|
if Line == 0 then
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ do -- TASK_A2A_DISPATCHER
|
|||||||
|
|
||||||
self.Detection = Detection
|
self.Detection = Detection
|
||||||
self.Mission = Mission
|
self.Mission = Mission
|
||||||
|
self.FlashNewTask = false
|
||||||
|
|
||||||
-- TODO: Check detection through radar.
|
-- TODO: Check detection through radar.
|
||||||
self.Detection:FilterCategories( Unit.Category.AIRPLANE, Unit.Category.HELICOPTER )
|
self.Detection:FilterCategories( Unit.Category.AIRPLANE, Unit.Category.HELICOPTER )
|
||||||
@@ -253,7 +253,12 @@ do -- TASK_A2A_DISPATCHER
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set flashing player messages on or off
|
||||||
|
-- @param #TASK_A2A_DISPATCHER self
|
||||||
|
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||||
|
function TASK_A2A_DISPATCHER:SetSendMessages( onoff )
|
||||||
|
self.FlashNewTask = onoff
|
||||||
|
end
|
||||||
|
|
||||||
--- Creates an INTERCEPT task when there are targets for it.
|
--- Creates an INTERCEPT task when there are targets for it.
|
||||||
-- @param #TASK_A2A_DISPATCHER self
|
-- @param #TASK_A2A_DISPATCHER self
|
||||||
@@ -610,7 +615,7 @@ do -- TASK_A2A_DISPATCHER
|
|||||||
local TaskText = TaskReport:Text(", ")
|
local TaskText = TaskReport:Text(", ")
|
||||||
|
|
||||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||||
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then
|
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and (self.FlashNewTask) then
|
||||||
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -451,6 +451,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
|
|
||||||
self.Detection = Detection
|
self.Detection = Detection
|
||||||
self.Mission = Mission
|
self.Mission = Mission
|
||||||
|
self.FlashNewTask = true --set to false to suppress flash messages
|
||||||
|
|
||||||
self.Detection:FilterCategories( { Unit.Category.GROUND_UNIT } )
|
self.Detection:FilterCategories( { Unit.Category.GROUND_UNIT } )
|
||||||
|
|
||||||
@@ -471,6 +472,12 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set flashing player messages on or off
|
||||||
|
-- @param #TASK_A2G_DISPATCHER self
|
||||||
|
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||||
|
function TASK_A2G_DISPATCHER:SetSendMessages( onoff )
|
||||||
|
self.FlashNewTask = onoff
|
||||||
|
end
|
||||||
|
|
||||||
--- Creates a SEAD task when there are targets for it.
|
--- Creates a SEAD task when there are targets for it.
|
||||||
-- @param #TASK_A2G_DISPATCHER self
|
-- @param #TASK_A2G_DISPATCHER self
|
||||||
@@ -616,8 +623,10 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
if not DetectedItem then
|
if not DetectedItem then
|
||||||
local TaskText = Task:GetName()
|
local TaskText = Task:GetName()
|
||||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||||
|
if self.FlashNewTask then
|
||||||
Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2G task %s for %s removed.", TaskText, Mission:GetShortText() ), TaskGroup )
|
Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2G task %s for %s removed.", TaskText, Mission:GetShortText() ), TaskGroup )
|
||||||
end
|
end
|
||||||
|
end
|
||||||
Task = self:RemoveTask( TaskIndex )
|
Task = self:RemoveTask( TaskIndex )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -686,7 +695,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
-- Now we send to each group the changes, if any.
|
-- Now we send to each group the changes, if any.
|
||||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||||
local TargetsText = TargetsReport:Text(", ")
|
local TargetsText = TargetsReport:Text(", ")
|
||||||
if ( Mission:IsGroupAssigned(TaskGroup) ) and TargetsText ~= "" then
|
if ( Mission:IsGroupAssigned(TaskGroup) ) and TargetsText ~= "" and self.FlashNewTask then
|
||||||
Mission:GetCommandCenter():MessageToGroup( string.format( "Task %s has change of targets:\n %s", Task:GetName(), TargetsText ), TaskGroup )
|
Mission:GetCommandCenter():MessageToGroup( string.format( "Task %s has change of targets:\n %s", Task:GetName(), TargetsText ), TaskGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -744,6 +753,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||||
if TargetSetUnit then
|
if TargetSetUnit then
|
||||||
Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit )
|
Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit )
|
||||||
|
DetectedItem.DesignateMenuName = string.format( "SEAD.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||||
Task:SetDetection( Detection, DetectedItem )
|
Task:SetDetection( Detection, DetectedItem )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -752,6 +762,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
||||||
if TargetSetUnit then
|
if TargetSetUnit then
|
||||||
Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit )
|
Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit )
|
||||||
|
DetectedItem.DesignateMenuName = string.format( "CAS.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||||
Task:SetDetection( Detection, DetectedItem )
|
Task:SetDetection( Detection, DetectedItem )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -760,6 +771,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed...
|
local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed...
|
||||||
if TargetSetUnit then
|
if TargetSetUnit then
|
||||||
Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit )
|
Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit )
|
||||||
|
DetectedItem.DesignateMenuName = string.format( "BAI.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||||
Task:SetDetection( Detection, DetectedItem )
|
Task:SetDetection( Detection, DetectedItem )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -805,7 +817,7 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
|
|
||||||
local TaskText = TaskReport:Text(", ")
|
local TaskText = TaskReport:Text(", ")
|
||||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||||
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then
|
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and self.FlashNewTask then
|
||||||
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
|||||||
-- ## 1.1. Create a command center.
|
-- ## 1.1. Create a command center.
|
||||||
--
|
--
|
||||||
-- First you need to create a command center using the @{Tasking.CommandCenter#COMMANDCENTER.New}() constructor.
|
-- First you need to create a command center using the @{Tasking.CommandCenter#COMMANDCENTER.New}() constructor.
|
||||||
-- The command assumes that you´ve setup a group in the mission editor with the name HQ.
|
-- The command assumes that you´ve setup a group in the mission editor with the name HQ.
|
||||||
-- This group will act as the command center object.
|
-- This group will act as the command center object.
|
||||||
-- It is a good practice to mark this group as invisible and invulnerable.
|
-- It is a good practice to mark this group as invisible and invulnerable.
|
||||||
--
|
--
|
||||||
@@ -184,6 +184,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
|||||||
local self = BASE:Inherit( self, TASK_MANAGER:New( SetGroup ) ) -- #TASK_CAPTURE_DISPATCHER
|
local self = BASE:Inherit( self, TASK_MANAGER:New( SetGroup ) ) -- #TASK_CAPTURE_DISPATCHER
|
||||||
|
|
||||||
self.Mission = Mission
|
self.Mission = Mission
|
||||||
|
self.FlashNewTask = false
|
||||||
|
|
||||||
self:AddTransition( "Started", "Assign", "Started" )
|
self:AddTransition( "Started", "Assign", "Started" )
|
||||||
self:AddTransition( "Started", "ZoneCaptured", "Started" )
|
self:AddTransition( "Started", "ZoneCaptured", "Started" )
|
||||||
@@ -383,7 +384,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
|||||||
local TaskText = TaskReport:Text(", ")
|
local TaskText = TaskReport:Text(", ")
|
||||||
|
|
||||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||||
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then
|
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and ( not self.FlashNewTask ) then
|
||||||
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,6 +56,17 @@ ENUMS.ROT = {
|
|||||||
AllowAbortMission=4,
|
AllowAbortMission=4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Alarm state.
|
||||||
|
-- @type ENUMS.AlarmState
|
||||||
|
-- @field #number Auto AI will automatically switch alarm states based on the presence of threats. The AI kind of cheats in this regard.
|
||||||
|
-- @field #number Green Group is not combat ready. Sensors are stowed if possible.
|
||||||
|
-- @field #number Red Group is combat ready and actively searching for targets. Some groups like infantry will not move in this state.
|
||||||
|
ENUMS.AlarmState = {
|
||||||
|
Auto=0,
|
||||||
|
Green=1,
|
||||||
|
Red=2,
|
||||||
|
}
|
||||||
|
|
||||||
--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerotor on hoggit wiki.
|
--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerotor on hoggit wiki.
|
||||||
-- @type ENUMS.WeaponFlag
|
-- @type ENUMS.WeaponFlag
|
||||||
ENUMS.WeaponFlag={
|
ENUMS.WeaponFlag={
|
||||||
@@ -222,6 +233,15 @@ ENUMS.Formation.RotaryWing.EchelonLeft={}
|
|||||||
ENUMS.Formation.RotaryWing.EchelonLeft.D70 =590081
|
ENUMS.Formation.RotaryWing.EchelonLeft.D70 =590081
|
||||||
ENUMS.Formation.RotaryWing.EchelonLeft.D300=590082
|
ENUMS.Formation.RotaryWing.EchelonLeft.D300=590082
|
||||||
ENUMS.Formation.RotaryWing.EchelonLeft.D600=590083
|
ENUMS.Formation.RotaryWing.EchelonLeft.D600=590083
|
||||||
|
ENUMS.Formation.Vehicle={}
|
||||||
|
ENUMS.Formation.Vehicle.Vee="Vee"
|
||||||
|
ENUMS.Formation.Vehicle.EchelonRight="EchelonR"
|
||||||
|
ENUMS.Formation.Vehicle.OffRoad="Off Road"
|
||||||
|
ENUMS.Formation.Vehicle.Rank="Rank"
|
||||||
|
ENUMS.Formation.Vehicle.EchelonLeft="EchelonL"
|
||||||
|
ENUMS.Formation.Vehicle.OnRoad="On Road"
|
||||||
|
ENUMS.Formation.Vehicle.Cone="Cone"
|
||||||
|
ENUMS.Formation.Vehicle.Diamond="Diamond"
|
||||||
|
|
||||||
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
|
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
|
||||||
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
||||||
@@ -291,3 +311,52 @@ ENUMS.Morse.N8="- - - * *"
|
|||||||
ENUMS.Morse.N9="- - - - *"
|
ENUMS.Morse.N9="- - - - *"
|
||||||
ENUMS.Morse.N0="- - - - -"
|
ENUMS.Morse.N0="- - - - -"
|
||||||
ENUMS.Morse[" "]=" "
|
ENUMS.Morse[" "]=" "
|
||||||
|
|
||||||
|
--- ISO (639-1) 2-letter Language Codes. See the [Wikipedia](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
|
||||||
|
--
|
||||||
|
-- @type ENUMS.ISOLang
|
||||||
|
ENUMS.ISOLang =
|
||||||
|
{
|
||||||
|
Arabic = 'AR',
|
||||||
|
Chinese = 'ZH',
|
||||||
|
English = 'EN',
|
||||||
|
French = 'FR',
|
||||||
|
German = 'DE',
|
||||||
|
Russian = 'RU',
|
||||||
|
Spanish = 'ES',
|
||||||
|
Japanese = 'JA',
|
||||||
|
Italian = 'IT',
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Phonetic Alphabet (NATO). See the [Wikipedia](https://en.wikipedia.org/wiki/NATO_phonetic_alphabet).
|
||||||
|
--
|
||||||
|
-- @type ENUMS.Phonetic
|
||||||
|
ENUMS.Phonetic =
|
||||||
|
{
|
||||||
|
A = 'Alpha',
|
||||||
|
B = 'Bravo',
|
||||||
|
C = 'Charlie',
|
||||||
|
D = 'Delta',
|
||||||
|
E = 'Echo',
|
||||||
|
F = 'Foxtrot',
|
||||||
|
G = 'Golf',
|
||||||
|
H = 'Hotel',
|
||||||
|
I = 'India',
|
||||||
|
J = 'Juliett',
|
||||||
|
K = 'Kilo',
|
||||||
|
L = 'Lima',
|
||||||
|
M = 'Mike',
|
||||||
|
N = 'November',
|
||||||
|
O = 'Oscar',
|
||||||
|
P = 'Papa',
|
||||||
|
Q = 'Quebec',
|
||||||
|
R = 'Romeo',
|
||||||
|
S = 'Sierra',
|
||||||
|
T = 'Tango',
|
||||||
|
U = 'Uniform',
|
||||||
|
V = 'Victor',
|
||||||
|
W = 'Whiskey',
|
||||||
|
X = 'Xray',
|
||||||
|
Y = 'Yankee',
|
||||||
|
Z = 'Zulu',
|
||||||
|
}
|
||||||
539
Moose Development/Moose/Utilities/Profiler.lua
Normal file
539
Moose Development/Moose/Utilities/Profiler.lua
Normal file
@@ -0,0 +1,539 @@
|
|||||||
|
--- **Utils** - Lua Profiler.
|
||||||
|
--
|
||||||
|
-- Find out how many times functions are called and how much real time it costs.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **TAW CougarNL**, *funkyfranky*
|
||||||
|
--
|
||||||
|
-- @module Utilities.PROFILER
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
|
--- PROFILER class.
|
||||||
|
-- @type PROFILER
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #table Counters Function counters.
|
||||||
|
-- @field #table dInfo Info.
|
||||||
|
-- @field #table fTime Function time.
|
||||||
|
-- @field #table fTimeTotal Total function time.
|
||||||
|
-- @field #table eventhandler Event handler to get mission end event.
|
||||||
|
-- @field #number TstartGame Game start time timer.getTime().
|
||||||
|
-- @field #number TstartOS OS real start time os.clock.
|
||||||
|
-- @field #boolean logUnknown Log unknown functions. Default is off.
|
||||||
|
-- @field #number ThreshCPS Low calls per second threshold. Only write output if function has more calls per second than this value.
|
||||||
|
-- @field #number ThreshTtot Total time threshold. Only write output if total function CPU time is more than this value.
|
||||||
|
-- @field #string fileNamePrefix Output file name prefix, e.g. "MooseProfiler".
|
||||||
|
-- @field #string fileNameSuffix Output file name prefix, e.g. "txt"
|
||||||
|
|
||||||
|
--- *The emperor counsels simplicity. First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature? *
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- # The PROFILER Concept
|
||||||
|
--
|
||||||
|
-- Profile your lua code. This tells you, which functions are called very often and which consume most real time.
|
||||||
|
-- With this information you can optimize the perfomance of your code.
|
||||||
|
--
|
||||||
|
-- # Prerequisites
|
||||||
|
--
|
||||||
|
-- The modules **os** and **lfs** need to be desanizied.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Start
|
||||||
|
--
|
||||||
|
-- The profiler can simply be started with the @{#PROFILER.Start}(*Delay, Duration*) function
|
||||||
|
--
|
||||||
|
-- PROFILER.Start()
|
||||||
|
--
|
||||||
|
-- The optional parameter *Delay* can be used to delay the start by a certain amount of seconds and the optional parameter *Duration* can be used to
|
||||||
|
-- stop the profiler after a certain amount of seconds.
|
||||||
|
--
|
||||||
|
-- # Stop
|
||||||
|
--
|
||||||
|
-- The profiler automatically stops when the mission ends. But it can be stopped any time with the @{#PROFILER.Stop}(*Delay*) function
|
||||||
|
--
|
||||||
|
-- PROFILER.Stop()
|
||||||
|
--
|
||||||
|
-- The optional parameter *Delay* can be used to specify a delay after which the profiler is stopped.
|
||||||
|
--
|
||||||
|
-- When the profiler is stopped, the output is written to a file.
|
||||||
|
--
|
||||||
|
-- # Output
|
||||||
|
--
|
||||||
|
-- The profiler output is written to a file in your DCS home folder
|
||||||
|
--
|
||||||
|
-- X:\User\<Your User Name>\Saved Games\DCS OpenBeta\Logs
|
||||||
|
--
|
||||||
|
-- The default file name is "MooseProfiler.txt". If that file exists, the file name is "MooseProfiler-001.txt" etc.
|
||||||
|
--
|
||||||
|
-- ## Data
|
||||||
|
--
|
||||||
|
-- The data in the output file provides information on the functions that were called in the mission.
|
||||||
|
--
|
||||||
|
-- It will tell you how many times a function was called in total, how many times per second, how much time in total and the percentage of time.
|
||||||
|
--
|
||||||
|
-- If you only want output for functions that are called more than *X* times per second, you can set
|
||||||
|
--
|
||||||
|
-- PROFILER.ThreshCPS=1.5
|
||||||
|
--
|
||||||
|
-- With this setting, only functions which are called more than 1.5 times per second are displayed. The default setting is PROFILER.ThreshCPS=0.0 (no threshold).
|
||||||
|
--
|
||||||
|
-- Furthermore, you can limit the output for functions that consumed a certain amount of CPU time in total by
|
||||||
|
--
|
||||||
|
-- PROFILER.ThreshTtot=0.005
|
||||||
|
--
|
||||||
|
-- With this setting, which is also the default, only functions which in total used more than 5 milliseconds CPU time.
|
||||||
|
--
|
||||||
|
-- @field #PROFILER
|
||||||
|
PROFILER = {
|
||||||
|
ClassName = "PROFILER",
|
||||||
|
Counters = {},
|
||||||
|
dInfo = {},
|
||||||
|
fTime = {},
|
||||||
|
fTimeTotal = {},
|
||||||
|
eventHandler = {},
|
||||||
|
logUnknown = false,
|
||||||
|
ThreshCPS = 0.0,
|
||||||
|
ThreshTtot = 0.005,
|
||||||
|
fileNamePrefix = "MooseProfiler",
|
||||||
|
fileNameSuffix = "txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Waypoint data.
|
||||||
|
-- @type PROFILER.Data
|
||||||
|
-- @field #string func The function name.
|
||||||
|
-- @field #string src The source file.
|
||||||
|
-- @field #number line The line number
|
||||||
|
-- @field #number count Number of function calls.
|
||||||
|
-- @field #number tm Total time in seconds.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Start/Stop Profiler
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Start profiler.
|
||||||
|
-- @param #number Delay Delay in seconds before profiler is stated. Default is immediately.
|
||||||
|
-- @param #number Duration Duration in (game) seconds before the profiler is stopped. Default is when mission ends.
|
||||||
|
function PROFILER.Start(Delay, Duration)
|
||||||
|
|
||||||
|
-- Check if os, io and lfs are available.
|
||||||
|
local go=true
|
||||||
|
if not os then
|
||||||
|
env.error("ERROR: Profiler needs os to be desanitized!")
|
||||||
|
go=false
|
||||||
|
end
|
||||||
|
if not io then
|
||||||
|
env.error("ERROR: Profiler needs io to be desanitized!")
|
||||||
|
go=false
|
||||||
|
end
|
||||||
|
if not lfs then
|
||||||
|
env.error("ERROR: Profiler needs lfs to be desanitized!")
|
||||||
|
go=false
|
||||||
|
end
|
||||||
|
if not go then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
BASE:ScheduleOnce(Delay, PROFILER.Start, 0, Duration)
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Set start time.
|
||||||
|
PROFILER.TstartGame=timer.getTime()
|
||||||
|
PROFILER.TstartOS=os.clock()
|
||||||
|
|
||||||
|
-- Add event handler.
|
||||||
|
world.addEventHandler(PROFILER.eventHandler)
|
||||||
|
|
||||||
|
-- Info in log.
|
||||||
|
env.info('############################ Profiler Started ############################')
|
||||||
|
if Duration then
|
||||||
|
env.info(string.format("- Will be running for %d seconds", Duration))
|
||||||
|
else
|
||||||
|
env.info(string.format("- Will be stopped when mission ends"))
|
||||||
|
end
|
||||||
|
env.info(string.format("- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS))
|
||||||
|
env.info(string.format("- Total function time threshold %.3f sec", PROFILER.ThreshTtot))
|
||||||
|
env.info(string.format("- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename(PROFILER.fileNameSuffix)))
|
||||||
|
env.info(string.format("- Output file \"%s\" in CSV format", PROFILER.getfilename("csv")))
|
||||||
|
env.info('###############################################################################')
|
||||||
|
|
||||||
|
|
||||||
|
-- Message on screen
|
||||||
|
local duration=Duration or 600
|
||||||
|
trigger.action.outText("### Profiler running ###", duration)
|
||||||
|
|
||||||
|
-- Set hook.
|
||||||
|
debug.sethook(PROFILER.hook, "cr")
|
||||||
|
|
||||||
|
-- Auto stop profiler.
|
||||||
|
if Duration then
|
||||||
|
PROFILER.Stop(Duration)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Stop profiler.
|
||||||
|
-- @param #number Delay Delay before stop in seconds.
|
||||||
|
function PROFILER.Stop(Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
|
||||||
|
BASE:ScheduleOnce(Delay, PROFILER.Stop)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Remove hook.
|
||||||
|
debug.sethook()
|
||||||
|
|
||||||
|
|
||||||
|
-- Run time game.
|
||||||
|
local runTimeGame=timer.getTime()-PROFILER.TstartGame
|
||||||
|
|
||||||
|
-- Run time real OS.
|
||||||
|
local runTimeOS=os.clock()-PROFILER.TstartOS
|
||||||
|
|
||||||
|
-- Show info.
|
||||||
|
PROFILER.showInfo(runTimeGame, runTimeOS)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Event handler.
|
||||||
|
function PROFILER.eventHandler:onEvent(event)
|
||||||
|
if event.id==world.event.S_EVENT_MISSION_END then
|
||||||
|
PROFILER.Stop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Hook
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Debug hook.
|
||||||
|
-- @param #table event Event.
|
||||||
|
function PROFILER.hook(event)
|
||||||
|
|
||||||
|
local f=debug.getinfo(2, "f").func
|
||||||
|
|
||||||
|
if event=='call' then
|
||||||
|
|
||||||
|
if PROFILER.Counters[f]==nil then
|
||||||
|
|
||||||
|
PROFILER.Counters[f]=1
|
||||||
|
PROFILER.dInfo[f]=debug.getinfo(2,"Sn")
|
||||||
|
|
||||||
|
if PROFILER.fTimeTotal[f]==nil then
|
||||||
|
PROFILER.fTimeTotal[f]=0
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
PROFILER.Counters[f]=PROFILER.Counters[f]+1
|
||||||
|
end
|
||||||
|
|
||||||
|
if PROFILER.fTime[f]==nil then
|
||||||
|
PROFILER.fTime[f]=os.clock()
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (event=='return') then
|
||||||
|
|
||||||
|
if PROFILER.fTime[f]~=nil then
|
||||||
|
PROFILER.fTimeTotal[f]=PROFILER.fTimeTotal[f]+(os.clock()-PROFILER.fTime[f])
|
||||||
|
PROFILER.fTime[f]=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Data
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Get data.
|
||||||
|
-- @param #function func Function.
|
||||||
|
-- @return #string Function name.
|
||||||
|
-- @return #string Source file name.
|
||||||
|
-- @return #string Line number.
|
||||||
|
-- @return #number Function time in seconds.
|
||||||
|
function PROFILER.getData(func)
|
||||||
|
|
||||||
|
local n=PROFILER.dInfo[func]
|
||||||
|
|
||||||
|
if n.what=="C" then
|
||||||
|
return n.name, "?", "?", PROFILER.fTimeTotal[func]
|
||||||
|
end
|
||||||
|
|
||||||
|
return n.name, n.short_src, n.linedefined, PROFILER.fTimeTotal[func]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Write text to log file.
|
||||||
|
-- @param #function f The file.
|
||||||
|
-- @param #string txt The text.
|
||||||
|
function PROFILER._flog(f, txt)
|
||||||
|
f:write(txt.."\r\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Show table.
|
||||||
|
-- @param #table data Data table.
|
||||||
|
-- @param #function f The file.
|
||||||
|
-- @param #number runTimeGame Game run time in seconds.
|
||||||
|
function PROFILER.showTable(data, f, runTimeGame)
|
||||||
|
|
||||||
|
-- Loop over data.
|
||||||
|
for i=1, #data do
|
||||||
|
local t=data[i] --#PROFILER.Data
|
||||||
|
|
||||||
|
-- Calls per second.
|
||||||
|
local cps=t.count/runTimeGame
|
||||||
|
|
||||||
|
local threshCPS=cps>=PROFILER.ThreshCPS
|
||||||
|
local threshTot=t.tm>=PROFILER.ThreshTtot
|
||||||
|
|
||||||
|
if threshCPS and threshTot then
|
||||||
|
|
||||||
|
-- Output
|
||||||
|
local text=string.format("%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||||
|
PROFILER._flog(f, text)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Print csv file.
|
||||||
|
-- @param #table data Data table.
|
||||||
|
-- @param #number runTimeGame Game run time in seconds.
|
||||||
|
function PROFILER.printCSV(data, runTimeGame)
|
||||||
|
|
||||||
|
-- Output file.
|
||||||
|
local file=PROFILER.getfilename("csv")
|
||||||
|
local g=io.open(file, 'w')
|
||||||
|
|
||||||
|
-- Header.
|
||||||
|
local text="Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
|
||||||
|
g:write(text.."\r\n")
|
||||||
|
|
||||||
|
-- Loop over data.
|
||||||
|
for i=1, #data do
|
||||||
|
local t=data[i] --#PROFILER.Data
|
||||||
|
|
||||||
|
-- Calls per second.
|
||||||
|
local cps=t.count/runTimeGame
|
||||||
|
|
||||||
|
-- Output
|
||||||
|
local txt=string.format("%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||||
|
g:write(txt.."\r\n")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Close file.
|
||||||
|
g:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Write info to output file.
|
||||||
|
-- @param #string ext Extension.
|
||||||
|
-- @return #string File name.
|
||||||
|
function PROFILER.getfilename(ext)
|
||||||
|
|
||||||
|
local dir=lfs.writedir()..[[Logs\]]
|
||||||
|
|
||||||
|
ext=ext or PROFILER.fileNameSuffix
|
||||||
|
|
||||||
|
local file=dir..PROFILER.fileNamePrefix.."."..ext
|
||||||
|
|
||||||
|
if not UTILS.FileExists(file) then
|
||||||
|
return file
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1,999 do
|
||||||
|
|
||||||
|
local file=string.format("%s%s-%03d.%s", dir,PROFILER.fileNamePrefix, i, ext)
|
||||||
|
|
||||||
|
if not UTILS.FileExists(file) then
|
||||||
|
return file
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Write info to output file.
|
||||||
|
-- @param #number runTimeGame Game time in seconds.
|
||||||
|
-- @param #number runTimeOS OS time in seconds.
|
||||||
|
function PROFILER.showInfo(runTimeGame, runTimeOS)
|
||||||
|
|
||||||
|
-- Output file.
|
||||||
|
local file=PROFILER.getfilename(PROFILER.fileNameSuffix)
|
||||||
|
local f=io.open(file, 'w')
|
||||||
|
|
||||||
|
-- Gather data.
|
||||||
|
local Ttot=0
|
||||||
|
local Calls=0
|
||||||
|
|
||||||
|
local t={}
|
||||||
|
|
||||||
|
local tcopy=nil --#PROFILER.Data
|
||||||
|
local tserialize=nil --#PROFILER.Data
|
||||||
|
local tforgen=nil --#PROFILER.Data
|
||||||
|
local tpairs=nil --#PROFILER.Data
|
||||||
|
|
||||||
|
|
||||||
|
for func, count in pairs(PROFILER.Counters) do
|
||||||
|
|
||||||
|
local s,src,line,tm=PROFILER.getData(func)
|
||||||
|
|
||||||
|
if PROFILER.logUnknown==true then
|
||||||
|
if s==nil then s="<Unknown>" end
|
||||||
|
end
|
||||||
|
|
||||||
|
if s~=nil then
|
||||||
|
|
||||||
|
-- Profile data.
|
||||||
|
local T=
|
||||||
|
{ func=s,
|
||||||
|
src=src,
|
||||||
|
line=line,
|
||||||
|
count=count,
|
||||||
|
tm=tm,
|
||||||
|
} --#PROFILER.Data
|
||||||
|
|
||||||
|
-- Collect special cases. Somehow, e.g. "_copy" appears multiple times so we try to gather all data.
|
||||||
|
if s=="_copy" then
|
||||||
|
if tcopy==nil then
|
||||||
|
tcopy=T
|
||||||
|
else
|
||||||
|
tcopy.count=tcopy.count+T.count
|
||||||
|
tcopy.tm=tcopy.tm+T.tm
|
||||||
|
end
|
||||||
|
elseif s=="_Serialize" then
|
||||||
|
if tserialize==nil then
|
||||||
|
tserialize=T
|
||||||
|
else
|
||||||
|
tserialize.count=tserialize.count+T.count
|
||||||
|
tserialize.tm=tserialize.tm+T.tm
|
||||||
|
end
|
||||||
|
elseif s=="(for generator)" then
|
||||||
|
if tforgen==nil then
|
||||||
|
tforgen=T
|
||||||
|
else
|
||||||
|
tforgen.count=tforgen.count+T.count
|
||||||
|
tforgen.tm=tforgen.tm+T.tm
|
||||||
|
end
|
||||||
|
elseif s=="pairs" then
|
||||||
|
if tpairs==nil then
|
||||||
|
tpairs=T
|
||||||
|
else
|
||||||
|
tpairs.count=tpairs.count+T.count
|
||||||
|
tpairs.tm=tpairs.tm+T.tm
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(t, T)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Total function time.
|
||||||
|
Ttot=Ttot+tm
|
||||||
|
|
||||||
|
-- Total number of calls.
|
||||||
|
Calls=Calls+count
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add special cases.
|
||||||
|
if tcopy then
|
||||||
|
table.insert(t, tcopy)
|
||||||
|
end
|
||||||
|
if tserialize then
|
||||||
|
table.insert(t, tserialize)
|
||||||
|
end
|
||||||
|
if tforgen then
|
||||||
|
table.insert(t, tforgen)
|
||||||
|
end
|
||||||
|
if tpairs then
|
||||||
|
table.insert(t, tpairs)
|
||||||
|
end
|
||||||
|
|
||||||
|
env.info('############################ Profiler Stopped ############################')
|
||||||
|
env.info(string.format("* Runtime Game : %s = %d sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||||
|
env.info(string.format("* Runtime Real : %s = %d sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||||
|
env.info(string.format("* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||||
|
env.info(string.format("* Total functions : %d", #t))
|
||||||
|
env.info(string.format("* Total func calls : %d", Calls))
|
||||||
|
env.info(string.format("* Writing to file : \"%s\"", file))
|
||||||
|
env.info(string.format("* Writing to file : \"%s\"", PROFILER.getfilename("csv")))
|
||||||
|
env.info("##############################################################################")
|
||||||
|
|
||||||
|
-- Sort by total time.
|
||||||
|
table.sort(t, function(a,b) return a.tm>b.tm end)
|
||||||
|
|
||||||
|
-- Write data.
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"-------------------------")
|
||||||
|
PROFILER._flog(f,"---- Profiler Report ----")
|
||||||
|
PROFILER._flog(f,"-------------------------")
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,string.format("* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||||
|
PROFILER._flog(f,string.format("* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||||
|
PROFILER._flog(f,string.format("* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,string.format("* Total functions = %d", #t))
|
||||||
|
PROFILER._flog(f,string.format("* Total func calls = %d", Calls))
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,string.format("* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS))
|
||||||
|
PROFILER._flog(f,string.format("* Total func time threshold = %.3f sec", PROFILER.ThreshTtot))
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER.showTable(t, f, runTimeGame)
|
||||||
|
|
||||||
|
-- Sort by number of calls.
|
||||||
|
table.sort(t, function(a,b) return a.tm/a.count>b.tm/b.count end)
|
||||||
|
|
||||||
|
-- Detailed data.
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"--------------------------------------")
|
||||||
|
PROFILER._flog(f,"---- Data Sorted by Time per Call ----")
|
||||||
|
PROFILER._flog(f,"--------------------------------------")
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER.showTable(t, f, runTimeGame)
|
||||||
|
|
||||||
|
-- Sort by number of calls.
|
||||||
|
table.sort(t, function(a,b) return a.count>b.count end)
|
||||||
|
|
||||||
|
-- Detailed data.
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"------------------------------------")
|
||||||
|
PROFILER._flog(f,"---- Data Sorted by Total Calls ----")
|
||||||
|
PROFILER._flog(f,"------------------------------------")
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER.showTable(t, f, runTimeGame)
|
||||||
|
|
||||||
|
-- Closing.
|
||||||
|
PROFILER._flog(f,"")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
|
-- Close file.
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
-- Print csv file.
|
||||||
|
PROFILER.printCSV(t, runTimeGame)
|
||||||
|
end
|
||||||
|
|
||||||
@@ -48,11 +48,15 @@ BIGSMOKEPRESET = {
|
|||||||
-- @field #string Normandy Normandy map.
|
-- @field #string Normandy Normandy map.
|
||||||
-- @field #string NTTR Nevada Test and Training Range map.
|
-- @field #string NTTR Nevada Test and Training Range map.
|
||||||
-- @field #string PersianGulf Persian Gulf map.
|
-- @field #string PersianGulf Persian Gulf map.
|
||||||
|
-- @field #string TheChannel The Channel map.
|
||||||
|
-- @field #string Syria Syria map.
|
||||||
DCSMAP = {
|
DCSMAP = {
|
||||||
Caucasus="Caucasus",
|
Caucasus="Caucasus",
|
||||||
NTTR="Nevada",
|
NTTR="Nevada",
|
||||||
Normandy="Normandy",
|
Normandy="Normandy",
|
||||||
PersianGulf="PersianGulf"
|
PersianGulf="PersianGulf",
|
||||||
|
TheChannel="TheChannel",
|
||||||
|
Syria="Syria",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -93,7 +97,7 @@ CALLSIGN={
|
|||||||
JTAC={
|
JTAC={
|
||||||
Axeman=1,
|
Axeman=1,
|
||||||
Darknight=2,
|
Darknight=2,
|
||||||
Warrier=3,
|
Warrior=3,
|
||||||
Pointer=4,
|
Pointer=4,
|
||||||
Eyeball=5,
|
Eyeball=5,
|
||||||
Moonbeam=6,
|
Moonbeam=6,
|
||||||
@@ -111,6 +115,19 @@ CALLSIGN={
|
|||||||
Mantis=18,
|
Mantis=18,
|
||||||
Badger=19,
|
Badger=19,
|
||||||
},
|
},
|
||||||
|
-- FARP
|
||||||
|
FARP={
|
||||||
|
London=1,
|
||||||
|
Dallas=2,
|
||||||
|
Paris=3,
|
||||||
|
Moscow=4,
|
||||||
|
Berlin=5,
|
||||||
|
Rome=6,
|
||||||
|
Madrid=7,
|
||||||
|
Warsaw=8,
|
||||||
|
Dublin=9,
|
||||||
|
Perth=10,
|
||||||
|
},
|
||||||
} --#CALLSIGN
|
} --#CALLSIGN
|
||||||
|
|
||||||
--- Utilities static class.
|
--- Utilities static class.
|
||||||
@@ -187,21 +204,30 @@ end
|
|||||||
-- @param #table object The input table.
|
-- @param #table object The input table.
|
||||||
-- @return #table Copy of the input table.
|
-- @return #table Copy of the input table.
|
||||||
UTILS.DeepCopy = function(object)
|
UTILS.DeepCopy = function(object)
|
||||||
|
|
||||||
local lookup_table = {}
|
local lookup_table = {}
|
||||||
|
|
||||||
|
-- Copy function.
|
||||||
local function _copy(object)
|
local function _copy(object)
|
||||||
if type(object) ~= "table" then
|
if type(object) ~= "table" then
|
||||||
return object
|
return 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
|
||||||
|
|
||||||
@@ -311,6 +337,10 @@ UTILS.MetersToNM = function(meters)
|
|||||||
return meters/1852
|
return meters/1852
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UTILS.MetersToSM = function(meters)
|
||||||
|
return meters/1609.34
|
||||||
|
end
|
||||||
|
|
||||||
UTILS.MetersToFeet = function(meters)
|
UTILS.MetersToFeet = function(meters)
|
||||||
return meters/0.3048
|
return meters/0.3048
|
||||||
end
|
end
|
||||||
@@ -351,7 +381,7 @@ UTILS.MpsToMiph = function( mps )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Convert meters per second to knots.
|
--- Convert meters per second to knots.
|
||||||
-- @param #number knots Speed in m/s.
|
-- @param #number mps Speed in m/s.
|
||||||
-- @return #number Speed in knots.
|
-- @return #number Speed in knots.
|
||||||
UTILS.MpsToKnots = function( mps )
|
UTILS.MpsToKnots = function( mps )
|
||||||
return mps * 1.94384 --3600 / 1852
|
return mps * 1.94384 --3600 / 1852
|
||||||
@@ -378,6 +408,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.
|
||||||
@@ -718,7 +756,8 @@ function UTILS.SecondsToClock(seconds, short)
|
|||||||
local clock=hours..":"..mins..":"..secs.."+"..days
|
local clock=hours..":"..mins..":"..secs.."+"..days
|
||||||
if short then
|
if short then
|
||||||
if hours=="00" then
|
if hours=="00" then
|
||||||
clock=mins..":"..secs
|
--clock=mins..":"..secs
|
||||||
|
clock=hours..":"..mins..":"..secs
|
||||||
else
|
else
|
||||||
clock=hours..":"..mins..":"..secs
|
clock=hours..":"..mins..":"..secs
|
||||||
end
|
end
|
||||||
@@ -727,6 +766,26 @@ function UTILS.SecondsToClock(seconds, short)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Seconds of today.
|
||||||
|
-- @return #number Seconds passed since last midnight.
|
||||||
|
function UTILS.SecondsOfToday()
|
||||||
|
|
||||||
|
-- Time in seconds.
|
||||||
|
local time=timer.getAbsTime()
|
||||||
|
|
||||||
|
-- Short format without days since mission start.
|
||||||
|
local clock=UTILS.SecondsToClock(time, true)
|
||||||
|
|
||||||
|
-- Time is now the seconds passed since last midnight.
|
||||||
|
return UTILS.ClockToSeconds(clock)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Cound seconds until next midnight.
|
||||||
|
-- @return #number Seconds to midnight.
|
||||||
|
function UTILS.SecondsToMidnight()
|
||||||
|
return 24*60*60-UTILS.SecondsOfToday()
|
||||||
|
end
|
||||||
|
|
||||||
--- Convert clock time from hours, minutes and seconds to seconds.
|
--- Convert clock time from hours, minutes and seconds to seconds.
|
||||||
-- @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.
|
||||||
@@ -783,6 +842,15 @@ function UTILS.DisplayMissionTime(duration)
|
|||||||
MESSAGE:New(text, duration):ToAll()
|
MESSAGE:New(text, duration):ToAll()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Replace illegal characters [<>|/?*:\\] in a string.
|
||||||
|
-- @param #string Text Input text.
|
||||||
|
-- @param #string ReplaceBy Replace illegal characters by this character or string. Default underscore "_".
|
||||||
|
-- @return #string The input text with illegal chars replaced.
|
||||||
|
function UTILS.ReplaceIllegalCharacters(Text, ReplaceBy)
|
||||||
|
ReplaceBy=ReplaceBy or "_"
|
||||||
|
local text=Text:gsub("[<>|/?*:\\]", ReplaceBy)
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
--- Generate a Gaussian pseudo-random number.
|
--- Generate a Gaussian pseudo-random number.
|
||||||
-- @param #number x0 Expectation value of distribution.
|
-- @param #number x0 Expectation value of distribution.
|
||||||
@@ -937,6 +1005,22 @@ function UTILS.HdgDiff(h1, h2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- 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 #number distance The distance to translate.
|
||||||
|
-- @param #number angle Rotation angle in degrees.
|
||||||
|
-- @return DCS#Vec3 Vector rotated in the (x,z) plane.
|
||||||
|
function UTILS.VecTranslate(a, distance, angle)
|
||||||
|
|
||||||
|
local SX = a.x
|
||||||
|
local SY = a.z
|
||||||
|
local Radians=math.rad(angle or 0)
|
||||||
|
local TX=distance*math.cos(Radians)+SX
|
||||||
|
local TY=distance*math.sin(Radians)+SY
|
||||||
|
|
||||||
|
return {x=TX, y=a.y, z=TY}
|
||||||
|
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.
|
||||||
@@ -958,7 +1042,6 @@ function UTILS.Rotate2D(a, angle)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Converts a TACAN Channel/Mode couple into a frequency in Hz.
|
--- Converts a TACAN Channel/Mode couple into a frequency in Hz.
|
||||||
-- @param #number TACANChannel The TACAN channel, i.e. the 10 in "10X".
|
-- @param #number TACANChannel The TACAN channel, i.e. the 10 in "10X".
|
||||||
-- @param #string TACANMode The TACAN mode, i.e. the "X" in "10X".
|
-- @param #string TACANMode The TACAN mode, i.e. the "X" in "10X".
|
||||||
@@ -1002,15 +1085,64 @@ function UTILS.GetDCSMap()
|
|||||||
return env.mission.theatre
|
return env.mission.theatre
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the mission date. This is the date the mission started.
|
--- Returns the mission date. This is the date the mission **started**.
|
||||||
-- @return #string Mission date in yyyy/mm/dd format.
|
-- @return #string Mission date in yyyy/mm/dd format.
|
||||||
|
-- @return #number The year anno domini.
|
||||||
|
-- @return #number The month.
|
||||||
|
-- @return #number The day.
|
||||||
function UTILS.GetDCSMissionDate()
|
function UTILS.GetDCSMissionDate()
|
||||||
local year=tostring(env.mission.date.Year)
|
local year=tostring(env.mission.date.Year)
|
||||||
local month=tostring(env.mission.date.Month)
|
local month=tostring(env.mission.date.Month)
|
||||||
local day=tostring(env.mission.date.Day)
|
local day=tostring(env.mission.date.Day)
|
||||||
return string.format("%s/%s/%s", year, month, day)
|
return string.format("%s/%s/%s", year, month, day), tonumber(year), tonumber(month), tonumber(day)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the day of the mission.
|
||||||
|
-- @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.
|
||||||
|
function UTILS.GetMissionDay(Time)
|
||||||
|
|
||||||
|
Time=Time or timer.getAbsTime()
|
||||||
|
|
||||||
|
local clock=UTILS.SecondsToClock(Time, false)
|
||||||
|
|
||||||
|
local x=tonumber(UTILS.Split(clock, "+")[2])
|
||||||
|
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the current day of the year of the mission.
|
||||||
|
-- @param #number Time (Optional) Abs. time in seconds. Default now, i.e. the value return from timer.getAbsTime().
|
||||||
|
-- @return #number Current day of year of the mission. For example, January 1st returns 0, January 2nd returns 1 etc.
|
||||||
|
function UTILS.GetMissionDayOfYear(Time)
|
||||||
|
|
||||||
|
local Date, Year, Month, Day=UTILS.GetDCSMissionDate()
|
||||||
|
|
||||||
|
local d=UTILS.GetMissionDay(Time)
|
||||||
|
|
||||||
|
return UTILS.GetDayOfYear(Year, Month, Day)+d
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the current date.
|
||||||
|
-- @return #string Mission date in yyyy/mm/dd format.
|
||||||
|
-- @return #number The year anno domini.
|
||||||
|
-- @return #number The month.
|
||||||
|
-- @return #number The day.
|
||||||
|
function UTILS.GetDate()
|
||||||
|
|
||||||
|
-- Mission start date
|
||||||
|
local date, year, month, day=UTILS.GetDCSMissionDate()
|
||||||
|
|
||||||
|
local time=timer.getAbsTime()
|
||||||
|
|
||||||
|
local clock=UTILS.SecondsToClock(time, false)
|
||||||
|
|
||||||
|
local x=tonumber(UTILS.Split(clock, "+")[2])
|
||||||
|
|
||||||
|
local day=day+x
|
||||||
|
|
||||||
|
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:
|
||||||
@@ -1035,6 +1167,10 @@ function UTILS.GetMagneticDeclination(map)
|
|||||||
declination=-10
|
declination=-10
|
||||||
elseif map==DCSMAP.PersianGulf then
|
elseif map==DCSMAP.PersianGulf then
|
||||||
declination=2
|
declination=2
|
||||||
|
elseif map==DCSMAP.TheChannel then
|
||||||
|
declination=-10
|
||||||
|
elseif map==DCSMAP.Syria then
|
||||||
|
declination=5
|
||||||
else
|
else
|
||||||
declination=0
|
declination=0
|
||||||
end
|
end
|
||||||
@@ -1144,3 +1280,189 @@ function UTILS.GetCallsignName(Callsign)
|
|||||||
|
|
||||||
return "Ghostrider"
|
return "Ghostrider"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the time difference between GMT and local time.
|
||||||
|
-- @return #number Local time difference in hours compared to GMT. E.g. Dubai is GMT+4 ==> +4 is returned.
|
||||||
|
function UTILS.GMTToLocalTimeDifference()
|
||||||
|
|
||||||
|
local theatre=UTILS.GetDCSMap()
|
||||||
|
|
||||||
|
if theatre==DCSMAP.Caucasus then
|
||||||
|
return 4 -- Caucasus UTC+4 hours
|
||||||
|
elseif theatre==DCSMAP.PersianGulf then
|
||||||
|
return 4 -- Abu Dhabi UTC+4 hours
|
||||||
|
elseif theatre==DCSMAP.NTTR then
|
||||||
|
return -8 -- Las Vegas UTC-8 hours
|
||||||
|
elseif theatre==DCSMAP.Normandy then
|
||||||
|
return 0 -- Calais UTC+1 hour
|
||||||
|
elseif theatre==DCSMAP.TheChannel then
|
||||||
|
return 2 -- This map currently needs +2
|
||||||
|
elseif theatre==DCSMAP.Syria then
|
||||||
|
return 3 -- Damascus is UTC+3 hours
|
||||||
|
else
|
||||||
|
BASE:E(string.format("ERROR: Unknown Map %s in UTILS.GMTToLocal function. Returning 0", tostring(theatre)))
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the day of the year. Counting starts on 1st of January.
|
||||||
|
-- @param #number Year The year.
|
||||||
|
-- @param #number Month The month.
|
||||||
|
-- @param #number Day The day.
|
||||||
|
-- @return #number The day of the year.
|
||||||
|
function UTILS.GetDayOfYear(Year, Month, Day)
|
||||||
|
|
||||||
|
local floor = math.floor
|
||||||
|
|
||||||
|
local n1 = floor(275 * Month / 9)
|
||||||
|
local n2 = floor((Month + 9) / 12)
|
||||||
|
local n3 = (1 + floor((Year - 4 * floor(Year / 4) + 2) / 3))
|
||||||
|
|
||||||
|
return n1 - (n2 * n3) + Day - 30
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get sunrise or sun set of a specific day of the year at a specific location.
|
||||||
|
-- @param #number DayOfYear The day of the year.
|
||||||
|
-- @param #number Latitude Latitude.
|
||||||
|
-- @param #number Longitude Longitude.
|
||||||
|
-- @param #boolean Rising If true, calc sun rise, or sun set otherwise.
|
||||||
|
-- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4.
|
||||||
|
-- @return #number Sun rise/set in seconds of the day.
|
||||||
|
function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal)
|
||||||
|
|
||||||
|
-- Defaults
|
||||||
|
local zenith=90.83
|
||||||
|
local latitude=Latitude
|
||||||
|
local longitude=Longitude
|
||||||
|
local rising=Rising
|
||||||
|
local n=DayOfYear
|
||||||
|
Tlocal=Tlocal or 0
|
||||||
|
|
||||||
|
|
||||||
|
-- Short cuts.
|
||||||
|
local rad = math.rad
|
||||||
|
local deg = math.deg
|
||||||
|
local floor = math.floor
|
||||||
|
local frac = function(n) return n - floor(n) end
|
||||||
|
local cos = function(d) return math.cos(rad(d)) end
|
||||||
|
local acos = function(d) return deg(math.acos(d)) end
|
||||||
|
local sin = function(d) return math.sin(rad(d)) end
|
||||||
|
local asin = function(d) return deg(math.asin(d)) end
|
||||||
|
local tan = function(d) return math.tan(rad(d)) end
|
||||||
|
local atan = function(d) return deg(math.atan(d)) end
|
||||||
|
|
||||||
|
local function fit_into_range(val, min, max)
|
||||||
|
local range = max - min
|
||||||
|
local count
|
||||||
|
if val < min then
|
||||||
|
count = floor((min - val) / range) + 1
|
||||||
|
return val + count * range
|
||||||
|
elseif val >= max then
|
||||||
|
count = floor((val - max) / range) + 1
|
||||||
|
return val - count * range
|
||||||
|
else
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert the longitude to hour value and calculate an approximate time
|
||||||
|
local lng_hour = longitude / 15
|
||||||
|
|
||||||
|
local t
|
||||||
|
if rising then -- Rising time is desired
|
||||||
|
t = n + ((6 - lng_hour) / 24)
|
||||||
|
else -- Setting time is desired
|
||||||
|
t = n + ((18 - lng_hour) / 24)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate the Sun's mean anomaly
|
||||||
|
local M = (0.9856 * t) - 3.289
|
||||||
|
|
||||||
|
-- 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)
|
||||||
|
|
||||||
|
-- Calculate the Sun's right ascension
|
||||||
|
local RA = fit_into_range(atan(0.91764 * tan(L)), 0, 360)
|
||||||
|
|
||||||
|
-- Right ascension value needs to be in the same quadrant as L
|
||||||
|
local Lquadrant = floor(L / 90) * 90
|
||||||
|
local RAquadrant = floor(RA / 90) * 90
|
||||||
|
RA = RA + Lquadrant - RAquadrant
|
||||||
|
|
||||||
|
-- Right ascension value needs to be converted into hours
|
||||||
|
RA = RA / 15
|
||||||
|
|
||||||
|
-- Calculate the Sun's declination
|
||||||
|
local sinDec = 0.39782 * sin(L)
|
||||||
|
local cosDec = cos(asin(sinDec))
|
||||||
|
|
||||||
|
-- Calculate the Sun's local hour angle
|
||||||
|
local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude))
|
||||||
|
|
||||||
|
if rising and cosH > 1 then
|
||||||
|
return "N/R" -- The sun never rises on this location on the specified date
|
||||||
|
elseif cosH < -1 then
|
||||||
|
return "N/S" -- The sun never sets on this location on the specified date
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Finish calculating H and convert into hours
|
||||||
|
local H
|
||||||
|
if rising then
|
||||||
|
H = 360 - acos(cosH)
|
||||||
|
else
|
||||||
|
H = acos(cosH)
|
||||||
|
end
|
||||||
|
H = H / 15
|
||||||
|
|
||||||
|
-- Calculate local mean time of rising/setting
|
||||||
|
local T = H + RA - (0.06571 * t) - 6.622
|
||||||
|
|
||||||
|
-- Adjust back to UTC
|
||||||
|
local UT = fit_into_range(T - lng_hour +Tlocal, 0, 24)
|
||||||
|
|
||||||
|
return floor(UT)*60*60+frac(UT)*60*60--+Tlocal*60*60
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get sun rise of a specific day of the year at a specific location.
|
||||||
|
-- @param #number Day Day of the year.
|
||||||
|
-- @param #number Month Month of the year.
|
||||||
|
-- @param #number Year Year.
|
||||||
|
-- @param #number Latitude Latitude.
|
||||||
|
-- @param #number Longitude Longitude.
|
||||||
|
-- @param #boolean Rising If true, calc sun rise, or sun set otherwise.
|
||||||
|
-- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. Default 0.
|
||||||
|
-- @return #number Sun rise in seconds of the day.
|
||||||
|
function UTILS.GetSunrise(Day, Month, Year, Latitude, Longitude, Tlocal)
|
||||||
|
|
||||||
|
local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day)
|
||||||
|
|
||||||
|
return UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tlocal)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get sun set of a specific day of the year at a specific location.
|
||||||
|
-- @param #number Day Day of the year.
|
||||||
|
-- @param #number Month Month of the year.
|
||||||
|
-- @param #number Year Year.
|
||||||
|
-- @param #number Latitude Latitude.
|
||||||
|
-- @param #number Longitude Longitude.
|
||||||
|
-- @param #boolean Rising If true, calc sun rise, or sun set otherwise.
|
||||||
|
-- @param #number Tlocal Local time offset in hours. E.g. +4 for a location which has GMT+4. Default 0.
|
||||||
|
-- @return #number Sun rise in seconds of the day.
|
||||||
|
function UTILS.GetSunset(Day, Month, Year, Latitude, Longitude, Tlocal)
|
||||||
|
|
||||||
|
local DayOfYear=UTILS.GetDayOfYear(Year, Month, Day)
|
||||||
|
|
||||||
|
return UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tlocal)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get OS time. Needs os to be desanitized!
|
||||||
|
-- @return #number Os time in seconds.
|
||||||
|
function UTILS.GetOSTime()
|
||||||
|
if os then
|
||||||
|
return os.clock()
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|||||||
@@ -15,7 +15,18 @@
|
|||||||
--- @type AIRBASE
|
--- @type AIRBASE
|
||||||
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
|
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
|
||||||
-- @field #table CategoryName Names of airbase categories.
|
-- @field #table CategoryName Names of airbase categories.
|
||||||
|
-- @field #string AirbaseName Name of the airbase.
|
||||||
|
-- @field #number AirbaseID Airbase ID.
|
||||||
|
-- @field #number category Airbase category.
|
||||||
|
-- @field #table descriptors DCS descriptors.
|
||||||
|
-- @field #boolean isAirdrome Airbase is an airdrome.
|
||||||
|
-- @field #boolean isHelipad Airbase is a helipad.
|
||||||
|
-- @field #boolean isShip Airbase is a ship.
|
||||||
|
-- @field #table parking Parking spot data.
|
||||||
|
-- @field #table parkingByID Parking spot data table with ID as key.
|
||||||
-- @field #number activerwyno Active runway number (forced).
|
-- @field #number activerwyno Active runway number (forced).
|
||||||
|
-- @field #table parkingWhitelist List of parking spot terminal IDs considered for spawning.
|
||||||
|
-- @field #table parkingBlacklist List of parking spot terminal IDs **not** considered for spawning.
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
--- Wrapper class to handle the DCS Airbase objects:
|
--- Wrapper class to handle the DCS Airbase objects:
|
||||||
@@ -259,37 +270,152 @@ AIRBASE.Normandy = {
|
|||||||
-- * AIRBASE.PersianGulf.Tunb_Kochak
|
-- * AIRBASE.PersianGulf.Tunb_Kochak
|
||||||
-- @field PersianGulf
|
-- @field PersianGulf
|
||||||
AIRBASE.PersianGulf = {
|
AIRBASE.PersianGulf = {
|
||||||
["Abu_Dhabi_International_Airport"] = "Abu Dhabi International Airport",
|
["Abu_Dhabi_International_Airport"] = "Abu Dhabi Intl",
|
||||||
["Abu_Musa_Island_Airport"] = "Abu Musa Island Airport",
|
["Abu_Musa_Island_Airport"] = "Abu Musa Island",
|
||||||
["Al_Ain_International_Airport"] = "Al Ain International Airport",
|
["Al_Ain_International_Airport"] = "Al Ain Intl",
|
||||||
["Al_Bateen_Airport"] = "Al-Bateen Airport",
|
["Al_Bateen_Airport"] = "Al-Bateen",
|
||||||
["Al_Dhafra_AB"] = "Al Dhafra AB",
|
["Al_Dhafra_AB"] = "Al Dhafra AFB",
|
||||||
["Al_Maktoum_Intl"] = "Al Maktoum Intl",
|
["Al_Maktoum_Intl"] = "Al Maktoum Intl",
|
||||||
["Al_Minhad_AB"] = "Al Minhad AB",
|
["Al_Minhad_AB"] = "Al Minhad AFB",
|
||||||
["Bandar_Abbas_Intl"] = "Bandar Abbas Intl",
|
["Bandar_Abbas_Intl"] = "Bandar Abbas Intl",
|
||||||
["Bandar_Lengeh"] = "Bandar Lengeh",
|
["Bandar_Lengeh"] = "Bandar Lengeh",
|
||||||
["Bandar_e_Jask_airfield"] = "Bandar-e-Jask airfield",
|
["Bandar_e_Jask_airfield"] = "Bandar-e-Jask",
|
||||||
["Dubai_Intl"] = "Dubai Intl",
|
["Dubai_Intl"] = "Dubai Intl",
|
||||||
["Fujairah_Intl"] = "Fujairah Intl",
|
["Fujairah_Intl"] = "Fujairah Intl",
|
||||||
["Havadarya"] = "Havadarya",
|
["Havadarya"] = "Havadarya",
|
||||||
["Jiroft_Airport"] = "Jiroft Airport",
|
["Jiroft_Airport"] = "Jiroft",
|
||||||
["Kerman_Airport"] = "Kerman Airport",
|
["Kerman_Airport"] = "Kerman",
|
||||||
["Khasab"] = "Khasab",
|
["Khasab"] = "Khasab",
|
||||||
["Kish_International_Airport"] = "Kish International Airport",
|
["Kish_International_Airport"] = "Kish Intl",
|
||||||
["Lar_Airbase"] = "Lar Airbase",
|
["Lar_Airbase"] = "Lar",
|
||||||
["Lavan_Island_Airport"] = "Lavan Island Airport",
|
["Lavan_Island_Airport"] = "Lavan Island",
|
||||||
["Liwa_Airbase"] = "Liwa Airbase",
|
["Liwa_Airbase"] = "Liwa AFB",
|
||||||
["Qeshm_Island"] = "Qeshm Island",
|
["Qeshm_Island"] = "Qeshm Island",
|
||||||
["Ras_Al_Khaimah"] = "Ras Al Khaimah",
|
["Ras_Al_Khaimah"] = "Ras Al Khaimah Intl",
|
||||||
["Sas_Al_Nakheel_Airport"] = "Sas Al Nakheel Airport",
|
["Sas_Al_Nakheel_Airport"] = "Sas Al Nakheel",
|
||||||
["Sharjah_Intl"] = "Sharjah Intl",
|
["Sharjah_Intl"] = "Sharjah Intl",
|
||||||
["Shiraz_International_Airport"] = "Shiraz International Airport",
|
["Shiraz_International_Airport"] = "Shiraz Intl",
|
||||||
["Sir_Abu_Nuayr"] = "Sir Abu Nuayr",
|
["Sir_Abu_Nuayr"] = "Sir Abu Nuayr",
|
||||||
["Sirri_Island"] = "Sirri Island",
|
["Sirri_Island"] = "Sirri Island",
|
||||||
["Tunb_Island_AFB"] = "Tunb Island AFB",
|
["Tunb_Island_AFB"] = "Tunb Island AFB",
|
||||||
["Tunb_Kochak"] = "Tunb Kochak",
|
["Tunb_Kochak"] = "Tunb Kochak",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- These are all airbases of the The Channel Map:
|
||||||
|
--
|
||||||
|
-- * AIRBASE.TheChannel.Abbeville_Drucat
|
||||||
|
-- * AIRBASE.TheChannel.Merville_Calonne
|
||||||
|
-- * AIRBASE.TheChannel.Saint_Omer_Longuenesse
|
||||||
|
-- * AIRBASE.TheChannel.Dunkirk_Mardyck
|
||||||
|
-- * AIRBASE.TheChannel.Manston
|
||||||
|
-- * AIRBASE.TheChannel.Hawkinge
|
||||||
|
-- * AIRBASE.TheChannel.Lympne
|
||||||
|
-- * AIRBASE.TheChannel.Detling
|
||||||
|
-- * AIRBASE.TheChannel.High_Halden
|
||||||
|
--
|
||||||
|
-- @field TheChannel
|
||||||
|
AIRBASE.TheChannel = {
|
||||||
|
["Abbeville_Drucat"] = "Abbeville Drucat",
|
||||||
|
["Merville_Calonne"] = "Merville Calonne",
|
||||||
|
["Saint_Omer_Longuenesse"] = "Saint Omer Longuenesse",
|
||||||
|
["Dunkirk_Mardyck"] = "Dunkirk Mardyck",
|
||||||
|
["Manston"] = "Manston",
|
||||||
|
["Hawkinge"] = "Hawkinge",
|
||||||
|
["Lympne"] = "Lympne",
|
||||||
|
["Detling"] = "Detling",
|
||||||
|
["High_Halden"] = "High Halden",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Airbases of Syria
|
||||||
|
--
|
||||||
|
-- * AIRBASE.Syria.Kuweires
|
||||||
|
-- * AIRBASE.Syria.Marj_Ruhayyil
|
||||||
|
-- * AIRBASE.Syria.Kiryat_Shmona
|
||||||
|
-- * AIRBASE.Syria.Marj_as_Sultan_North
|
||||||
|
-- * AIRBASE.Syria.Eyn_Shemer
|
||||||
|
-- * AIRBASE.Syria.Incirlik
|
||||||
|
-- * AIRBASE.Syria.Damascus
|
||||||
|
-- * AIRBASE.Syria.Bassel_Al_Assad
|
||||||
|
-- * AIRBASE.Syria.Aleppo
|
||||||
|
-- * AIRBASE.Syria.Qabr_as_Sitt
|
||||||
|
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
||||||
|
-- * AIRBASE.Syria.Al_Dumayr
|
||||||
|
-- * AIRBASE.Syria.Hatay
|
||||||
|
-- * AIRBASE.Syria.Haifa
|
||||||
|
-- * AIRBASE.Syria.Khalkhalah
|
||||||
|
-- * AIRBASE.Syria.Megiddo
|
||||||
|
-- * AIRBASE.Syria.Rayak
|
||||||
|
-- * AIRBASE.Syria.Mezzeh
|
||||||
|
-- * AIRBASE.Syria.King_Hussein_Air_College
|
||||||
|
-- * AIRBASE.Syria.Jirah
|
||||||
|
-- * AIRBASE.Syria.Taftanaz
|
||||||
|
-- * AIRBASE.Syria.Rene_Mouawad
|
||||||
|
-- * AIRBASE.Syria.Ramat_David
|
||||||
|
-- * AIRBASE.Syria.Minakh
|
||||||
|
-- * AIRBASE.Syria.Adana_Sakirpasa
|
||||||
|
-- * AIRBASE.Syria.Marj_as_Sultan_South
|
||||||
|
-- * AIRBASE.Syria.Hama
|
||||||
|
-- * AIRBASE.Syria.Al_Qusayr
|
||||||
|
-- * AIRBASE.Syria.Palmyra
|
||||||
|
-- * AIRBASE.Syria.Tabqa
|
||||||
|
-- * AIRBASE.Syria.Beirut_Rafic_Hariri
|
||||||
|
-- * AIRBASE.Syria.An_Nasiriyah
|
||||||
|
-- * AIRBASE.Syria.Abu_al_Duhur
|
||||||
|
-- * AIRBASE.Syria.H4
|
||||||
|
-- * AIRBASE.Syria.Gaziantep
|
||||||
|
-- * AIRBASE.Syria.Rosh_Pina
|
||||||
|
-- * AIRBASE.Syria.Sayqal
|
||||||
|
-- * AIRBASE.Syria.Shayrat
|
||||||
|
-- * AIRBASE.Syria.Tiyas
|
||||||
|
-- * AIRBASE.Syria.Tha_lah
|
||||||
|
-- * AIRBASE.Syria.Naqoura
|
||||||
|
--
|
||||||
|
-- @field Syria
|
||||||
|
AIRBASE.Syria={
|
||||||
|
["Kuweires"]="Kuweires",
|
||||||
|
["Marj_Ruhayyil"]="Marj Ruhayyil",
|
||||||
|
["Kiryat_Shmona"]="Kiryat Shmona",
|
||||||
|
["Marj_as_Sultan_North"]="Marj as Sultan North",
|
||||||
|
["Eyn_Shemer"]="Eyn Shemer",
|
||||||
|
["Incirlik"]="Incirlik",
|
||||||
|
["Damascus"]="Damascus",
|
||||||
|
["Bassel_Al_Assad"]="Bassel Al-Assad",
|
||||||
|
["Aleppo"]="Aleppo",
|
||||||
|
["Qabr_as_Sitt"]="Qabr as Sitt",
|
||||||
|
["Wujah_Al_Hajar"]="Wujah Al Hajar",
|
||||||
|
["Al_Dumayr"]="Al-Dumayr",
|
||||||
|
["Hatay"]="Hatay",
|
||||||
|
["Haifa"]="Haifa",
|
||||||
|
["Khalkhalah"]="Khalkhalah",
|
||||||
|
["Megiddo"]="Megiddo",
|
||||||
|
["Rayak"]="Rayak",
|
||||||
|
["Mezzeh"]="Mezzeh",
|
||||||
|
["King_Hussein_Air_College"]="King Hussein Air College",
|
||||||
|
["Jirah"]="Jirah",
|
||||||
|
["Taftanaz"]="Taftanaz",
|
||||||
|
["Rene_Mouawad"]="Rene Mouawad",
|
||||||
|
["Ramat_David"]="Ramat David",
|
||||||
|
["Minakh"]="Minakh",
|
||||||
|
["Adana_Sakirpasa"]="Adana Sakirpasa",
|
||||||
|
["Marj_as_Sultan_South"]="Marj as Sultan South",
|
||||||
|
["Hama"]="Hama",
|
||||||
|
["Al_Qusayr"]="Al Qusayr",
|
||||||
|
["Palmyra"]="Palmyra",
|
||||||
|
["Tabqa"]="Tabqa",
|
||||||
|
["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri",
|
||||||
|
["An_Nasiriyah"]="An Nasiriyah",
|
||||||
|
["Abu_al_Duhur"]="Abu al-Duhur",
|
||||||
|
["H4"]="H4",
|
||||||
|
["Gaziantep"]="Gaziantep",
|
||||||
|
["Rosh_Pina"]="Rosh Pina",
|
||||||
|
["Sayqal"]="Sayqal",
|
||||||
|
["Shayrat"]="Shayrat",
|
||||||
|
["Tiyas"]="Tiyas",
|
||||||
|
["Tha_lah"]="Tha'lah",
|
||||||
|
["Naqoura"]="Naqoura",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||||
-- @type AIRBASE.ParkingSpot
|
-- @type AIRBASE.ParkingSpot
|
||||||
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
|
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
|
||||||
@@ -341,20 +467,52 @@ AIRBASE.TerminalType = {
|
|||||||
-- @field Core.Point#COORDINATE position Position of runway start.
|
-- @field Core.Point#COORDINATE position Position of runway start.
|
||||||
-- @field Core.Point#COORDINATE endpoint End point of runway.
|
-- @field Core.Point#COORDINATE endpoint End point of runway.
|
||||||
|
|
||||||
-- Registration.
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Registration
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Create a new AIRBASE from DCSAirbase.
|
--- Create a new AIRBASE from DCSAirbase.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @param #string AirbaseName The name of the airbase.
|
-- @param #string AirbaseName The name of the airbase.
|
||||||
-- @return Wrapper.Airbase#AIRBASE
|
-- @return #AIRBASE self
|
||||||
function AIRBASE:Register( AirbaseName )
|
function AIRBASE:Register(AirbaseName)
|
||||||
|
|
||||||
|
-- Inherit everything from positionable.
|
||||||
|
local self=BASE:Inherit(self, POSITIONABLE:New(AirbaseName)) --#AIRBASE
|
||||||
|
|
||||||
|
-- Set airbase name.
|
||||||
|
self.AirbaseName=AirbaseName
|
||||||
|
|
||||||
|
-- Set airbase ID.
|
||||||
|
self.AirbaseID=self:GetID(true)
|
||||||
|
|
||||||
|
-- Get descriptors.
|
||||||
|
self.descriptors=self:GetDesc()
|
||||||
|
|
||||||
|
-- Category.
|
||||||
|
self.category=self.descriptors and self.descriptors.category or Airbase.Category.AIRDROME
|
||||||
|
|
||||||
|
-- Set category.
|
||||||
|
if self.category==Airbase.Category.AIRDROME then
|
||||||
|
self.isAirdrome=true
|
||||||
|
elseif self.category==Airbase.Category.HELIPAD then
|
||||||
|
self.isHelipad=true
|
||||||
|
elseif self.category==Airbase.Category.SHIP then
|
||||||
|
self.isShip=true
|
||||||
|
else
|
||||||
|
self:E("ERROR: Unknown airbase category!")
|
||||||
|
end
|
||||||
|
|
||||||
|
self:_InitParkingSpots()
|
||||||
|
|
||||||
local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) ) --#AIRBASE
|
|
||||||
self.AirbaseName = AirbaseName
|
|
||||||
self.AirbaseID = self:GetID(true)
|
|
||||||
local vec2=self:GetVec2()
|
local vec2=self:GetVec2()
|
||||||
|
|
||||||
|
-- Init coordinate.
|
||||||
|
self:GetCoordinate()
|
||||||
|
|
||||||
if vec2 then
|
if vec2 then
|
||||||
self.AirbaseZone = ZONE_RADIUS:New( AirbaseName, vec2, 2500 )
|
-- TODO: For ships we need a moving zone.
|
||||||
|
self.AirbaseZone=ZONE_RADIUS:New( AirbaseName, vec2, 2500 )
|
||||||
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
|
||||||
@@ -362,7 +520,9 @@ function AIRBASE:Register( AirbaseName )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reference methods.
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Reference methods
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Finds a AIRBASE from the _DATABASE using a DCSAirbase object.
|
--- Finds a AIRBASE from the _DATABASE using a DCSAirbase object.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
@@ -409,7 +569,9 @@ end
|
|||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @return DCS#Airbase DCS airbase object.
|
-- @return DCS#Airbase DCS airbase object.
|
||||||
function AIRBASE:GetDCSObject()
|
function AIRBASE:GetDCSObject()
|
||||||
local DCSAirbase = Airbase.getByName( self.AirbaseName )
|
|
||||||
|
-- Get the DCS object.
|
||||||
|
local DCSAirbase = Airbase.getByName(self.AirbaseName)
|
||||||
|
|
||||||
if DCSAirbase then
|
if DCSAirbase then
|
||||||
return DCSAirbase
|
return DCSAirbase
|
||||||
@@ -434,7 +596,7 @@ function AIRBASE.GetAllAirbases(coalition, category)
|
|||||||
local airbases={}
|
local airbases={}
|
||||||
for _,_airbase in pairs(_DATABASE.AIRBASES) do
|
for _,_airbase in pairs(_DATABASE.AIRBASES) do
|
||||||
local airbase=_airbase --#AIRBASE
|
local airbase=_airbase --#AIRBASE
|
||||||
if (coalition~=nil and airbase:GetCoalition()==coalition) or coalition==nil then
|
if coalition==nil or airbase:GetCoalition()==coalition then
|
||||||
if category==nil or category==airbase:GetAirbaseCategory() then
|
if category==nil or category==airbase:GetAirbaseCategory() then
|
||||||
table.insert(airbases, airbase)
|
table.insert(airbases, airbase)
|
||||||
end
|
end
|
||||||
@@ -444,6 +606,25 @@ function AIRBASE.GetAllAirbases(coalition, category)
|
|||||||
return airbases
|
return airbases
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get all airbase names of the current map. This includes ships and FARPS.
|
||||||
|
-- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned.
|
||||||
|
-- @param #number category (Optional) Return only airbases of a certain category, e.g. Airbase.Category.FARP
|
||||||
|
-- @return #table Table containing all airbase names of the current map.
|
||||||
|
function AIRBASE.GetAllAirbaseNames(coalition, category)
|
||||||
|
|
||||||
|
local airbases={}
|
||||||
|
for airbasename,_airbase in pairs(_DATABASE.AIRBASES) do
|
||||||
|
local airbase=_airbase --#AIRBASE
|
||||||
|
if coalition==nil or airbase:GetCoalition()==coalition then
|
||||||
|
if category==nil or category==airbase:GetAirbaseCategory() then
|
||||||
|
table.insert(airbases, airbasename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return airbases
|
||||||
|
end
|
||||||
|
|
||||||
--- Get ID of the airbase.
|
--- Get ID of the airbase.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @param #boolean unique (Optional) If true, ships will get a negative sign as the unit ID might be the same as an airbase ID. Default off!
|
-- @param #boolean unique (Optional) If true, ships will get a negative sign as the unit ID might be the same as an airbase ID. Default off!
|
||||||
@@ -466,24 +647,8 @@ function AIRBASE:GetID(unique)
|
|||||||
|
|
||||||
local airbaseCategory=self:GetAirbaseCategory()
|
local airbaseCategory=self:GetAirbaseCategory()
|
||||||
|
|
||||||
--env.info(string.format("FF airbase=%s id=%s category=%s", tostring(AirbaseName), tostring(airbaseID), tostring(airbaseCategory)))
|
|
||||||
|
|
||||||
-- No way AFIK to get the DCS version. So we check if the event exists. That should tell us if we are on DCS 2.5.6 or prior to that.
|
|
||||||
--[[
|
|
||||||
if world.event.S_EVENT_KILL and world.event.S_EVENT_KILL>0 and airbaseCategory==Airbase.Category.AIRDROME then
|
|
||||||
|
|
||||||
-- We have to take the key value of this loop!
|
|
||||||
airbaseID=DCSAirbaseId
|
|
||||||
|
|
||||||
-- Now another quirk: for Caucasus, we need to add 11 to the key value to get the correct ID. See https://forums.eagle.ru/showpost.php?p=4210774&postcount=11
|
|
||||||
if UTILS.GetDCSMap()==DCSMAP.Caucasus then
|
|
||||||
airbaseID=airbaseID+11
|
|
||||||
end
|
|
||||||
end
|
|
||||||
]]
|
|
||||||
|
|
||||||
if AirbaseName==self.AirbaseName then
|
if AirbaseName==self.AirbaseName then
|
||||||
if airbaseCategory==Airbase.Category.SHIP 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.
|
||||||
return unique and -airbaseID or airbaseID
|
return unique and -airbaseID or airbaseID
|
||||||
else
|
else
|
||||||
@@ -498,6 +663,86 @@ function AIRBASE:GetID(unique)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set parking spot whitelist. Only these spots will be considered for spawning.
|
||||||
|
-- Black listed spots overrule white listed spots.
|
||||||
|
-- **NOTE** that terminal IDs are not necessarily the same as those displayed in the mission editor!
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param #table TerminalIdBlacklist Table of white listed terminal IDs.
|
||||||
|
-- @return #AIRBASE self
|
||||||
|
-- @usage AIRBASE:FindByName("Batumi"):SetParkingSpotWhitelist({2, 3, 4}) --Only allow terminal IDs 2, 3, 4
|
||||||
|
function AIRBASE:SetParkingSpotWhitelist(TerminalIdWhitelist)
|
||||||
|
|
||||||
|
if TerminalIdWhitelist==nil then
|
||||||
|
self.parkingWhitelist={}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure we got a table.
|
||||||
|
if type(TerminalIdWhitelist)~="table" then
|
||||||
|
TerminalIdWhitelist={TerminalIdWhitelist}
|
||||||
|
end
|
||||||
|
|
||||||
|
self.parkingWhitelist=TerminalIdWhitelist
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set parking spot blacklist. These parking spots will *not* be used for spawning.
|
||||||
|
-- Black listed spots overrule white listed spots.
|
||||||
|
-- **NOTE** that terminal IDs are not necessarily the same as those displayed in the mission editor!
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param #table TerminalIdBlacklist Table of black listed terminal IDs.
|
||||||
|
-- @return #AIRBASE self
|
||||||
|
-- @usage AIRBASE:FindByName("Batumi"):SetParkingSpotBlacklist({2, 3, 4}) --Forbit terminal IDs 2, 3, 4
|
||||||
|
function AIRBASE:SetParkingSpotBlacklist(TerminalIdBlacklist)
|
||||||
|
|
||||||
|
if TerminalIdBlacklist==nil then
|
||||||
|
self.parkingBlacklist={}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure we got a table.
|
||||||
|
if type(TerminalIdBlacklist)~="table" then
|
||||||
|
TerminalIdBlacklist={TerminalIdBlacklist}
|
||||||
|
end
|
||||||
|
|
||||||
|
self.parkingBlacklist=TerminalIdBlacklist
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get category of airbase.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @return #number Category of airbase from GetDesc().category.
|
||||||
|
function AIRBASE:GetAirbaseCategory()
|
||||||
|
return self.category
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if airbase is an airdrome.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @return #boolean If true, airbase is an airdrome.
|
||||||
|
function AIRBASE:IsAirdrome()
|
||||||
|
return self.isAirdrome
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if airbase is a helipad.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @return #boolean If true, airbase is a helipad.
|
||||||
|
function AIRBASE:IsHelipad()
|
||||||
|
return self.isHelipad
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if airbase is a ship.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @return #boolean If true, airbase is a ship.
|
||||||
|
function AIRBASE:IsShip()
|
||||||
|
return self.isShip
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Parking
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Returns a table of parking data for a given airbase. If the optional parameter *available* is true only available parking will be returned, otherwise all parking at the base is returned. Term types have the following enumerated values:
|
--- Returns a table of parking data for a given airbase. If the optional parameter *available* is true only available parking will be returned, otherwise all parking at the base is returned. Term types have the following enumerated values:
|
||||||
--
|
--
|
||||||
@@ -629,6 +874,60 @@ function AIRBASE:GetParkingSpotsCoordinates(termtype)
|
|||||||
return spots
|
return spots
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @return#AIRBASE self
|
||||||
|
function AIRBASE:_InitParkingSpots()
|
||||||
|
|
||||||
|
-- Get parking data of all spots (free or occupied)
|
||||||
|
local parkingdata=self:GetParkingData(false)
|
||||||
|
|
||||||
|
-- Init table.
|
||||||
|
self.parking={}
|
||||||
|
self.parkingByID={}
|
||||||
|
|
||||||
|
self.NparkingTotal=0
|
||||||
|
self.NparkingTerminal={}
|
||||||
|
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
||||||
|
self.NparkingTerminal[terminalType]=0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Put coordinates of parking spots into table.
|
||||||
|
for _,spot in pairs(parkingdata) do
|
||||||
|
|
||||||
|
-- New parking spot.
|
||||||
|
local park={} --#AIRBASE.ParkingSpot
|
||||||
|
park.Vec3=spot.vTerminalPos
|
||||||
|
park.Coordinate=COORDINATE:NewFromVec3(spot.vTerminalPos)
|
||||||
|
park.DistToRwy=spot.fDistToRW
|
||||||
|
park.Free=nil
|
||||||
|
park.TerminalID=spot.Term_Index
|
||||||
|
park.TerminalID0=spot.Term_Index_0
|
||||||
|
park.TerminalType=spot.Term_Type
|
||||||
|
park.TOAC=spot.TO_AC
|
||||||
|
|
||||||
|
self.NparkingTotal=self.NparkingTotal+1
|
||||||
|
|
||||||
|
for _,terminalType in pairs(AIRBASE.TerminalType) do
|
||||||
|
if self._CheckTerminalType(terminalType, park.TerminalType) then
|
||||||
|
self.NparkingTerminal[terminalType]=self.NparkingTerminal[terminalType]+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.parkingByID[park.TerminalID]=park
|
||||||
|
table.insert(self.parking, park)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param #number TerminalID Terminal ID.
|
||||||
|
-- @return #AIRBASE.ParkingSpot Parking spot.
|
||||||
|
function AIRBASE:_GetParkingSpotByID(TerminalID)
|
||||||
|
return self.parkingByID[TerminalID]
|
||||||
|
end
|
||||||
|
|
||||||
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
@@ -638,6 +937,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)
|
||||||
|
|
||||||
@@ -654,15 +954,18 @@ 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
|
||||||
self:T2({_spot=_spot})
|
|
||||||
local _free=_isfree(_spot)
|
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
|
||||||
local _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos)
|
|
||||||
table.insert(spots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=_free, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW})
|
spot.Free=_isfree(_spot) -- updated
|
||||||
end
|
spot.TOAC=_spot.TO_AC -- updated
|
||||||
|
|
||||||
|
table.insert(spots, spot)
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T2({ spots = spots } )
|
end
|
||||||
|
|
||||||
return spots
|
return spots
|
||||||
end
|
end
|
||||||
@@ -682,8 +985,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 _coord=COORDINATE:NewFromVec3(_spot.vTerminalPos)
|
|
||||||
table.insert(freespots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=true, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW})
|
local spot=self:_GetParkingSpotByID(_spot.Term_Index)
|
||||||
|
|
||||||
|
spot.Free=true -- updated
|
||||||
|
spot.TOAC=_spot.TO_AC -- updated
|
||||||
|
|
||||||
|
table.insert(freespots, spot)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -696,14 +1005,10 @@ end
|
|||||||
-- @param #number TerminalID The terminal ID of the parking spot.
|
-- @param #number TerminalID The terminal ID of the parking spot.
|
||||||
-- @return #AIRBASE.ParkingSpot Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
-- @return #AIRBASE.ParkingSpot Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||||
function AIRBASE:GetParkingSpotData(TerminalID)
|
function AIRBASE:GetParkingSpotData(TerminalID)
|
||||||
self:F({TerminalID=TerminalID})
|
|
||||||
|
|
||||||
-- Get parking data.
|
-- Get parking data.
|
||||||
local parkingdata=self:GetParkingSpotsTable()
|
local parkingdata=self:GetParkingSpotsTable()
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
self:T2({parkingdata=parkingdata})
|
|
||||||
|
|
||||||
for _,_spot in pairs(parkingdata) do
|
for _,_spot in pairs(parkingdata) do
|
||||||
local spot=_spot --#AIRBASE.ParkingSpot
|
local spot=_spot --#AIRBASE.ParkingSpot
|
||||||
self:T({TerminalID=spot.TerminalID,TerminalType=spot.TerminalType})
|
self:T({TerminalID=spot.TerminalID,TerminalType=spot.TerminalType})
|
||||||
@@ -838,9 +1143,8 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
||||||
local _termid=parkingspot.TerminalID
|
local _termid=parkingspot.TerminalID
|
||||||
|
|
||||||
self:T2({_termid=_termid})
|
-- Check terminal type and black/white listed parking spots.
|
||||||
|
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) and self:_CheckParkingLists(_termid) then
|
||||||
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) then
|
|
||||||
|
|
||||||
-- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off.
|
-- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off.
|
||||||
if verysafe and (parkingspot.Free==false or parkingspot.TOAC==true) then
|
if verysafe and (parkingspot.Free==false or parkingspot.TOAC==true) then
|
||||||
@@ -942,98 +1246,38 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
return validspots
|
return validspots
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function that checks if at leat one unit of a group has been spawned close to a spawn point on the runway.
|
--- Check black and white lists.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @param Wrapper.Group#GROUP group Group to be checked.
|
-- @param #number TerminalID Terminal ID to check.
|
||||||
-- @param #number radius Radius around the spawn point to be checked. Default is 50 m.
|
-- @return #boolean `true` if this is a valid spot.
|
||||||
-- @param #boolean despawn If true, the group is destroyed.
|
function AIRBASE:_CheckParkingLists(TerminalID)
|
||||||
-- @return #boolean True if group is within radius around spawn points on runway.
|
|
||||||
function AIRBASE:CheckOnRunWay(group, radius, despawn)
|
|
||||||
|
|
||||||
-- Default radius.
|
-- First check the black list. If we find a match, this spot is forbidden!
|
||||||
radius=radius or 50
|
if self.parkingBlacklist and #self.parkingBlacklist>0 then
|
||||||
|
for _,terminalID in pairs(self.parkingBlacklist or {}) do
|
||||||
-- We only check at real airbases (not FARPS or ships).
|
if terminalID==TerminalID then
|
||||||
if self:GetAirbaseCategory()~=Airbase.Category.AIRDROME then
|
-- This is a invalid spot.
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if group and group:IsAlive() then
|
|
||||||
|
|
||||||
-- Debug.
|
|
||||||
self:T(string.format("%s, checking if group %s is on runway?",self:GetName(), group:GetName()))
|
|
||||||
|
|
||||||
-- Get coordinates on runway.
|
|
||||||
local runwaypoints=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
|
|
||||||
|
|
||||||
-- Mark runway spawn points.
|
|
||||||
--[[
|
|
||||||
for _i,_coord in pairs(runwaypoints) do
|
|
||||||
_coord:MarkToAll(string.format("runway %d",_i))
|
|
||||||
end
|
end
|
||||||
]]
|
|
||||||
|
|
||||||
-- Get units of group.
|
|
||||||
local units=group:GetUnits()
|
|
||||||
|
|
||||||
-- Loop over units.
|
|
||||||
for _,_unit in pairs(units) do
|
|
||||||
|
|
||||||
local unit=_unit --Wrapper.Unit#UNIT
|
|
||||||
|
|
||||||
-- Check if unit is alive and not in air.
|
|
||||||
if unit and unit:IsAlive() and not unit:InAir() then
|
|
||||||
self:T(string.format("%s, checking if unit %s is on runway?",self:GetName(), unit:GetName()))
|
|
||||||
|
|
||||||
-- Loop over runway spawn points.
|
|
||||||
for _i,_coord in pairs(runwaypoints) do
|
|
||||||
|
|
||||||
-- Distance between unit and spawn pos.
|
|
||||||
local dist=unit:GetCoordinate():Get2DDistance(_coord)
|
|
||||||
|
|
||||||
-- Mark unit spawn points for debugging.
|
|
||||||
--unit:GetCoordinate():MarkToAll(string.format("unit %s distance to rwy %d = %d",unit:GetName(),_i, dist))
|
|
||||||
|
|
||||||
-- Check if unit is withing radius.
|
|
||||||
if dist<radius then
|
|
||||||
self:E(string.format("%s, unit %s of group %s was spawned on runway #%d. Distance %.1f < radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
|
|
||||||
--unit:FlareRed()
|
|
||||||
if despawn then
|
|
||||||
group:Destroy(true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Check if a whitelist was defined.
|
||||||
|
if self.parkingWhitelist and #self.parkingWhitelist>0 then
|
||||||
|
for _,terminalID in pairs(self.parkingWhitelist or {}) do
|
||||||
|
if terminalID==TerminalID then
|
||||||
|
-- This is a valid spot.
|
||||||
return true
|
return true
|
||||||
else
|
|
||||||
self:T(string.format("%s, unit %s of group %s was NOT spawned on runway #%d. Distance %.1f > radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
|
|
||||||
--unit:FlareGreen()
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self:T(string.format("%s, checking if unit %s of group %s is on runway. Unit is NOT alive.",self:GetName(), unit:GetName(), group:GetName()))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
-- No match ==> invalid spot
|
||||||
self:T(string.format("%s, checking if group %s is on runway. Group is NOT alive.",self:GetName(), group:GetName()))
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
|
||||||
|
|
||||||
--- Get category of airbase.
|
|
||||||
-- @param #AIRBASE self
|
|
||||||
-- @return #number Category of airbase from GetDesc().category.
|
|
||||||
function AIRBASE:GetAirbaseCategory()
|
|
||||||
local desc=self:GetDesc()
|
|
||||||
local category=Airbase.Category.AIRDROME
|
|
||||||
|
|
||||||
if desc and desc.category then
|
|
||||||
category=desc.category
|
|
||||||
else
|
|
||||||
self:E(string.format("ERROR: Cannot get category of airbase %s due to DCS 2.5.6 bug! Assuming it is an AIRDROME for now...", tostring(self.AirbaseName)))
|
|
||||||
end
|
end
|
||||||
return category
|
|
||||||
end
|
|
||||||
|
|
||||||
|
-- Neither black nor white lists were defined or spot is not in black list.
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
--- Helper function to check for the correct terminal type including "artificial" ones.
|
--- Helper function to check for the correct terminal type including "artificial" ones.
|
||||||
-- @param #number Term_Type Termial type from getParking routine.
|
-- @param #number Term_Type Termial type from getParking routine.
|
||||||
@@ -1081,6 +1325,10 @@ function AIRBASE._CheckTerminalType(Term_Type, termtype)
|
|||||||
return match
|
return match
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Runway
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Get runways data. Only for airdromes!
|
--- Get runways data. Only for airdromes!
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @param #number magvar (Optional) Magnetic variation in degrees.
|
-- @param #number magvar (Optional) Magnetic variation in degrees.
|
||||||
@@ -1095,17 +1343,30 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get spawn points on runway.
|
-- 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.
|
||||||
|
if false then
|
||||||
|
for i,_coord in pairs(runwaycoords) do
|
||||||
|
local coord=_coord --Core.Point#COORDINATE
|
||||||
|
coord:Translate(100, 0):MarkToAll("Runway i="..i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Magnetic declination.
|
-- Magnetic declination.
|
||||||
magvar=magvar or UTILS.GetMagneticDeclination()
|
magvar=magvar or UTILS.GetMagneticDeclination()
|
||||||
|
|
||||||
|
-- Number of runways.
|
||||||
local N=#runwaycoords
|
local N=#runwaycoords
|
||||||
local dN=2
|
local N2=N/2
|
||||||
local ex=false
|
local exception=false
|
||||||
|
|
||||||
|
-- Airbase name.
|
||||||
local name=self:GetName()
|
local name=self:GetName()
|
||||||
|
|
||||||
|
|
||||||
|
-- Exceptions
|
||||||
if name==AIRBASE.Nevada.Jean_Airport or
|
if name==AIRBASE.Nevada.Jean_Airport or
|
||||||
name==AIRBASE.Nevada.Creech_AFB or
|
name==AIRBASE.Nevada.Creech_AFB or
|
||||||
name==AIRBASE.PersianGulf.Abu_Dhabi_International_Airport or
|
name==AIRBASE.PersianGulf.Abu_Dhabi_International_Airport or
|
||||||
@@ -1113,23 +1374,96 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
name==AIRBASE.PersianGulf.Shiraz_International_Airport or
|
name==AIRBASE.PersianGulf.Shiraz_International_Airport or
|
||||||
name==AIRBASE.PersianGulf.Kish_International_Airport then
|
name==AIRBASE.PersianGulf.Kish_International_Airport then
|
||||||
|
|
||||||
N=#runwaycoords/2
|
-- 1-->4, 2-->3, 3-->2, 4-->1
|
||||||
dN=1
|
exception=1
|
||||||
ex=true
|
|
||||||
|
elseif UTILS.GetDCSMap()==DCSMAP.Syria and N>=2 and
|
||||||
|
name~=AIRBASE.Syria.Minakh and
|
||||||
|
name~=AIRBASE.Syria.Damascus and
|
||||||
|
name~=AIRBASE.Syria.Khalkhalah and
|
||||||
|
name~=AIRBASE.Syria.Marj_Ruhayyil and
|
||||||
|
name~=AIRBASE.Syria.Beirut_Rafic_Hariri then
|
||||||
|
|
||||||
|
-- 1-->3, 2-->4, 3-->1, 4-->2
|
||||||
|
exception=2
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function returning the index of the runway coordinate belonding to the given index i.
|
||||||
|
local function f(i)
|
||||||
|
|
||||||
|
local j
|
||||||
|
|
||||||
|
if exception==1 then
|
||||||
|
|
||||||
|
j=N-(i-1) -- 1-->4, 2-->3
|
||||||
|
|
||||||
|
elseif exception==2 then
|
||||||
|
|
||||||
|
if i<=N2 then
|
||||||
|
j=i+N2 -- 1-->3, 2-->4
|
||||||
|
else
|
||||||
|
j=i-N2 -- 3-->1, 4-->3
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
if i%2==0 then
|
||||||
|
j=i-1 -- even 2-->1, 4-->3
|
||||||
|
else
|
||||||
|
j=i+1 -- odd 1-->2, 3-->4
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Special case where there is no obvious order.
|
||||||
|
if name==AIRBASE.Syria.Beirut_Rafic_Hariri then
|
||||||
|
if i==1 then
|
||||||
|
j=3
|
||||||
|
elseif i==2 then
|
||||||
|
j=6
|
||||||
|
elseif i==3 then
|
||||||
|
j=1
|
||||||
|
elseif i==4 then
|
||||||
|
j=5
|
||||||
|
elseif i==5 then
|
||||||
|
j=4
|
||||||
|
elseif i==6 then
|
||||||
|
j=2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if name==AIRBASE.Syria.Ramat_David then
|
||||||
|
if i==1 then
|
||||||
|
j=4
|
||||||
|
elseif i==2 then
|
||||||
|
j=6
|
||||||
|
elseif i==3 then
|
||||||
|
j=5
|
||||||
|
elseif i==4 then
|
||||||
|
j=1
|
||||||
|
elseif i==5 then
|
||||||
|
j=3
|
||||||
|
elseif i==6 then
|
||||||
|
j=2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return j
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
for i=1,N,dN do
|
for i=1,N do
|
||||||
|
|
||||||
local j=i+1
|
-- Get the other spawn point coordinate.
|
||||||
if ex then
|
local j=f(i)
|
||||||
--j=N+i
|
|
||||||
j=#runwaycoords-i+1
|
-- Debug info.
|
||||||
end
|
--env.info(string.format("Runway i=%s j=%s (N=%d #runwaycoord=%d)", tostring(i), tostring(j), N, #runwaycoords))
|
||||||
|
|
||||||
-- Coordinates of the two runway points.
|
-- Coordinates of the two runway points.
|
||||||
local c1=runwaycoords[i] --Core.Point#COORDINATES
|
local c1=runwaycoords[i] --Core.Point#COORDINATE
|
||||||
local c2=runwaycoords[j] --Core.Point#COORDINATES
|
local c2=runwaycoords[j] --Core.Point#COORDINATE
|
||||||
|
|
||||||
-- Heading of runway.
|
-- Heading of runway.
|
||||||
local hdg=c1:HeadingTo(c2)
|
local hdg=c1:HeadingTo(c2)
|
||||||
@@ -1146,11 +1480,11 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
runway.endpoint=c2
|
runway.endpoint=c2
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m", self:GetName(), runway.idx, runway.heading, runway.length))
|
--self:I(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m i=%d j=%d", self:GetName(), runway.idx, runway.heading, runway.length, i, j))
|
||||||
|
|
||||||
-- Debug mark
|
-- Debug mark
|
||||||
if mark then
|
if mark then
|
||||||
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d (magvar=%d), length=%d m", runway.idx, runway.heading, magvar, runway.length))
|
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d (magvar=%d), length=%d m, i=%d, j=%d", runway.idx, runway.heading, magvar, runway.length, i, j))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add runway.
|
-- Add runway.
|
||||||
@@ -1158,38 +1492,6 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get inverse runways
|
|
||||||
local inverse={}
|
|
||||||
for _,_runway in pairs(runways) do
|
|
||||||
local r=_runway --#AIRBASE.Runway
|
|
||||||
|
|
||||||
local runway={} --#AIRBASE.Runway
|
|
||||||
runway.heading=r.heading-180
|
|
||||||
if runway.heading<0 then
|
|
||||||
runway.heading=runway.heading+360
|
|
||||||
end
|
|
||||||
runway.idx=string.format("%02d", math.max(0, UTILS.Round((runway.heading-magvar)/10, 0)))
|
|
||||||
runway.length=r.length
|
|
||||||
runway.position=r.endpoint
|
|
||||||
runway.endpoint=r.position
|
|
||||||
|
|
||||||
-- Debug info.
|
|
||||||
self:T(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m", self:GetName(), runway.idx, runway.heading, runway.length))
|
|
||||||
|
|
||||||
-- Debug mark
|
|
||||||
if mark then
|
|
||||||
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d (magvar=%d), length=%d m", runway.idx, runway.heading, magvar, runway.length))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add runway.
|
|
||||||
table.insert(inverse, runway)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add inverse runway.
|
|
||||||
for _,runway in pairs(inverse) do
|
|
||||||
table.insert(runways, runway)
|
|
||||||
end
|
|
||||||
|
|
||||||
return runways
|
return runways
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1260,5 +1562,72 @@ function AIRBASE:GetActiveRunway(magvar)
|
|||||||
return runways[iact]
|
return runways[iact]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function that checks if at leat one unit of a group has been spawned close to a spawn point on the runway.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param Wrapper.Group#GROUP group Group to be checked.
|
||||||
|
-- @param #number radius Radius around the spawn point to be checked. Default is 50 m.
|
||||||
|
-- @param #boolean despawn If true, the group is destroyed.
|
||||||
|
-- @return #boolean True if group is within radius around spawn points on runway.
|
||||||
|
function AIRBASE:CheckOnRunWay(group, radius, despawn)
|
||||||
|
|
||||||
|
-- Default radius.
|
||||||
|
radius=radius or 50
|
||||||
|
|
||||||
|
-- We only check at real airbases (not FARPS or ships).
|
||||||
|
if self:GetAirbaseCategory()~=Airbase.Category.AIRDROME then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if group and group:IsAlive() then
|
||||||
|
|
||||||
|
-- Debug.
|
||||||
|
self:T(string.format("%s, checking if group %s is on runway?",self:GetName(), group:GetName()))
|
||||||
|
|
||||||
|
-- Get coordinates on runway.
|
||||||
|
local runwaypoints=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
|
||||||
|
|
||||||
|
-- Get units of group.
|
||||||
|
local units=group:GetUnits()
|
||||||
|
|
||||||
|
-- Loop over units.
|
||||||
|
for _,_unit in pairs(units) do
|
||||||
|
|
||||||
|
local unit=_unit --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
-- Check if unit is alive and not in air.
|
||||||
|
if unit and unit:IsAlive() and not unit:InAir() then
|
||||||
|
self:T(string.format("%s, checking if unit %s is on runway?",self:GetName(), unit:GetName()))
|
||||||
|
|
||||||
|
-- Loop over runway spawn points.
|
||||||
|
for _i,_coord in pairs(runwaypoints) do
|
||||||
|
|
||||||
|
-- Distance between unit and spawn pos.
|
||||||
|
local dist=unit:GetCoordinate():Get2DDistance(_coord)
|
||||||
|
|
||||||
|
-- Mark unit spawn points for debugging.
|
||||||
|
--unit:GetCoordinate():MarkToAll(string.format("unit %s distance to rwy %d = %d",unit:GetName(),_i, dist))
|
||||||
|
|
||||||
|
-- Check if unit is withing radius.
|
||||||
|
if dist<radius then
|
||||||
|
self:E(string.format("%s, unit %s of group %s was spawned on runway #%d. Distance %.1f < radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
|
||||||
|
--unit:FlareRed()
|
||||||
|
if despawn then
|
||||||
|
group:Destroy(true)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
self:T(string.format("%s, unit %s of group %s was NOT spawned on runway #%d. Distance %.1f > radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
|
||||||
|
--unit:FlareGreen()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:T(string.format("%s, checking if unit %s of group %s is on runway. Unit is NOT alive.",self:GetName(), unit:GetName(), group:GetName()))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:T(string.format("%s, checking if group %s is on runway. Group is NOT alive.",self:GetName(), group:GetName()))
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
--
|
-- ### Contributions: **funkyfranky**
|
||||||
-- ### Contributions:
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -52,13 +51,6 @@
|
|||||||
--
|
--
|
||||||
-- @field #CLIENT
|
-- @field #CLIENT
|
||||||
CLIENT = {
|
CLIENT = {
|
||||||
ONBOARDSIDE = {
|
|
||||||
NONE = 0,
|
|
||||||
LEFT = 1,
|
|
||||||
RIGHT = 2,
|
|
||||||
BACK = 3,
|
|
||||||
FRONT = 4
|
|
||||||
},
|
|
||||||
ClassName = "CLIENT",
|
ClassName = "CLIENT",
|
||||||
ClientName = nil,
|
ClientName = nil,
|
||||||
ClientAlive = false,
|
ClientAlive = false,
|
||||||
@@ -66,27 +58,20 @@ CLIENT = {
|
|||||||
ClientBriefingShown = false,
|
ClientBriefingShown = false,
|
||||||
_Menus = {},
|
_Menus = {},
|
||||||
_Tasks = {},
|
_Tasks = {},
|
||||||
Messages = {
|
Messages = {},
|
||||||
}
|
Players = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--- Finds a CLIENT from the _DATABASE using the relevant DCS Unit.
|
--- Finds a CLIENT from the _DATABASE using the relevant DCS Unit.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor.
|
-- @param DCS#Unit DCSUnit The DCS unit of the client.
|
||||||
-- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client.
|
-- @param #boolean Error Throw an error message.
|
||||||
-- @return #CLIENT
|
-- @return #CLIENT The CLIENT found in the _DATABASE.
|
||||||
-- @usage
|
function CLIENT:Find(DCSUnit, Error)
|
||||||
-- -- Create new Clients.
|
|
||||||
-- local Mission = MISSIONSCHEDULER.AddMission( 'Russia Transport Troops SA-6', 'Operational', 'Transport troops from the control center to one of the SA-6 SAM sites to activate their operation.', 'Russia' )
|
|
||||||
-- Mission:AddGoal( DeploySA6TroopsGoal )
|
|
||||||
--
|
|
||||||
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 1' ):Transport() )
|
|
||||||
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() )
|
|
||||||
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() )
|
|
||||||
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() )
|
|
||||||
function CLIENT:Find( DCSUnit, Error )
|
|
||||||
local ClientName = DCSUnit:getName()
|
local ClientName = DCSUnit:getName()
|
||||||
|
|
||||||
local ClientFound = _DATABASE:FindClient( ClientName )
|
local ClientFound = _DATABASE:FindClient( ClientName )
|
||||||
|
|
||||||
if ClientFound then
|
if ClientFound then
|
||||||
@@ -117,11 +102,15 @@ end
|
|||||||
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() )
|
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() )
|
||||||
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() )
|
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() )
|
||||||
function CLIENT:FindByName( ClientName, ClientBriefing, Error )
|
function CLIENT:FindByName( ClientName, ClientBriefing, Error )
|
||||||
|
|
||||||
|
-- Client
|
||||||
local ClientFound = _DATABASE:FindClient( ClientName )
|
local ClientFound = _DATABASE:FindClient( ClientName )
|
||||||
|
|
||||||
if ClientFound then
|
if ClientFound then
|
||||||
ClientFound:F( { ClientName, ClientBriefing } )
|
ClientFound:F( { ClientName, ClientBriefing } )
|
||||||
ClientFound:AddBriefing( ClientBriefing )
|
|
||||||
|
ClientFound:AddBriefing(ClientBriefing)
|
||||||
|
|
||||||
ClientFound.MessageSwitch = true
|
ClientFound.MessageSwitch = true
|
||||||
|
|
||||||
return ClientFound
|
return ClientFound
|
||||||
@@ -132,51 +121,105 @@ function CLIENT:FindByName( ClientName, ClientBriefing, Error )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function CLIENT:Register( ClientName )
|
--- Transport defines that the Client is a Transport. Transports show cargo.
|
||||||
|
-- @param #CLIENT self
|
||||||
|
-- @param #string ClientName Name of the client unit.
|
||||||
|
-- @return #CLIENT self
|
||||||
|
function CLIENT:Register(ClientName)
|
||||||
|
|
||||||
local self = BASE:Inherit( self, UNIT:Register( ClientName ) ) -- #CLIENT
|
-- Inherit unit.
|
||||||
|
local self = BASE:Inherit( self, UNIT:Register(ClientName )) -- #CLIENT
|
||||||
|
|
||||||
self:F( ClientName )
|
-- Set client name.
|
||||||
self.ClientName = ClientName
|
self.ClientName = ClientName
|
||||||
|
|
||||||
|
-- Message switch.
|
||||||
self.MessageSwitch = true
|
self.MessageSwitch = true
|
||||||
|
|
||||||
|
-- Alive2.
|
||||||
self.ClientAlive2 = false
|
self.ClientAlive2 = false
|
||||||
|
|
||||||
--self.AliveCheckScheduler = routines.scheduleFunction( self._AliveCheckScheduler, { self }, timer.getTime() + 1, 5 )
|
|
||||||
self.AliveCheckScheduler = SCHEDULER:New( self, self._AliveCheckScheduler, { "Client Alive " .. ClientName }, 1, 5, 0.5 )
|
|
||||||
self.AliveCheckScheduler:NoTrace()
|
|
||||||
|
|
||||||
self:F( self )
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Transport defines that the Client is a Transport. Transports show cargo.
|
--- Transport defines that the Client is a Transport. Transports show cargo.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @return #CLIENT
|
-- @return #CLIENT self
|
||||||
function CLIENT:Transport()
|
function CLIENT:Transport()
|
||||||
self:F()
|
|
||||||
|
|
||||||
self.ClientTransport = true
|
self.ClientTransport = true
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- AddBriefing adds a briefing to a CLIENT when a player joins a mission.
|
--- Adds a briefing to a CLIENT when a player joins a mission.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @param #string ClientBriefing is the text defining the Mission briefing.
|
-- @param #string ClientBriefing is the text defining the Mission briefing.
|
||||||
-- @return #CLIENT self
|
-- @return #CLIENT self
|
||||||
function CLIENT:AddBriefing( ClientBriefing )
|
function CLIENT:AddBriefing( ClientBriefing )
|
||||||
self:F( ClientBriefing )
|
|
||||||
self.ClientBriefing = ClientBriefing
|
self.ClientBriefing = ClientBriefing
|
||||||
self.ClientBriefingShown = false
|
self.ClientBriefingShown = false
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add player name.
|
||||||
|
-- @param #CLIENT self
|
||||||
|
-- @param #string PlayerName Name of the player.
|
||||||
|
-- @return #CLIENT self
|
||||||
|
function CLIENT:AddPlayer(PlayerName)
|
||||||
|
|
||||||
|
table.insert(self.Players, PlayerName)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get player name(s).
|
||||||
|
-- @param #CLIENT self
|
||||||
|
-- @return #table List of player names or an empty table `{}`.
|
||||||
|
function CLIENT:GetPlayers()
|
||||||
|
return self.Players
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get name of player.
|
||||||
|
-- @param #CLIENT self
|
||||||
|
-- @return #string Player name or `nil`.
|
||||||
|
function CLIENT:GetPlayer()
|
||||||
|
if #self.Players>0 then
|
||||||
|
return self.Players[1]
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove player.
|
||||||
|
-- @param #CLIENT self
|
||||||
|
-- @param #string PlayerName Name of the player.
|
||||||
|
-- @return #CLIENT self
|
||||||
|
function CLIENT:RemovePlayer(PlayerName)
|
||||||
|
|
||||||
|
for i,playername in pairs(self.Players) do
|
||||||
|
if PlayerName==playername then
|
||||||
|
table.remove(self.Players, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove all players.
|
||||||
|
-- @param #CLIENT self
|
||||||
|
-- @return #CLIENT self
|
||||||
|
function CLIENT:RemovePlayers()
|
||||||
|
self.Players={}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Show the briefing of a CLIENT.
|
--- Show the briefing of a CLIENT.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @return #CLIENT self
|
-- @return #CLIENT self
|
||||||
function CLIENT:ShowBriefing()
|
function CLIENT:ShowBriefing()
|
||||||
self:F( { self.ClientName, self.ClientBriefingShown } )
|
|
||||||
|
|
||||||
if not self.ClientBriefingShown then
|
if not self.ClientBriefingShown then
|
||||||
self.ClientBriefingShown = true
|
self.ClientBriefingShown = true
|
||||||
@@ -204,8 +247,6 @@ function CLIENT:ShowMissionBriefing( MissionBriefing )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Resets a CLIENT.
|
--- Resets a CLIENT.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @param #string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client.
|
-- @param #string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client.
|
||||||
@@ -241,6 +282,7 @@ end
|
|||||||
--- Checks for a client alive event and calls a function on a continuous basis.
|
--- Checks for a client alive event and calls a function on a continuous basis.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @param #function CallBackFunction Create a function that will be called when a player joins the slot.
|
-- @param #function CallBackFunction Create a function that will be called when a player joins the slot.
|
||||||
|
-- @param ... (Optional) Arguments for callback function as comma separated list.
|
||||||
-- @return #CLIENT
|
-- @return #CLIENT
|
||||||
function CLIENT:Alive( CallBackFunction, ... )
|
function CLIENT:Alive( CallBackFunction, ... )
|
||||||
self:F()
|
self:F()
|
||||||
@@ -248,6 +290,9 @@ function CLIENT:Alive( CallBackFunction, ... )
|
|||||||
self.ClientCallBack = CallBackFunction
|
self.ClientCallBack = CallBackFunction
|
||||||
self.ClientParameters = arg
|
self.ClientParameters = arg
|
||||||
|
|
||||||
|
self.AliveCheckScheduler = SCHEDULER:New( self, self._AliveCheckScheduler, { "Client Alive " .. self.ClientName }, 0.1, 5, 0.5 )
|
||||||
|
self.AliveCheckScheduler:NoTrace()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -256,18 +301,28 @@ function CLIENT:_AliveCheckScheduler( SchedulerName )
|
|||||||
self:F3( { SchedulerName, self.ClientName, self.ClientAlive2, self.ClientBriefingShown, self.ClientCallBack } )
|
self:F3( { SchedulerName, self.ClientName, self.ClientAlive2, self.ClientBriefingShown, self.ClientCallBack } )
|
||||||
|
|
||||||
if self:IsAlive() then
|
if self:IsAlive() then
|
||||||
|
|
||||||
if self.ClientAlive2 == false then
|
if self.ClientAlive2 == false then
|
||||||
|
|
||||||
|
-- Show briefing.
|
||||||
self:ShowBriefing()
|
self:ShowBriefing()
|
||||||
|
|
||||||
|
-- Callback function.
|
||||||
if self.ClientCallBack then
|
if self.ClientCallBack then
|
||||||
self:T("Calling Callback function")
|
self:T("Calling Callback function")
|
||||||
self.ClientCallBack( self, unpack( self.ClientParameters ) )
|
self.ClientCallBack( self, unpack( self.ClientParameters ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Alive.
|
||||||
self.ClientAlive2 = true
|
self.ClientAlive2 = true
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if self.ClientAlive2 == true then
|
if self.ClientAlive2 == true then
|
||||||
self.ClientAlive2 = false
|
self.ClientAlive2 = false
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -291,6 +346,7 @@ function CLIENT:GetDCSGroup()
|
|||||||
local ClientUnit = Unit.getByName( self.ClientName )
|
local ClientUnit = Unit.getByName( self.ClientName )
|
||||||
|
|
||||||
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
|
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
|
||||||
|
|
||||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||||
self:T3( { "CoalitionData:", CoalitionData } )
|
self:T3( { "CoalitionData:", CoalitionData } )
|
||||||
for UnitId, UnitData in pairs( CoalitionData ) do
|
for UnitId, UnitData in pairs( CoalitionData ) do
|
||||||
@@ -299,10 +355,14 @@ function CLIENT:GetDCSGroup()
|
|||||||
|
|
||||||
--self:F(self.ClientName)
|
--self:F(self.ClientName)
|
||||||
if ClientUnit then
|
if ClientUnit then
|
||||||
|
|
||||||
local ClientGroup = ClientUnit:getGroup()
|
local ClientGroup = ClientUnit:getGroup()
|
||||||
|
|
||||||
if ClientGroup then
|
if ClientGroup then
|
||||||
self:T3( "ClientGroup = " .. self.ClientName )
|
self:T3( "ClientGroup = " .. self.ClientName )
|
||||||
|
|
||||||
if ClientGroup:isExist() and UnitData:getGroup():isExist() then
|
if ClientGroup:isExist() and UnitData:getGroup():isExist() then
|
||||||
|
|
||||||
if ClientGroup:getID() == UnitData:getGroup():getID() then
|
if ClientGroup:getID() == UnitData:getGroup():getID() then
|
||||||
self:T3( "Normal logic" )
|
self:T3( "Normal logic" )
|
||||||
self:T3( self.ClientName .. " : group found!" )
|
self:T3( self.ClientName .. " : group found!" )
|
||||||
@@ -310,15 +370,22 @@ function CLIENT:GetDCSGroup()
|
|||||||
self.ClientGroupName = ClientGroup:getName()
|
self.ClientGroupName = ClientGroup:getName()
|
||||||
return ClientGroup
|
return ClientGroup
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Now we need to resolve the bugs in DCS 1.5 ...
|
-- Now we need to resolve the bugs in DCS 1.5 ...
|
||||||
-- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil)
|
-- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil)
|
||||||
self:T3( "Bug 1.5 logic" )
|
self:T3( "Bug 1.5 logic" )
|
||||||
|
|
||||||
local ClientGroupTemplate = _DATABASE.Templates.Units[self.ClientName].GroupTemplate
|
local ClientGroupTemplate = _DATABASE.Templates.Units[self.ClientName].GroupTemplate
|
||||||
|
|
||||||
self.ClientGroupID = ClientGroupTemplate.groupId
|
self.ClientGroupID = ClientGroupTemplate.groupId
|
||||||
|
|
||||||
self.ClientGroupName = _DATABASE.Templates.Units[self.ClientName].GroupName
|
self.ClientGroupName = _DATABASE.Templates.Units[self.ClientName].GroupName
|
||||||
|
|
||||||
self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" )
|
self:T3( self.ClientName .. " : group found in bug 1.5 resolvement logic!" )
|
||||||
return ClientGroup
|
return ClientGroup
|
||||||
|
|
||||||
end
|
end
|
||||||
-- else
|
-- else
|
||||||
-- error( "Client " .. self.ClientName .. " not found!" )
|
-- error( "Client " .. self.ClientName .. " not found!" )
|
||||||
@@ -343,22 +410,22 @@ function CLIENT:GetDCSGroup()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Nothing could be found :(
|
||||||
self.ClientGroupID = nil
|
self.ClientGroupID = nil
|
||||||
self.ClientGroupUnit = nil
|
self.ClientGroupName = nil
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- TODO: Check DCS#Group.ID
|
|
||||||
--- Get the group ID of the client.
|
--- Get the group ID of the client.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @return DCS#Group.ID
|
-- @return #number DCS#Group ID.
|
||||||
function CLIENT:GetClientGroupID()
|
function CLIENT:GetClientGroupID()
|
||||||
|
|
||||||
local ClientGroup = self:GetDCSGroup()
|
-- This updates the ID.
|
||||||
|
self:GetDCSGroup()
|
||||||
|
|
||||||
--self:F( self.ClientGroupID ) -- Determined in GetDCSGroup()
|
|
||||||
return self.ClientGroupID
|
return self.ClientGroupID
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -368,26 +435,28 @@ end
|
|||||||
-- @return #string
|
-- @return #string
|
||||||
function CLIENT:GetClientGroupName()
|
function CLIENT:GetClientGroupName()
|
||||||
|
|
||||||
local ClientGroup = self:GetDCSGroup()
|
-- This updates the group name.
|
||||||
|
self:GetDCSGroup()
|
||||||
|
|
||||||
self:T( self.ClientGroupName ) -- Determined in GetDCSGroup()
|
|
||||||
return self.ClientGroupName
|
return self.ClientGroupName
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the UNIT of the CLIENT.
|
--- Returns the UNIT of the CLIENT.
|
||||||
-- @param #CLIENT self
|
-- @param #CLIENT self
|
||||||
-- @return Wrapper.Unit#UNIT
|
-- @return Wrapper.Unit#UNIT The client UNIT or `nil`.
|
||||||
function CLIENT:GetClientGroupUnit()
|
function CLIENT:GetClientGroupUnit()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
local ClientDCSUnit = Unit.getByName( self.ClientName )
|
local ClientDCSUnit = Unit.getByName( self.ClientName )
|
||||||
|
|
||||||
self:T( self.ClientDCSUnit )
|
self:T( self.ClientDCSUnit )
|
||||||
|
|
||||||
if ClientDCSUnit and ClientDCSUnit:isExist() then
|
if ClientDCSUnit and ClientDCSUnit:isExist() then
|
||||||
local ClientUnit = _DATABASE:FindUnit( self.ClientName )
|
local ClientUnit=_DATABASE:FindUnit( self.ClientName )
|
||||||
self:T2( ClientUnit )
|
|
||||||
return ClientUnit
|
return ClientUnit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the DCSUnit of the CLIENT.
|
--- Returns the DCSUnit of the CLIENT.
|
||||||
|
|||||||
@@ -129,6 +129,7 @@
|
|||||||
-- * @{#CONTROLLABLE.Route}(): Make the Controllable to follow a given route.
|
-- * @{#CONTROLLABLE.Route}(): Make the Controllable to follow a given route.
|
||||||
-- * @{#CONTROLLABLE.RouteGroundTo}(): Make the GROUND Controllable to drive towards a specific coordinate.
|
-- * @{#CONTROLLABLE.RouteGroundTo}(): Make the GROUND Controllable to drive towards a specific coordinate.
|
||||||
-- * @{#CONTROLLABLE.RouteAirTo}(): Make the AIR Controllable to fly towards a specific coordinate.
|
-- * @{#CONTROLLABLE.RouteAirTo}(): Make the AIR Controllable to fly towards a specific coordinate.
|
||||||
|
-- * @{#CONTROLLABLE.RelocateGroundRandomInRadius}(): Relocate the GROUND controllable to a random point in a given radius.
|
||||||
--
|
--
|
||||||
-- # 5) Option methods
|
-- # 5) Option methods
|
||||||
--
|
--
|
||||||
@@ -173,6 +174,12 @@
|
|||||||
-- * @{#CONTROLLABLE.OptionAllowJettisonWeaponsOnThreat}
|
-- * @{#CONTROLLABLE.OptionAllowJettisonWeaponsOnThreat}
|
||||||
-- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat}
|
-- * @{#CONTROLLABLE.OptionKeepWeaponsOnThreat}
|
||||||
--
|
--
|
||||||
|
-- ## 5.5) Air-2-Air missile attack range:
|
||||||
|
-- * @{#CONTROLLABLE.OptionAAAttackRange}(): Defines the usage of A2A missiles against possible targets.
|
||||||
|
--
|
||||||
|
-- ## 5.6) GROUND units attack range:
|
||||||
|
-- * @{#CONTROLLABLE.OptionEngageRange}(): Engage range limit in percent (a number between 0 and 100). Default 100. Defines the range at which a GROUND unit/group (e.g. a SAM site) is allowed to use its weapons automatically.
|
||||||
|
--
|
||||||
-- @field #CONTROLLABLE
|
-- @field #CONTROLLABLE
|
||||||
CONTROLLABLE = {
|
CONTROLLABLE = {
|
||||||
ClassName = "CONTROLLABLE",
|
ClassName = "CONTROLLABLE",
|
||||||
@@ -243,8 +250,7 @@ end
|
|||||||
|
|
||||||
--- Returns the initial health.
|
--- Returns the initial health.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #number The controllable health value (unit or group average).
|
-- @return #number The controllable health value (unit or group average) or `nil` if the controllable does not exist.
|
||||||
-- @return #nil The controllable is not existing or alive.
|
|
||||||
function CONTROLLABLE:GetLife0()
|
function CONTROLLABLE:GetLife0()
|
||||||
self:F2( self.ControllableName )
|
self:F2( self.ControllableName )
|
||||||
|
|
||||||
@@ -296,7 +302,6 @@ end
|
|||||||
-- @return #nil The CONTROLLABLE is not existing or alive.
|
-- @return #nil The CONTROLLABLE is not existing or alive.
|
||||||
function CONTROLLABLE:GetFuel()
|
function CONTROLLABLE:GetFuel()
|
||||||
self:F( self.ControllableName )
|
self:F( self.ControllableName )
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -803,7 +808,7 @@ function CONTROLLABLE:CommandSetFrequency(Frequency, Modulation, Delay)
|
|||||||
local CommandSetFrequency = {
|
local CommandSetFrequency = {
|
||||||
id = 'SetFrequency',
|
id = 'SetFrequency',
|
||||||
params = {
|
params = {
|
||||||
frequency = Frequency,
|
frequency = Frequency*1000000,
|
||||||
modulation = Modulation or radio.modulation.AM,
|
modulation = Modulation or radio.modulation.AM,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1426,26 +1431,22 @@ end
|
|||||||
-- @param DCS#Distance Radius The radius of the zone to deploy the fire at.
|
-- @param DCS#Distance Radius The radius of the zone to deploy the fire at.
|
||||||
-- @param #number AmmoCount (optional) Quantity of ammunition to expand (omit to fire until ammunition is depleted).
|
-- @param #number AmmoCount (optional) Quantity of ammunition to expand (omit to fire until ammunition is depleted).
|
||||||
-- @param #number WeaponType (optional) Enum for weapon type ID. This value is only required if you want the group firing to use a specific weapon, for instance using the task on a ship to force it to fire guided missiles at targets within cannon range. See http://wiki.hoggit.us/view/DCS_enum_weapon_flag
|
-- @param #number WeaponType (optional) Enum for weapon type ID. This value is only required if you want the group firing to use a specific weapon, for instance using the task on a ship to force it to fire guided missiles at targets within cannon range. See http://wiki.hoggit.us/view/DCS_enum_weapon_flag
|
||||||
|
-- @param #number Altitude (Optional) Altitude in meters.
|
||||||
|
-- @param #number ASL Altitude is above mean sea level. Default is above ground level.
|
||||||
-- @return DCS#Task The DCS task structure.
|
-- @return DCS#Task The DCS task structure.
|
||||||
function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType )
|
function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType, Altitude, ASL )
|
||||||
|
|
||||||
-- FireAtPoint = {
|
|
||||||
-- id = 'FireAtPoint',
|
|
||||||
-- params = {
|
|
||||||
-- point = Vec2,
|
|
||||||
-- radius = Distance,
|
|
||||||
-- expendQty = number,
|
|
||||||
-- expendQtyEnabled = boolean,
|
|
||||||
-- }
|
|
||||||
-- }
|
|
||||||
|
|
||||||
local DCSTask = {
|
local DCSTask = {
|
||||||
id = 'FireAtPoint',
|
id = 'FireAtPoint',
|
||||||
params = {
|
params = {
|
||||||
point = Vec2,
|
point = Vec2,
|
||||||
|
x=Vec2.x,
|
||||||
|
y=Vec2.y,
|
||||||
zoneRadius = Radius,
|
zoneRadius = Radius,
|
||||||
|
radius = Radius,
|
||||||
expendQty = 100, -- dummy value
|
expendQty = 100, -- dummy value
|
||||||
expendQtyEnabled = false,
|
expendQtyEnabled = false,
|
||||||
|
alt_type = ASL and 0 or 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1454,11 +1455,16 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType )
|
|||||||
DCSTask.params.expendQtyEnabled = true
|
DCSTask.params.expendQtyEnabled = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Altitude then
|
||||||
|
DCSTask.params.altitude=Altitude
|
||||||
|
end
|
||||||
|
|
||||||
if WeaponType then
|
if WeaponType then
|
||||||
DCSTask.params.weaponType=WeaponType
|
DCSTask.params.weaponType=WeaponType
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T3( { DCSTask } )
|
self:I(DCSTask)
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1481,8 +1487,8 @@ end
|
|||||||
-- @param #number WeaponType Bitmask of weapon types, which are allowed to use.
|
-- @param #number WeaponType Bitmask of weapon types, which are allowed to use.
|
||||||
-- @param DCS#AI.Task.Designation Designation (Optional) Designation type.
|
-- @param DCS#AI.Task.Designation Designation (Optional) Designation type.
|
||||||
-- @param #boolean Datalink (Optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default.
|
-- @param #boolean Datalink (Optional) Allows to use datalink to send the target information to attack aircraft. Enabled by default.
|
||||||
-- @param #number Frequency Frequency used to communicate with the FAC.
|
-- @param #number Frequency Frequency in MHz used to communicate with the FAC. Default 133 MHz.
|
||||||
-- @param #number Modulation Modulation of radio for communication.
|
-- @param #number Modulation Modulation of radio for communication. Default 0=AM.
|
||||||
-- @param #number CallsignName Callsign enumerator name of the FAC.
|
-- @param #number CallsignName Callsign enumerator name of the FAC.
|
||||||
-- @param #number CallsignNumber Callsign number, e.g. Axeman-**1**.
|
-- @param #number CallsignNumber Callsign number, e.g. Axeman-**1**.
|
||||||
-- @return DCS#Task The DCS task structure.
|
-- @return DCS#Task The DCS task structure.
|
||||||
@@ -1492,11 +1498,11 @@ function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation,
|
|||||||
id = 'FAC_AttackGroup',
|
id = 'FAC_AttackGroup',
|
||||||
params = {
|
params = {
|
||||||
groupId = AttackGroup:GetID(),
|
groupId = AttackGroup:GetID(),
|
||||||
weaponType = WeaponType,
|
weaponType = WeaponType or ENUMS.WeaponFlag.AutoDCS,
|
||||||
designation = Designation,
|
designation = Designation or "Auto",
|
||||||
datalink = Datalink,
|
datalink = Datalink and Datalink or true,
|
||||||
frequency = Frequency,
|
frequency = (Frequency or 133)*1000000,
|
||||||
modulation = Modulation,
|
modulation = Modulation or radio.modulation.AM,
|
||||||
callname = CallsignName,
|
callname = CallsignName,
|
||||||
number = CallsignNumber,
|
number = CallsignNumber,
|
||||||
}
|
}
|
||||||
@@ -1903,7 +1909,7 @@ do -- Patrol methods
|
|||||||
local ToCoord = COORDINATE:NewFromVec2( { x = Waypoint.x, y = Waypoint.y } )
|
local ToCoord = COORDINATE:NewFromVec2( { x = Waypoint.x, y = Waypoint.y } )
|
||||||
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
|
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
|
||||||
local Route = {}
|
local Route = {}
|
||||||
Route[#Route+1] = FromCoord:WaypointGround( 0 )
|
Route[#Route+1] = FromCoord:WaypointGround( Speed, Formation )
|
||||||
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )
|
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )
|
||||||
|
|
||||||
|
|
||||||
@@ -1956,7 +1962,7 @@ do -- Patrol methods
|
|||||||
|
|
||||||
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
|
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
|
||||||
local Route = {}
|
local Route = {}
|
||||||
Route[#Route+1] = FromCoord:WaypointGround( 20 )
|
Route[#Route+1] = FromCoord:WaypointGround( Speed, Formation )
|
||||||
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )
|
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )
|
||||||
|
|
||||||
|
|
||||||
@@ -2841,7 +2847,7 @@ function CONTROLLABLE:GetDetectedUnitSet(DetectVisual, DetectOptical, DetectRada
|
|||||||
return unitset
|
return unitset
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return the detected target groups of the controllable as a @{SET_GROUP}.
|
--- Return the detected target groups of the controllable as a @{Core.Set#SET_GROUP}.
|
||||||
-- The optional parametes specify the detection methods that can be applied.
|
-- The optional parametes specify the detection methods that can be applied.
|
||||||
-- If no detection method is given, the detection will use all the available methods by default.
|
-- If no detection method is given, the detection will use all the available methods by default.
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE self
|
-- @param Wrapper.Controllable#CONTROLLABLE self
|
||||||
@@ -2904,7 +2910,7 @@ end
|
|||||||
--- Set option for Rules of Engagement (ROE).
|
--- Set option for Rules of Engagement (ROE).
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE self
|
-- @param Wrapper.Controllable#CONTROLLABLE self
|
||||||
-- @param #number ROEvalue ROE value. See ENUMS.ROE.
|
-- @param #number ROEvalue ROE value. See ENUMS.ROE.
|
||||||
-- @return Wrapper.Controllable#CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:OptionROE(ROEvalue)
|
function CONTROLLABLE:OptionROE(ROEvalue)
|
||||||
|
|
||||||
local DCSControllable = self:GetDCSObject()
|
local DCSControllable = self:GetDCSObject()
|
||||||
@@ -2946,8 +2952,8 @@ function CONTROLLABLE:OptionROEHoldFirePossible()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Weapons Hold: AI will hold fire under all circumstances.
|
--- Weapons Hold: AI will hold fire under all circumstances.
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return Wrapper.Controllable#CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:OptionROEHoldFire()
|
function CONTROLLABLE:OptionROEHoldFire()
|
||||||
self:F2( { self.ControllableName } )
|
self:F2( { self.ControllableName } )
|
||||||
|
|
||||||
@@ -3545,7 +3551,7 @@ end
|
|||||||
-- Note that when WayPointInitialize is called, the Mission of the controllable is RESTARTED!
|
-- Note that when WayPointInitialize is called, the Mission of the controllable is RESTARTED!
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #table WayPoints If WayPoints is given, then use the route.
|
-- @param #table WayPoints If WayPoints is given, then use the route.
|
||||||
-- @return #CONTROLLABLE
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:WayPointInitialize( WayPoints )
|
function CONTROLLABLE:WayPointInitialize( WayPoints )
|
||||||
self:F( { WayPoints } )
|
self:F( { WayPoints } )
|
||||||
|
|
||||||
@@ -3576,7 +3582,7 @@ end
|
|||||||
-- @param #number WayPoint The waypoint number. Note that the start waypoint on the route is WayPoint 1!
|
-- @param #number WayPoint The waypoint number. Note that the start waypoint on the route is WayPoint 1!
|
||||||
-- @param #number WayPointIndex When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions.
|
-- @param #number WayPointIndex When defining multiple WayPoint functions for one WayPoint, use WayPointIndex to set the sequence of actions.
|
||||||
-- @param #function WayPointFunction The waypoint function to be called when the controllable moves over the waypoint. The waypoint function takes variable parameters.
|
-- @param #function WayPointFunction The waypoint function to be called when the controllable moves over the waypoint. The waypoint function takes variable parameters.
|
||||||
-- @return #CONTROLLABLE
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... )
|
function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunction, ... )
|
||||||
self:F2( { WayPoint, WayPointIndex, WayPointFunction } )
|
self:F2( { WayPoint, WayPointIndex, WayPointFunction } )
|
||||||
|
|
||||||
@@ -3592,7 +3598,7 @@ end
|
|||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number WayPoint The WayPoint from where to execute the mission.
|
-- @param #number WayPoint The WayPoint from where to execute the mission.
|
||||||
-- @param #number WaitTime The amount seconds to wait before initiating the mission.
|
-- @param #number WaitTime The amount seconds to wait before initiating the mission.
|
||||||
-- @return #CONTROLLABLE
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:WayPointExecute( WayPoint, WaitTime )
|
function CONTROLLABLE:WayPointExecute( WayPoint, WaitTime )
|
||||||
self:F( { WayPoint, WaitTime } )
|
self:F( { WayPoint, WaitTime } )
|
||||||
|
|
||||||
@@ -3672,3 +3678,104 @@ function CONTROLLABLE:OptionRestrictBurner(RestrictBurner)
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sets Controllable Option for A2A attack range for AIR FIGHTER units.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number range Defines the range
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
-- @usage Range can be one of MAX_RANGE = 0, NEZ_RANGE = 1, HALF_WAY_RMAX_NEZ = 2, TARGET_THREAT_EST = 3, RANDOM_RANGE = 4. Defaults to 3. See: https://wiki.hoggitworld.com/view/DCS_option_missileAttack
|
||||||
|
function CONTROLLABLE:OptionAAAttackRange(range)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
-- defaults to 3
|
||||||
|
local range = range or 3
|
||||||
|
if range < 0 or range > 4 then
|
||||||
|
range = 3
|
||||||
|
end
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local Controller = self:_GetController()
|
||||||
|
if Controller then
|
||||||
|
if self:IsAir() then
|
||||||
|
self:SetOption(AI.Option.Air.val.MISSILE_ATTACK, range)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Defines the range at which a GROUND unit/group is allowed to use its weapons automatically.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number EngageRange Engage range limit in percent (a number between 0 and 100). Default 100.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:OptionEngageRange(EngageRange)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
-- Set default if not specified.
|
||||||
|
EngageRange=EngageRange or 100
|
||||||
|
if EngageRange < 0 or EngageRange > 100 then
|
||||||
|
EngageRange = 100
|
||||||
|
end
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local Controller = self:_GetController()
|
||||||
|
if Controller then
|
||||||
|
if self:IsGround() then
|
||||||
|
self:SetOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION, EngageRange)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (GROUND) Relocate controllable to a random point within a given radius; use e.g.for evasive actions; Note that not all ground controllables can actually drive, also the alarm state of the controllable might stop it from moving.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number speed Speed of the controllable, default 20
|
||||||
|
-- @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 shortcut If true and onroad is set, take a shorter route - if available - off road, default false
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:RelocateGroundRandomInRadius(speed, radius, onroad, shortcut)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
|
||||||
|
local _coord = self:GetCoordinate()
|
||||||
|
local _radius = radius or 500
|
||||||
|
local _speed = speed or 20
|
||||||
|
local _tocoord = _coord:GetRandomCoordinateInRadius(_radius,100)
|
||||||
|
local _onroad = onroad or true
|
||||||
|
local _grptsk = {}
|
||||||
|
local _candoroad = false
|
||||||
|
local _shortcut = shortcut or false
|
||||||
|
|
||||||
|
-- create a DCS Task an push it on the group
|
||||||
|
-- TaskGroundOnRoad(ToCoordinate,Speed,OffRoadFormation,Shortcut,FromCoordinate,WaypointFunction,WaypointFunctionArguments)
|
||||||
|
if onroad then
|
||||||
|
_grptsk, _candoroad = self:TaskGroundOnRoad(_tocoord,_speed,"Off Road",_shortcut)
|
||||||
|
self:Route(_grptsk,5)
|
||||||
|
else
|
||||||
|
self:TaskRouteToVec2(_tocoord:GetVec2(),_speed,"Off Road")
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Defines how long a GROUND unit/group will move to avoid an ongoing attack.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number Seconds Any positive number: AI will disperse, but only for the specified time before continuing their route. 0: AI will not disperse.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:OptionDisperseOnAttack(Seconds)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
-- Set default if not specified.
|
||||||
|
local seconds = Seconds or 0
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local Controller = self:_GetController()
|
||||||
|
if Controller then
|
||||||
|
if self:IsGround() then
|
||||||
|
self:SetOption(AI.Option.GROUND.id.DISPERSE_ON_ATTACK, seconds)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|||||||
@@ -261,7 +261,9 @@ end
|
|||||||
-- @param #string GroupName The Group name
|
-- @param #string GroupName The Group name
|
||||||
-- @return #GROUP self
|
-- @return #GROUP self
|
||||||
function GROUP:Register( GroupName )
|
function GROUP:Register( GroupName )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) -- #GROUP
|
local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) -- #GROUP
|
||||||
|
|
||||||
self.GroupName = GroupName
|
self.GroupName = GroupName
|
||||||
|
|
||||||
self:SetEventPriority( 4 )
|
self:SetEventPriority( 4 )
|
||||||
@@ -668,14 +670,15 @@ end
|
|||||||
-- @param #number UnitNumber The number of the UNIT wrapper class to be returned.
|
-- @param #number UnitNumber The number of the UNIT wrapper class to be returned.
|
||||||
-- @return Wrapper.Unit#UNIT The UNIT wrapper class.
|
-- @return Wrapper.Unit#UNIT The UNIT wrapper class.
|
||||||
function GROUP:GetUnit( UnitNumber )
|
function GROUP:GetUnit( UnitNumber )
|
||||||
self:F3( { self.GroupName, UnitNumber } )
|
|
||||||
|
|
||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
|
|
||||||
local DCSUnit = DCSGroup:getUnit( UnitNumber )
|
local DCSUnit = DCSGroup:getUnit( UnitNumber )
|
||||||
local UnitFound = UNIT:Find( DCSGroup:getUnit( UnitNumber ) )
|
|
||||||
self:T2( UnitFound )
|
local UnitFound = UNIT:Find(DCSUnit)
|
||||||
|
|
||||||
return UnitFound
|
return UnitFound
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -688,13 +691,11 @@ end
|
|||||||
-- @param #number UnitNumber The number of the DCS Unit to be returned.
|
-- @param #number UnitNumber The number of the DCS Unit to be returned.
|
||||||
-- @return DCS#Unit The DCS Unit.
|
-- @return DCS#Unit The DCS Unit.
|
||||||
function GROUP:GetDCSUnit( UnitNumber )
|
function GROUP:GetDCSUnit( UnitNumber )
|
||||||
self:F3( { self.GroupName, UnitNumber } )
|
|
||||||
|
|
||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup=self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local DCSUnitFound = DCSGroup:getUnit( UnitNumber )
|
local DCSUnitFound=DCSGroup:getUnit( UnitNumber )
|
||||||
self:T3( DCSUnitFound )
|
|
||||||
return DCSUnitFound
|
return DCSUnitFound
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -706,14 +707,14 @@ end
|
|||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return #number The DCS Group size.
|
-- @return #number The DCS Group size.
|
||||||
function GROUP:GetSize()
|
function GROUP:GetSize()
|
||||||
self:F3( { self.GroupName } )
|
|
||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
|
|
||||||
local GroupSize = DCSGroup:getSize()
|
local GroupSize = DCSGroup:getSize()
|
||||||
|
|
||||||
if GroupSize then
|
if GroupSize then
|
||||||
self:T3( GroupSize )
|
|
||||||
return GroupSize
|
return GroupSize
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
@@ -946,24 +947,31 @@ end
|
|||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return DCS#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group.
|
-- @return DCS#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group.
|
||||||
function GROUP:GetVec2()
|
function GROUP:GetVec2()
|
||||||
self:F2( self.GroupName )
|
|
||||||
|
|
||||||
local UnitPoint = self:GetUnit(1)
|
local Unit=self:GetUnit(1)
|
||||||
UnitPoint:GetVec2()
|
|
||||||
local GroupPointVec2 = UnitPoint:GetVec2()
|
if Unit then
|
||||||
self:T3( GroupPointVec2 )
|
local vec2=Unit:GetVec2()
|
||||||
return GroupPointVec2
|
return vec2
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the current Vec3 vector of the first DCS Unit in the GROUP.
|
--- Returns the current Vec3 vector of the first DCS Unit in the GROUP.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return DCS#Vec3 Current Vec3 of the first DCS Unit of the GROUP.
|
-- @return DCS#Vec3 Current Vec3 of the first DCS Unit of the GROUP.
|
||||||
function GROUP:GetVec3()
|
function GROUP:GetVec3()
|
||||||
self:F2( self.GroupName )
|
|
||||||
|
|
||||||
local GroupVec3 = self:GetUnit(1):GetVec3()
|
-- Get first unit.
|
||||||
self:T3( GroupVec3 )
|
local unit=self:GetUnit(1)
|
||||||
return GroupVec3
|
|
||||||
|
if unit then
|
||||||
|
local vec3=unit:GetVec3()
|
||||||
|
return vec3
|
||||||
|
end
|
||||||
|
|
||||||
|
self:E("ERROR: Cannot get Vec3 of group "..tostring(self.GroupName))
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a POINT_VEC2 object indicating the point in 2D of the first UNIT of the GROUP within the mission.
|
--- Returns a POINT_VEC2 object indicating the point in 2D of the first UNIT of the GROUP within the mission.
|
||||||
@@ -990,13 +998,11 @@ end
|
|||||||
-- @param Wrapper.Group#GROUP self
|
-- @param Wrapper.Group#GROUP self
|
||||||
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
||||||
function GROUP:GetCoordinate()
|
function GROUP:GetCoordinate()
|
||||||
self:F2( self.PositionableName )
|
|
||||||
|
|
||||||
local FirstUnit = self:GetUnit(1)
|
local FirstUnit = self:GetUnit(1)
|
||||||
|
|
||||||
if FirstUnit then
|
if FirstUnit then
|
||||||
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
||||||
self:T3(FirstUnitCoordinate)
|
|
||||||
return FirstUnitCoordinate
|
return FirstUnitCoordinate
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1039,11 +1045,16 @@ function GROUP:GetHeading()
|
|||||||
local GroupSize = self:GetSize()
|
local GroupSize = self:GetSize()
|
||||||
local HeadingAccumulator = 0
|
local HeadingAccumulator = 0
|
||||||
|
|
||||||
|
local n=0
|
||||||
if GroupSize then
|
if GroupSize then
|
||||||
for i = 1, GroupSize do
|
for i = 1, GroupSize do
|
||||||
HeadingAccumulator = HeadingAccumulator + self:GetUnit(i):GetHeading()
|
local unit=self:GetUnit(i)
|
||||||
|
if unit and unit:IsAlive() then
|
||||||
|
HeadingAccumulator = HeadingAccumulator + unit:GetHeading()
|
||||||
|
n=n+1
|
||||||
end
|
end
|
||||||
return math.floor(HeadingAccumulator / GroupSize)
|
end
|
||||||
|
return math.floor(HeadingAccumulator / n)
|
||||||
end
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetHeading", Group = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetHeading", Group = self, Alive = self:IsAlive() } )
|
||||||
@@ -1161,6 +1172,35 @@ end
|
|||||||
|
|
||||||
do -- Is Zone methods
|
do -- Is Zone methods
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if any unit of a group is inside a @{Zone}.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
|
||||||
|
-- @return #boolean Returns `true` if *at least one unit* is inside the zone or `false` if *no* unit is inside.
|
||||||
|
function GROUP:IsInZone( Zone )
|
||||||
|
|
||||||
|
if self:IsAlive() then
|
||||||
|
|
||||||
|
for UnitID, UnitData in pairs(self:GetUnits()) do
|
||||||
|
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
-- Get 2D vector. That's all we need for the zone check.
|
||||||
|
local vec2=Unit:GetVec2()
|
||||||
|
|
||||||
|
if Zone:IsVec2InZone(vec2) then
|
||||||
|
return true -- At least one unit is in the zone. That is enough.
|
||||||
|
else
|
||||||
|
-- This one is not but another could be.
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns true if all units of the group are within a @{Zone}.
|
--- Returns true if all units of the group are within a @{Zone}.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
|
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
|
||||||
@@ -2095,6 +2135,7 @@ end
|
|||||||
|
|
||||||
--- Calculate the maxium A2G threat level of the Group.
|
--- Calculate the maxium A2G threat level of the Group.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
|
-- @return #number Number between 0 and 10.
|
||||||
function GROUP:CalculateThreatLevelA2G()
|
function GROUP:CalculateThreatLevelA2G()
|
||||||
|
|
||||||
local MaxThreatLevelA2G = 0
|
local MaxThreatLevelA2G = 0
|
||||||
@@ -2110,6 +2151,25 @@ function GROUP:CalculateThreatLevelA2G()
|
|||||||
return MaxThreatLevelA2G
|
return MaxThreatLevelA2G
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get threat level of the group.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @return #number Max threat level (a number between 0 and 10).
|
||||||
|
function GROUP:GetThreatLevel()
|
||||||
|
|
||||||
|
local threatlevelMax = 0
|
||||||
|
for UnitName, UnitData in pairs(self:GetUnits()) do
|
||||||
|
local ThreatUnit = UnitData -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
local threatlevel = ThreatUnit:GetThreatLevel()
|
||||||
|
if threatlevel > threatlevelMax then
|
||||||
|
threatlevelMax=threatlevel
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return threatlevelMax
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns true if the first unit of the GROUP is in the air.
|
--- Returns true if the first unit of the GROUP is in the air.
|
||||||
-- @param Wrapper.Group#GROUP self
|
-- @param Wrapper.Group#GROUP self
|
||||||
-- @return #boolean true if in the first unit of the group is in the air or #nil if the GROUP is not existing or not alive.
|
-- @return #boolean true if in the first unit of the group is in the air or #nil if the GROUP is not existing or not alive.
|
||||||
@@ -2142,6 +2202,10 @@ function GROUP:IsAirborne(AllUnits)
|
|||||||
|
|
||||||
if units then
|
if units then
|
||||||
|
|
||||||
|
if AllUnits then
|
||||||
|
|
||||||
|
--- We want to know if ALL units are airborne.
|
||||||
|
|
||||||
for _,_unit in pairs(units) do
|
for _,_unit in pairs(units) do
|
||||||
local unit=_unit --Wrapper.Unit#UNIT
|
local unit=_unit --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
@@ -2150,19 +2214,40 @@ function GROUP:IsAirborne(AllUnits)
|
|||||||
-- Unit in air or not.
|
-- Unit in air or not.
|
||||||
local inair=unit:InAir()
|
local inair=unit:InAir()
|
||||||
|
|
||||||
-- Unit is not in air and we wanted to know whether ALL units are ==> return false
|
-- At least one unit is not in air.
|
||||||
if inair==false and AllUnits==true then
|
if not inair then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- At least one unit is in are and we did not care which one.
|
end
|
||||||
if inair==true and not AllUnits then
|
|
||||||
|
-- All units are in air.
|
||||||
|
return true
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
--- We want to know if ANY unit is airborne.
|
||||||
|
|
||||||
|
for _,_unit in pairs(units) do
|
||||||
|
local unit=_unit --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
if unit then
|
||||||
|
|
||||||
|
-- Unit in air or not.
|
||||||
|
local inair=unit:InAir()
|
||||||
|
|
||||||
|
if inair then
|
||||||
|
-- At least one unit is in air.
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
-- At least one unit is in the air.
|
|
||||||
return true
|
-- No unit is in air.
|
||||||
|
return false
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2466,6 +2551,23 @@ do -- Players
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- GROUND - Switch on/off radar emissions
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param #boolean switch
|
||||||
|
function GROUP:EnableEmission(switch)
|
||||||
|
self:F2( self.GroupName )
|
||||||
|
local switch = switch or false
|
||||||
|
|
||||||
|
local DCSUnit = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSUnit then
|
||||||
|
|
||||||
|
DCSUnit:enableEmission(switch)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--do -- Smoke
|
--do -- Smoke
|
||||||
--
|
--
|
||||||
----- Signal a flare at the position of the GROUP.
|
----- Signal a flare at the position of the GROUP.
|
||||||
|
|||||||
776
Moose Development/Moose/Wrapper/Marker.lua
Normal file
776
Moose Development/Moose/Wrapper/Marker.lua
Normal file
@@ -0,0 +1,776 @@
|
|||||||
|
--- **Wrapper** - Markers On the F10 map.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Convenient handling of markers via multiple user API functions.
|
||||||
|
-- * Update text and position of marker easily via scripting.
|
||||||
|
-- * Delay creation and removal of markers via (optional) parameters.
|
||||||
|
-- * Retrieve data such as text and coordinate.
|
||||||
|
-- * Marker specific FSM events when a marker is added, removed or changed.
|
||||||
|
-- * Additional FSM events when marker text or position is changed.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
-- @module Wrapper.Marker
|
||||||
|
-- @image Wrapper_Marker.png
|
||||||
|
|
||||||
|
|
||||||
|
--- Marker class.
|
||||||
|
-- @type MARKER
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #number mid Marker ID.
|
||||||
|
-- @field Core.Point#COORDINATE coordinate Coordinate of the mark.
|
||||||
|
-- @field #string text Text displayed in the mark panel.
|
||||||
|
-- @field #string message Message dispayed when the mark is added.
|
||||||
|
-- @field #boolean readonly Marker is read-only.
|
||||||
|
-- @field #number coalition Coalition to which the marker is displayed.
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
--- Just because...
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- 
|
||||||
|
--
|
||||||
|
-- # The MARKER Class Idea
|
||||||
|
--
|
||||||
|
-- The MARKER class simplifies creating, updating and removing of markers on the F10 map.
|
||||||
|
--
|
||||||
|
-- # Create a Marker
|
||||||
|
--
|
||||||
|
-- -- Create a MARKER object at Batumi with a trivial text.
|
||||||
|
-- local Coordinate=AIRBASE:FindByName("Batumi"):GetCoordinate()
|
||||||
|
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield")
|
||||||
|
--
|
||||||
|
-- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e.
|
||||||
|
-- show the marker to everyone, to a speficic coaliton only, or only to a specific group.
|
||||||
|
--
|
||||||
|
-- ## For Everyone
|
||||||
|
--
|
||||||
|
-- If the marker should be visible to everyone, you can use the :ToAll() function.
|
||||||
|
--
|
||||||
|
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToAll()
|
||||||
|
--
|
||||||
|
-- ## For a Coaliton
|
||||||
|
--
|
||||||
|
-- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function.
|
||||||
|
--
|
||||||
|
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToCoaliton(coaliton.side.BLUE)
|
||||||
|
--
|
||||||
|
-- ### To Blue Coaliton
|
||||||
|
--
|
||||||
|
-- ### To Red Coalition
|
||||||
|
--
|
||||||
|
-- This would show the marker only to the Blue coaliton.
|
||||||
|
--
|
||||||
|
-- ## For a Group
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Removing a Marker
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Updating a Marker
|
||||||
|
--
|
||||||
|
-- The marker text and coordinate can be updated easily as shown below.
|
||||||
|
--
|
||||||
|
-- However, note that **updateing involves to remove and recreate the marker if either text or its coordinate is changed**.
|
||||||
|
-- *This is a DCS scripting engine limitation.*
|
||||||
|
--
|
||||||
|
-- ## Update Text
|
||||||
|
--
|
||||||
|
-- If you created a marker "mymarker" as shown above, you can update the dispayed test by
|
||||||
|
--
|
||||||
|
-- mymarker:UpdateText("I am the new text at Batumi")
|
||||||
|
--
|
||||||
|
-- The update can also be delayed by, e.g. 90 seconds, using
|
||||||
|
--
|
||||||
|
-- mymarker:UpdateText("I am the new text at Batumi", 90)
|
||||||
|
--
|
||||||
|
-- ## Update Coordinate
|
||||||
|
--
|
||||||
|
-- If you created a marker "mymarker" as shown above, you can update its coordinate on the F10 map by
|
||||||
|
--
|
||||||
|
-- mymarker:UpdateCoordinate(NewCoordinate)
|
||||||
|
--
|
||||||
|
-- The update can also be delayed by, e.g. 60 seconds, using
|
||||||
|
--
|
||||||
|
-- mymarker:UpdateCoordinate(NewCoordinate, 60)
|
||||||
|
--
|
||||||
|
-- # Retrieve Data
|
||||||
|
--
|
||||||
|
-- The important data as the displayed text and the coordinate of the marker can be retrieved easily.
|
||||||
|
--
|
||||||
|
-- ## Text
|
||||||
|
--
|
||||||
|
-- local text=mymarker:GetText()
|
||||||
|
-- env.info("Marker Text = " .. text)
|
||||||
|
--
|
||||||
|
-- ## Coordinate
|
||||||
|
--
|
||||||
|
-- local Coordinate=mymarker:GetCoordinate()
|
||||||
|
-- env.info("Marker Coordinate LL DSM = " .. Coordinate:ToStringLLDMS())
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # FSM Events
|
||||||
|
--
|
||||||
|
-- Moose creates addditonal events, so called FSM event, when markers are added, changed, removed, and text or the coordianteis updated.
|
||||||
|
--
|
||||||
|
-- These events can be captured and used for processing via OnAfter functions as shown below.
|
||||||
|
--
|
||||||
|
-- ## Added
|
||||||
|
--
|
||||||
|
-- ## Changed
|
||||||
|
--
|
||||||
|
-- ## Removed
|
||||||
|
--
|
||||||
|
-- ## TextUpdate
|
||||||
|
--
|
||||||
|
-- ## CoordUpdate
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Examples
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #MARKER
|
||||||
|
MARKER = {
|
||||||
|
ClassName = "MARKER",
|
||||||
|
Debug = false,
|
||||||
|
lid = nil,
|
||||||
|
mid = nil,
|
||||||
|
coordinate = nil,
|
||||||
|
text = nil,
|
||||||
|
message = nil,
|
||||||
|
readonly = nil,
|
||||||
|
coalition = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Marker ID. Running number.
|
||||||
|
_MARKERID=0
|
||||||
|
|
||||||
|
--- Marker class version.
|
||||||
|
-- @field #string version
|
||||||
|
MARKER.version="0.1.0"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: User "Get" functions. E.g., :GetCoordinate()
|
||||||
|
-- DONE: Add delay to user functions.
|
||||||
|
-- DONE: Handle events.
|
||||||
|
-- DONE: Create FSM events.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new MARKER class object.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Coordinate where to place the marker.
|
||||||
|
-- @param #string Text Text displayed on the mark panel.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:New(Coordinate, Text)
|
||||||
|
|
||||||
|
-- Inherit everything from FSM class.
|
||||||
|
local self=BASE:Inherit(self, FSM:New()) -- #MARKER
|
||||||
|
|
||||||
|
self.coordinate=Coordinate
|
||||||
|
|
||||||
|
self.text=Text
|
||||||
|
|
||||||
|
-- Defaults
|
||||||
|
self.readonly=false
|
||||||
|
self.message=""
|
||||||
|
|
||||||
|
-- New marker ID. This is not the one of the actual marker.
|
||||||
|
_MARKERID=_MARKERID+1
|
||||||
|
|
||||||
|
self.myid=_MARKERID
|
||||||
|
|
||||||
|
-- Log ID.
|
||||||
|
self.lid=string.format("Marker #%d | ", self.myid)
|
||||||
|
|
||||||
|
-- Start State.
|
||||||
|
self:SetStartState("Invisible")
|
||||||
|
|
||||||
|
-- Add FSM transitions.
|
||||||
|
-- From State --> Event --> To State
|
||||||
|
self:AddTransition("Invisible", "Added", "Visible") -- Marker was added.
|
||||||
|
self:AddTransition("Visible", "Removed", "Invisible") -- Marker was removed.
|
||||||
|
self:AddTransition("*", "Changed", "*") -- Marker was changed.
|
||||||
|
|
||||||
|
self:AddTransition("*", "TextUpdate", "*") -- Text updated.
|
||||||
|
self:AddTransition("*", "CoordUpdate", "*") -- Coordinates updated.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Added".
|
||||||
|
-- @function [parent=#MARKER] Added
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
--- Triggers the delayed FSM event "Added".
|
||||||
|
-- @function [parent=#MARKER] __Added
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
--- On after "Added" event user function.
|
||||||
|
-- @function [parent=#MARKER] OnAfterAdded
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Removed".
|
||||||
|
-- @function [parent=#MARKER] Removed
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
--- Triggers the delayed FSM event "Removed".
|
||||||
|
-- @function [parent=#MARKER] __Removed
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
--- On after "Removed" event user function.
|
||||||
|
-- @function [parent=#MARKER] OnAfterRemoved
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Changed".
|
||||||
|
-- @function [parent=#MARKER] Changed
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
--- Triggers the delayed FSM event "Changed".
|
||||||
|
-- @function [parent=#MARKER] __Changed
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
--- On after "Changed" event user function.
|
||||||
|
-- @function [parent=#MARKER] OnAfterChanged
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "TextUpdate".
|
||||||
|
-- @function [parent=#MARKER] TextUpdate
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string Text The new text.
|
||||||
|
|
||||||
|
--- Triggers the delayed FSM event "TextUpdate".
|
||||||
|
-- @function [parent=#MARKER] __TextUpdate
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string Text The new text.
|
||||||
|
|
||||||
|
--- On after "TextUpdate" event user function.
|
||||||
|
-- @function [parent=#MARKER] OnAfterTextUpdate
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string Text The new text.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "CoordUpdate".
|
||||||
|
-- @function [parent=#MARKER] CoordUpdate
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The new Coordinate.
|
||||||
|
|
||||||
|
--- Triggers the delayed FSM event "CoordUpdate".
|
||||||
|
-- @function [parent=#MARKER] __CoordUpdate
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The updated Coordinate.
|
||||||
|
|
||||||
|
--- On after "CoordUpdate" event user function.
|
||||||
|
-- @function [parent=#MARKER] OnAfterCoordUpdate
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The updated Coordinate.
|
||||||
|
|
||||||
|
|
||||||
|
-- Handle events.
|
||||||
|
self:HandleEvent(EVENTS.MarkAdded)
|
||||||
|
self:HandleEvent(EVENTS.MarkRemoved)
|
||||||
|
self:HandleEvent(EVENTS.MarkChange)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User API Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Marker is readonly. Text cannot be changed and marker cannot be removed.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ReadOnly()
|
||||||
|
|
||||||
|
self.readonly=true
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set message that is displayed on screen if the marker is added.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string Text Message displayed when the marker is added.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:Message(Text)
|
||||||
|
|
||||||
|
self.message=Text or ""
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Place marker visible for everyone.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ToAll(Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MARKER.ToAll, self)
|
||||||
|
else
|
||||||
|
|
||||||
|
self.toall=true
|
||||||
|
self.tocoaliton=nil
|
||||||
|
self.coalition=nil
|
||||||
|
self.togroup=nil
|
||||||
|
self.groupname=nil
|
||||||
|
self.groupid=nil
|
||||||
|
|
||||||
|
-- First remove an existing mark.
|
||||||
|
if self.shown then
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.mid=UTILS.GetMarkID()
|
||||||
|
|
||||||
|
-- Call DCS function.
|
||||||
|
trigger.action.markToAll(self.mid, self.text, self.coordinate:GetVec3(), self.readonly, self.message)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Place marker visible for a specific coalition only.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #number Coalition Coalition 1=Red, 2=Blue, 0=Neutral. See `coaliton.side.RED`.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ToCoalition(Coalition, Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MARKER.ToCoalition, self, Coalition)
|
||||||
|
else
|
||||||
|
|
||||||
|
self.coalition=Coalition
|
||||||
|
|
||||||
|
self.tocoaliton=true
|
||||||
|
self.toall=false
|
||||||
|
self.togroup=false
|
||||||
|
self.groupname=nil
|
||||||
|
self.groupid=nil
|
||||||
|
|
||||||
|
-- First remove an existing mark.
|
||||||
|
if self.shown then
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.mid=UTILS.GetMarkID()
|
||||||
|
|
||||||
|
-- Call DCS function.
|
||||||
|
trigger.action.markToCoalition(self.mid, self.text, self.coordinate:GetVec3(), self.coalition, self.readonly, self.message)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Place marker visible for the blue coalition only.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ToBlue(Delay)
|
||||||
|
self:ToCoalition(coalition.side.BLUE, Delay)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Place marker visible for the blue coalition only.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ToRed(Delay)
|
||||||
|
self:ToCoalition(coalition.side.RED, Delay)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Place marker visible for the neutral coalition only.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ToNeutral(Delay)
|
||||||
|
self:ToCoalition(coalition.side.NEUTRAL, Delay)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Place marker visible for a specific group only.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Wrapper.Group#GROUP Group The group to which the marker is displayed.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ToGroup(Group, Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MARKER.ToGroup, self, Group)
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Check if group exists.
|
||||||
|
if Group and Group:IsAlive()~=nil then
|
||||||
|
|
||||||
|
self.groupid=Group:GetID()
|
||||||
|
|
||||||
|
if self.groupid then
|
||||||
|
|
||||||
|
self.groupname=Group:GetName()
|
||||||
|
|
||||||
|
self.togroup=true
|
||||||
|
self.tocoaliton=nil
|
||||||
|
self.coalition=nil
|
||||||
|
self.toall=nil
|
||||||
|
|
||||||
|
-- First remove an existing mark.
|
||||||
|
if self.shown then
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.mid=UTILS.GetMarkID()
|
||||||
|
|
||||||
|
-- Call DCS function.
|
||||||
|
trigger.action.markToGroup(self.mid, self.text, self.coordinate:GetVec3(), self.groupid, self.readonly, self.message)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
--TODO: Warning!
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update the text displayed on the mark panel.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string Text Updated text.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:UpdateText(Text, Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MARKER.UpdateText, self, Text)
|
||||||
|
else
|
||||||
|
|
||||||
|
self.text=tostring(Text)
|
||||||
|
|
||||||
|
self:Refresh()
|
||||||
|
|
||||||
|
self:TextUpdate(tostring(Text))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update the coordinate where the marker is displayed.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The new coordinate.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:UpdateCoordinate(Coordinate, Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MARKER.UpdateCoordinate, self, Coordinate)
|
||||||
|
else
|
||||||
|
|
||||||
|
self.coordinate=Coordinate
|
||||||
|
|
||||||
|
self:Refresh()
|
||||||
|
|
||||||
|
self:CoordUpdate(Coordinate)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the marker.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:Refresh(Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MARKER.Refresh, self)
|
||||||
|
else
|
||||||
|
|
||||||
|
if self.toall then
|
||||||
|
|
||||||
|
self:ToAll()
|
||||||
|
|
||||||
|
elseif self.tocoaliton then
|
||||||
|
|
||||||
|
self:ToCoalition(self.coalition)
|
||||||
|
|
||||||
|
elseif self.togroup then
|
||||||
|
|
||||||
|
local group=GROUP:FindByName(self.groupname)
|
||||||
|
|
||||||
|
self:ToGroup(group)
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E(self.lid.."ERROR: unknown To in :Refresh()!")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove a marker.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is removed.
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:Remove(Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MARKER.Remove, self)
|
||||||
|
else
|
||||||
|
|
||||||
|
if self.shown then
|
||||||
|
|
||||||
|
-- Call DCS function.
|
||||||
|
trigger.action.removeMark(self.mid)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get position of the marker.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @return Core.Point#COORDINATE The coordinate of the marker.
|
||||||
|
function MARKER:GetCoordinate()
|
||||||
|
return self.coordinate
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get text that is displayed in the marker panel.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @return #string Marker text.
|
||||||
|
function MARKER:GetText()
|
||||||
|
return self.text
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set text that is displayed in the marker panel. Note this does not show the marker.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string Text Marker text. Default is an empty sting "".
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:SetText(Text)
|
||||||
|
self.text=Text and tostring(Text) or ""
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if marker is currently visible on the F10 map.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @return #boolean True if the marker is currently visible.
|
||||||
|
function MARKER:IsVisible()
|
||||||
|
return self:Is("Visible")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if marker is currently invisible on the F10 map.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @return
|
||||||
|
function MARKER:IsInvisible()
|
||||||
|
return self:Is("Invisible")
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Event Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Event function when a MARKER is added.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function MARKER:OnEventMarkAdded(EventData)
|
||||||
|
|
||||||
|
if EventData and EventData.MarkID then
|
||||||
|
|
||||||
|
local MarkID=EventData.MarkID
|
||||||
|
|
||||||
|
self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID)))
|
||||||
|
|
||||||
|
if MarkID==self.mid then
|
||||||
|
|
||||||
|
self.shown=true
|
||||||
|
|
||||||
|
self:Added(EventData)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Event function when a MARKER is removed.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function MARKER:OnEventMarkRemoved(EventData)
|
||||||
|
|
||||||
|
if EventData and EventData.MarkID then
|
||||||
|
|
||||||
|
local MarkID=EventData.MarkID
|
||||||
|
|
||||||
|
self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID)))
|
||||||
|
|
||||||
|
if MarkID==self.mid then
|
||||||
|
|
||||||
|
self.shown=false
|
||||||
|
|
||||||
|
self:Removed(EventData)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Event function when a MARKER changed.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function MARKER:OnEventMarkChange(EventData)
|
||||||
|
|
||||||
|
if EventData and EventData.MarkID then
|
||||||
|
|
||||||
|
local MarkID=EventData.MarkID
|
||||||
|
|
||||||
|
self:T3(self.lid..string.format("Captured event MarkChange for Mark ID=%s", tostring(MarkID)))
|
||||||
|
|
||||||
|
if MarkID==self.mid then
|
||||||
|
|
||||||
|
self:Changed(EventData)
|
||||||
|
|
||||||
|
self:TextChanged(tostring(EventData.MarkText))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- FSM Event Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- On after "Added" event.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
function MARKER:onafterAdded(From, Event, To, EventData)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Captured event MarkAdded for myself:\n")
|
||||||
|
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID))
|
||||||
|
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition))
|
||||||
|
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID))
|
||||||
|
text=text..string.format("Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody")
|
||||||
|
text=text..string.format("Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere")
|
||||||
|
text=text..string.format("Text: \n%s", tostring(EventData.MarkText))
|
||||||
|
self:T2(self.lid..text)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after "Removed" event.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
function MARKER:onafterRemoved(From, Event, To, EventData)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Captured event MarkRemoved for myself:\n")
|
||||||
|
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID))
|
||||||
|
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition))
|
||||||
|
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID))
|
||||||
|
text=text..string.format("Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody")
|
||||||
|
text=text..string.format("Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere")
|
||||||
|
text=text..string.format("Text: \n%s", tostring(EventData.MarkText))
|
||||||
|
self:T2(self.lid..text)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after "Changed" event.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
function MARKER:onafterChanged(From, Event, To, EventData)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Captured event MarkChange for myself:\n")
|
||||||
|
text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID))
|
||||||
|
text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition))
|
||||||
|
text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID))
|
||||||
|
text=text..string.format("Initiator = %s\n", EventData.IniUnit and EventData.IniUnit:GetName() or "Nobody")
|
||||||
|
text=text..string.format("Coordinate = %s\n", EventData.MarkCoordinate and EventData.MarkCoordinate:ToStringLLDMS() or "Nowhere")
|
||||||
|
text=text..string.format("Text: \n%s", tostring(EventData.MarkText))
|
||||||
|
self:T2(self.lid..text)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after "TextUpdate" event.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string Text The updated text, displayed in the mark panel.
|
||||||
|
function MARKER:onafterTextUpdate(From, Event, To, Text)
|
||||||
|
|
||||||
|
self:T(self.lid..string.format("New Marker Text:\n%s", Text))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On after "CoordUpdate" event.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The updated coordinates.
|
||||||
|
function MARKER:onafterCoordUpdate(From, Event, To, Coordinate)
|
||||||
|
|
||||||
|
self:T(self.lid..string.format("New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS()))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
||||||
|
|
||||||
--- @type POSITIONABLE
|
--- @type POSITIONABLE
|
||||||
|
-- @field Core.Point#COORDINATE coordinate Coordinate object.
|
||||||
|
-- @field Core.Point#POINT_VEC3 pointvec3 Point Vec3 object.
|
||||||
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
||||||
|
|
||||||
|
|
||||||
@@ -45,6 +47,8 @@
|
|||||||
POSITIONABLE = {
|
POSITIONABLE = {
|
||||||
ClassName = "POSITIONABLE",
|
ClassName = "POSITIONABLE",
|
||||||
PositionableName = "",
|
PositionableName = "",
|
||||||
|
coordinate = nil,
|
||||||
|
pointvec3 = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- @field #POSITIONABLE.__
|
--- @field #POSITIONABLE.__
|
||||||
@@ -121,10 +125,17 @@ function POSITIONABLE:Destroy( GenerateEvent )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the DCS object. Polymorphic for other classes like UNIT, STATIC, GROUP, AIRBASE.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @return DCS#Object The DCS object.
|
||||||
|
function POSITIONABLE:GetDCSObject()
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns a pos3 table of the objects current position and orientation in 3D space. X, Y, Z values are unit vectors defining the objects orientation.
|
--- Returns a pos3 table of the objects current position and orientation in 3D space. X, Y, Z values are unit vectors defining the objects orientation.
|
||||||
-- Coordinates are dependent on the position of the maps origin.
|
-- Coordinates are dependent on the position of the maps origin.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return DCS#Position Table consisting of the point and orientation tables.
|
-- @return DCS#Position3 Table consisting of the point and orientation tables.
|
||||||
function POSITIONABLE:GetPosition()
|
function POSITIONABLE:GetPosition()
|
||||||
self:F2( self.PositionableName )
|
self:F2( self.PositionableName )
|
||||||
|
|
||||||
@@ -215,27 +226,44 @@ function POSITIONABLE:GetPositionVec3()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the @{DCS#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission.
|
--- Returns the @{DCS#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE.
|
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE or `nil` if it is not existing or alive.
|
||||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
function POSITIONABLE:GetVec3()
|
||||||
function POSITIONABLE:GetVec2()
|
|
||||||
self:F2( self.PositionableName )
|
|
||||||
|
|
||||||
local DCSPositionable = self:GetDCSObject()
|
local DCSPositionable = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSPositionable then
|
if DCSPositionable then
|
||||||
local PositionableVec3 = DCSPositionable:getPosition().p
|
|
||||||
|
|
||||||
local PositionableVec2 = {}
|
local vec3=DCSPositionable:getPoint()
|
||||||
PositionableVec2.x = PositionableVec3.x
|
|
||||||
PositionableVec2.y = PositionableVec3.z
|
|
||||||
|
|
||||||
self:T2( PositionableVec2 )
|
if vec3 then
|
||||||
return PositionableVec2
|
return vec3
|
||||||
|
else
|
||||||
|
self:E("ERROR: Cannot get vec3!")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetVec2", Positionable = self, Alive = self:IsAlive() } )
|
-- ERROR!
|
||||||
|
self:E( { "Cannot GetVec3", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the @{DCS#Vec2} vector indicating the point in 2D of the POSITIONABLE within the mission.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return DCS#Vec2 The 2D point vector of the POSITIONABLE or #nil if it is not existing or alive.
|
||||||
|
function POSITIONABLE:GetVec2()
|
||||||
|
|
||||||
|
local DCSPositionable = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSPositionable then
|
||||||
|
|
||||||
|
local Vec3=DCSPositionable:getPoint() --DCS#Vec3
|
||||||
|
|
||||||
|
return {x=Vec3.x, y=Vec3.z}
|
||||||
|
end
|
||||||
|
|
||||||
|
self:E( { "Cannot GetVec2", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -258,7 +286,7 @@ function POSITIONABLE:GetPointVec2()
|
|||||||
return PositionablePointVec2
|
return PositionablePointVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetPointVec2", Positionable = self, Alive = self:IsAlive() } )
|
self:E( { "Cannot GetPointVec2", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -268,17 +296,29 @@ end
|
|||||||
-- @return Core.Point#POINT_VEC3 The 3D point vector of the POSITIONABLE.
|
-- @return Core.Point#POINT_VEC3 The 3D point vector of the POSITIONABLE.
|
||||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||||
function POSITIONABLE:GetPointVec3()
|
function POSITIONABLE:GetPointVec3()
|
||||||
self:F2( self.PositionableName )
|
|
||||||
|
|
||||||
local DCSPositionable = self:GetDCSObject()
|
local DCSPositionable = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSPositionable then
|
if DCSPositionable then
|
||||||
|
|
||||||
|
-- Get 3D vector.
|
||||||
local PositionableVec3 = self:GetPositionVec3()
|
local PositionableVec3 = self:GetPositionVec3()
|
||||||
|
|
||||||
local PositionablePointVec3 = POINT_VEC3:NewFromVec3( PositionableVec3 )
|
if false and self.pointvec3 then
|
||||||
|
|
||||||
self:T2( PositionablePointVec3 )
|
-- Update vector.
|
||||||
return PositionablePointVec3
|
self.pointvec3.x=PositionableVec3.x
|
||||||
|
self.pointvec3.y=PositionableVec3.y
|
||||||
|
self.pointvec3.z=PositionableVec3.z
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Create a new POINT_VEC3 object.
|
||||||
|
self.pointvec3=POINT_VEC3:NewFromVec3(PositionableVec3)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.pointvec3
|
||||||
end
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetPointVec3", Positionable = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetPointVec3", Positionable = self, Alive = self:IsAlive() } )
|
||||||
@@ -289,27 +329,64 @@ end
|
|||||||
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
|
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return Core.Point#COORDINATE The COORDINATE of the POSITIONABLE.
|
-- @return Core.Point#COORDINATE The COORDINATE of the POSITIONABLE.
|
||||||
function POSITIONABLE:GetCoordinate()
|
function POSITIONABLE:GetCoord()
|
||||||
self:F2( self.PositionableName )
|
|
||||||
|
|
||||||
|
-- Get DCS object.
|
||||||
local DCSPositionable = self:GetDCSObject()
|
local DCSPositionable = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSPositionable then
|
if DCSPositionable then
|
||||||
local PositionableVec3 = self:GetPositionVec3()
|
|
||||||
|
|
||||||
local PositionableCoordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
-- Get the current position.
|
||||||
PositionableCoordinate:SetHeading( self:GetHeading() )
|
local Vec3 = self:GetVec3()
|
||||||
PositionableCoordinate:SetVelocity( self:GetVelocityMPS() )
|
|
||||||
|
if self.coordinate then
|
||||||
|
|
||||||
|
-- Update vector.
|
||||||
|
self.coordinate.x=Vec3.x
|
||||||
|
self.coordinate.y=Vec3.y
|
||||||
|
self.coordinate.z=Vec3.z
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- New COORDINATE.
|
||||||
|
self.coordinate=COORDINATE:NewFromVec3(Vec3)
|
||||||
|
|
||||||
self:T2( PositionableCoordinate )
|
|
||||||
return PositionableCoordinate
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self.coordinate
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Error message.
|
||||||
BASE:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return Core.Point#COORDINATE The COORDINATE of the POSITIONABLE.
|
||||||
|
function POSITIONABLE:GetCoordinate()
|
||||||
|
|
||||||
|
-- Get DCS object.
|
||||||
|
local DCSPositionable = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSPositionable then
|
||||||
|
|
||||||
|
-- Get the current position.
|
||||||
|
local PositionableVec3 = self:GetVec3()
|
||||||
|
|
||||||
|
local coord=COORDINATE:NewFromVec3(PositionableVec3)
|
||||||
|
|
||||||
|
-- Return a new coordiante object.
|
||||||
|
return coord
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Error message.
|
||||||
|
self:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns a COORDINATE object, which is offset with respect to the orientation of the POSITIONABLE.
|
--- Returns a COORDINATE object, which is offset with respect to the orientation of the POSITIONABLE.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @param #number x Offset in the direction "the nose" of the unit is pointing in meters. Default 0 m.
|
-- @param #number x Offset in the direction "the nose" of the unit is pointing in meters. Default 0 m.
|
||||||
@@ -345,8 +422,10 @@ function POSITIONABLE:GetOffsetCoordinate(x,y,z)
|
|||||||
-- Translate offset vector from map origin to the unit: v=u+a.
|
-- Translate offset vector from map origin to the unit: v=u+a.
|
||||||
local v={x=a.x+u.x, y=a.y+u.y, z=a.z+u.z}
|
local v={x=a.x+u.x, y=a.y+u.y, z=a.z+u.z}
|
||||||
|
|
||||||
|
local coord=COORDINATE:NewFromVec3(v)
|
||||||
|
|
||||||
-- Return the offset coordinate.
|
-- Return the offset coordinate.
|
||||||
return COORDINATE:NewFromVec3(v)
|
return coord
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a random @{DCS#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission.
|
--- Returns a random @{DCS#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission.
|
||||||
@@ -384,26 +463,6 @@ function POSITIONABLE:GetRandomVec3( Radius )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the @{DCS#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission.
|
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
|
||||||
-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE.
|
|
||||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
|
||||||
function POSITIONABLE:GetVec3()
|
|
||||||
self:F2( self.PositionableName )
|
|
||||||
|
|
||||||
local DCSPositionable = self:GetDCSObject()
|
|
||||||
|
|
||||||
if DCSPositionable then
|
|
||||||
local PositionableVec3 = DCSPositionable:getPosition().p
|
|
||||||
self:T3( PositionableVec3 )
|
|
||||||
return PositionableVec3
|
|
||||||
end
|
|
||||||
|
|
||||||
BASE:E( { "Cannot GetVec3", Positionable = self, Alive = self:IsAlive() } )
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Get the bounding box of the underlying POSITIONABLE DCS Object.
|
--- Get the bounding box of the underlying POSITIONABLE DCS Object.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
@@ -531,26 +590,29 @@ end
|
|||||||
|
|
||||||
--- Returns the POSITIONABLE heading in degrees.
|
--- Returns the POSITIONABLE heading in degrees.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return #number The POSITIONABLE heading
|
-- @return #number The POSITIONABLE heading in degrees or `nil` if not existing or alive.
|
||||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
|
||||||
function POSITIONABLE:GetHeading()
|
function POSITIONABLE:GetHeading()
|
||||||
|
|
||||||
local DCSPositionable = self:GetDCSObject()
|
local DCSPositionable = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSPositionable then
|
if DCSPositionable then
|
||||||
|
|
||||||
local PositionablePosition = DCSPositionable:getPosition()
|
local PositionablePosition = DCSPositionable:getPosition()
|
||||||
|
|
||||||
if PositionablePosition then
|
if PositionablePosition then
|
||||||
local PositionableHeading = math.atan2( PositionablePosition.x.z, PositionablePosition.x.x )
|
local PositionableHeading = math.atan2( PositionablePosition.x.z, PositionablePosition.x.x )
|
||||||
|
|
||||||
if PositionableHeading < 0 then
|
if PositionableHeading < 0 then
|
||||||
PositionableHeading = PositionableHeading + 2 * math.pi
|
PositionableHeading = PositionableHeading + 2 * math.pi
|
||||||
end
|
end
|
||||||
|
|
||||||
PositionableHeading = PositionableHeading * 180 / math.pi
|
PositionableHeading = PositionableHeading * 180 / math.pi
|
||||||
self:T2( PositionableHeading )
|
|
||||||
return PositionableHeading
|
return PositionableHeading
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
BASE:E( { "Cannot GetHeading", Positionable = self, Alive = self:IsAlive() } )
|
self:E({"Cannot GetHeading", Positionable = self, Alive = self:IsAlive()})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -1390,44 +1452,67 @@ do -- Cargo
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.__.CargoBayWeightLimit = Weights[Desc.typeName] or ( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) )
|
self.__.CargoBayWeightLimit = Weights[Desc.typeName] or ( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) )
|
||||||
|
elseif self:IsShip() then
|
||||||
|
local Desc = self:GetDesc()
|
||||||
|
self:F({Desc=Desc})
|
||||||
|
|
||||||
|
local Weights = {
|
||||||
|
["Type_071"] = 245000,
|
||||||
|
["LHA_Tarawa"] = 500000,
|
||||||
|
["Ropucha-class"] = 150000,
|
||||||
|
["Dry-cargo ship-1"] = 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 )
|
||||||
|
|
||||||
else
|
else
|
||||||
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
|
||||||
@@ -1533,7 +1618,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
--- Returns true if the unit is within a @{Zone}.
|
--- Returns true if the unit is within a @{Zone}.
|
||||||
-- @param #STPOSITIONABLEATIC self
|
-- @param #POSITIONABLE self
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
|
-- @param Core.Zone#ZONE_BASE Zone The zone to test.
|
||||||
-- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE}
|
-- @return #boolean Returns true if the unit is within the @{Core.Zone#ZONE_BASE}
|
||||||
function POSITIONABLE:IsInZone( Zone )
|
function POSITIONABLE:IsInZone( Zone )
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ end
|
|||||||
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
||||||
-- @param #number Heading The heading of the static respawn in degrees. Default is 0 deg.
|
-- @param #number Heading The heading of the static respawn in degrees. Default is 0 deg.
|
||||||
-- @param #number Delay Delay in seconds before the static is spawned.
|
-- @param #number Delay Delay in seconds before the static is spawned.
|
||||||
function STATIC:SpawnAt( Coordinate, Heading, Delay )
|
function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
||||||
|
|
||||||
Heading=Heading or 0
|
Heading=Heading or 0
|
||||||
|
|
||||||
@@ -202,51 +202,58 @@ function STATIC:SpawnAt( Coordinate, Heading, Delay )
|
|||||||
SCHEDULER:New(nil, self.SpawnAt, {self, Coordinate, Heading}, Delay)
|
SCHEDULER:New(nil, self.SpawnAt, {self, Coordinate, Heading}, Delay)
|
||||||
else
|
else
|
||||||
|
|
||||||
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName )
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName)
|
||||||
|
|
||||||
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Unit} at the same location with the same properties.
|
--- Respawn the @{Wrapper.Unit} at the same location with the same properties.
|
||||||
-- This is useful to respawn a cargo after it has been destroyed.
|
-- This is useful to respawn a cargo after it has been destroyed.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param DCS#country.id countryid The country ID used for spawning the new static. Default is same as currently.
|
-- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently.
|
||||||
-- @param #number Delay Delay in seconds before static is respawned.
|
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now.
|
||||||
function STATIC:ReSpawn(countryid, Delay)
|
function STATIC:ReSpawn(CountryID, Delay)
|
||||||
|
|
||||||
countryid=countryid or self:GetCountry()
|
|
||||||
|
|
||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
SCHEDULER:New(nil, self.ReSpawn, {self, countryid}, Delay)
|
SCHEDULER:New(nil, self.ReSpawn, {self, CountryID}, Delay)
|
||||||
else
|
else
|
||||||
|
|
||||||
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, countryid )
|
CountryID=CountryID or self:GetCountry()
|
||||||
|
|
||||||
SpawnStatic:ReSpawn()
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
||||||
|
|
||||||
|
SpawnStatic:Spawn(nil, self.StaticName)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading.
|
--- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
||||||
-- @param #number Heading The heading of the static respawn in degrees. Default is 0 deg.
|
-- @param #number Heading (Optional) The heading of the static respawn in degrees. Default the current heading.
|
||||||
-- @param #number Delay Delay in seconds before static is respawned.
|
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now.
|
||||||
function STATIC:ReSpawnAt( Coordinate, Heading, Delay )
|
function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
||||||
|
|
||||||
Heading=Heading or 0
|
--Heading=Heading or 0
|
||||||
|
|
||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay)
|
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay)
|
||||||
else
|
else
|
||||||
|
|
||||||
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName )
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
||||||
|
|
||||||
|
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
||||||
|
|
||||||
SpawnStatic:ReSpawnAt( Coordinate, Heading )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions: **funkyfranky**
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
|
|
||||||
--- @type UNIT
|
--- @type UNIT
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string UnitName Name of the unit.
|
||||||
-- @extends Wrapper.Controllable#CONTROLLABLE
|
-- @extends Wrapper.Controllable#CONTROLLABLE
|
||||||
|
|
||||||
--- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object.
|
--- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object.
|
||||||
@@ -61,7 +63,7 @@
|
|||||||
--
|
--
|
||||||
-- The UNIT class provides methods to obtain the current point or position of the DCS Unit.
|
-- The UNIT class provides methods to obtain the current point or position of the DCS Unit.
|
||||||
-- The @{#UNIT.GetPointVec2}(), @{#UNIT.GetVec3}() will obtain the current **location** of the DCS Unit in a Vec2 (2D) or a **point** in a Vec3 (3D) vector respectively.
|
-- The @{#UNIT.GetPointVec2}(), @{#UNIT.GetVec3}() will obtain the current **location** of the DCS Unit in a Vec2 (2D) or a **point** in a Vec3 (3D) vector respectively.
|
||||||
-- If you want to obtain the complete **3D position** including ori<EFBFBD>ntation and direction vectors, consult the @{#UNIT.GetPositionVec3}() method respectively.
|
-- If you want to obtain the complete **3D position** including orientation and direction vectors, consult the @{#UNIT.GetPositionVec3}() method respectively.
|
||||||
--
|
--
|
||||||
-- ## Test if alive
|
-- ## Test if alive
|
||||||
--
|
--
|
||||||
@@ -87,6 +89,7 @@
|
|||||||
-- @field #UNIT UNIT
|
-- @field #UNIT UNIT
|
||||||
UNIT = {
|
UNIT = {
|
||||||
ClassName="UNIT",
|
ClassName="UNIT",
|
||||||
|
UnitName=nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -103,12 +106,18 @@ UNIT = {
|
|||||||
--- Create a new UNIT from DCSUnit.
|
--- Create a new UNIT from DCSUnit.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @param #string UnitName The name of the DCS unit.
|
-- @param #string UnitName The name of the DCS unit.
|
||||||
-- @return #UNIT
|
-- @return #UNIT self
|
||||||
function UNIT:Register( UnitName )
|
function UNIT:Register( UnitName )
|
||||||
|
|
||||||
|
-- Inherit CONTROLLABLE.
|
||||||
local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) )
|
local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) )
|
||||||
|
|
||||||
|
-- Set unit name.
|
||||||
self.UnitName = UnitName
|
self.UnitName = UnitName
|
||||||
|
|
||||||
|
-- Set event prio.
|
||||||
self:SetEventPriority( 3 )
|
self:SetEventPriority( 3 )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -145,8 +154,8 @@ function UNIT:Name()
|
|||||||
return self.UnitName
|
return self.UnitName
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the DCS unit object.
|
||||||
--- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return DCS#Unit
|
-- @return DCS#Unit
|
||||||
function UNIT:GetDCSObject()
|
function UNIT:GetDCSObject()
|
||||||
|
|
||||||
@@ -258,8 +267,7 @@ end
|
|||||||
|
|
||||||
--- Returns if the unit is activated.
|
--- Returns if the unit is activated.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean true if Unit is activated.
|
-- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive.
|
||||||
-- @return #nil The DCS Unit is not existing or alive.
|
|
||||||
function UNIT:IsActive()
|
function UNIT:IsActive()
|
||||||
self:F2( self.UnitName )
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
@@ -279,9 +287,7 @@ end
|
|||||||
-- If the Unit is alive and active, true is returned.
|
-- If the Unit is alive and active, true is returned.
|
||||||
-- If the Unit is alive but not active, false is returned.
|
-- If the Unit is alive but not active, false is returned.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean true if Unit is alive and active.
|
-- @return #boolean `true` if Unit is alive and active. `false` if Unit is alive but not active. `nil` if the Unit is not existing or is not alive.
|
||||||
-- @return #boolean false if Unit is alive but not active.
|
|
||||||
-- @return #nil if the Unit is not existing or is not alive.
|
|
||||||
function UNIT:IsAlive()
|
function UNIT:IsAlive()
|
||||||
self:F3( self.UnitName )
|
self:F3( self.UnitName )
|
||||||
|
|
||||||
@@ -300,7 +306,6 @@ end
|
|||||||
--- Returns the Unit's callsign - the localized string.
|
--- Returns the Unit's callsign - the localized string.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #string The Callsign of the Unit.
|
-- @return #string The Callsign of the Unit.
|
||||||
-- @return #nil The DCS Unit is not existing or alive.
|
|
||||||
function UNIT:GetCallsign()
|
function UNIT:GetCallsign()
|
||||||
self:F2( self.UnitName )
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
@@ -377,6 +382,32 @@ function UNIT:GetPlayerName()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Checks is the unit is a *Player* or *Client* slot.
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @return #boolean If true, unit is a player or client aircraft
|
||||||
|
function UNIT:IsClient()
|
||||||
|
|
||||||
|
if _DATABASE.CLIENTS[self.UnitName] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the CLIENT of the unit
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @return Wrapper.Client#CLIENT
|
||||||
|
function UNIT:GetClient()
|
||||||
|
|
||||||
|
local client=_DATABASE.CLIENTS[self.UnitName]
|
||||||
|
|
||||||
|
if client then
|
||||||
|
return client
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the unit's number in the group.
|
--- Returns the unit's number in the group.
|
||||||
-- The number is the same number the unit has in ME.
|
-- The number is the same number the unit has in ME.
|
||||||
-- It may not be changed during the mission.
|
-- It may not be changed during the mission.
|
||||||
@@ -496,8 +527,7 @@ end
|
|||||||
|
|
||||||
--- Returns the unit's group if it exist and nil otherwise.
|
--- Returns the unit's group if it exist and nil otherwise.
|
||||||
-- @param Wrapper.Unit#UNIT self
|
-- @param Wrapper.Unit#UNIT self
|
||||||
-- @return Wrapper.Group#GROUP The Group of the Unit.
|
-- @return Wrapper.Group#GROUP The Group of the Unit or `nil` if the unit does not exist.
|
||||||
-- @return #nil The DCS Unit is not existing or alive.
|
|
||||||
function UNIT:GetGroup()
|
function UNIT:GetGroup()
|
||||||
self:F2( self.UnitName )
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
@@ -640,8 +670,7 @@ end
|
|||||||
|
|
||||||
--- Returns the unit sensors.
|
--- Returns the unit sensors.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return DCS#Unit.Sensors
|
-- @return DCS#Unit.Sensors Table of sensors.
|
||||||
-- @return #nil The DCS Unit is not existing or alive.
|
|
||||||
function UNIT:GetSensors()
|
function UNIT:GetSensors()
|
||||||
self:F2( self.UnitName )
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
@@ -661,7 +690,6 @@ end
|
|||||||
--- Returns if the unit has sensors of a certain type.
|
--- Returns if the unit has sensors of a certain type.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors.
|
-- @return #boolean returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors.
|
||||||
-- @return #nil The DCS Unit is not existing or alive.
|
|
||||||
function UNIT:HasSensors( ... )
|
function UNIT:HasSensors( ... )
|
||||||
self:F2( arg )
|
self:F2( arg )
|
||||||
|
|
||||||
@@ -678,7 +706,6 @@ end
|
|||||||
--- Returns if the unit is SEADable.
|
--- Returns if the unit is SEADable.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean returns true if the unit is SEADable.
|
-- @return #boolean returns true if the unit is SEADable.
|
||||||
-- @return #nil The DCS Unit is not existing or alive.
|
|
||||||
function UNIT:HasSEAD()
|
function UNIT:HasSEAD()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
@@ -705,7 +732,6 @@ end
|
|||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean Indicates if at least one of the unit's radar(s) is on.
|
-- @return #boolean Indicates if at least one of the unit's radar(s) is on.
|
||||||
-- @return DCS#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target.
|
-- @return DCS#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target.
|
||||||
-- @return #nil The DCS Unit is not existing or alive.
|
|
||||||
function UNIT:GetRadar()
|
function UNIT:GetRadar()
|
||||||
self:F2( self.UnitName )
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
@@ -735,6 +761,41 @@ function UNIT:GetFuel()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sets the passed group or unit objects radar emitters on or off. Can be used on sam sites for example to shut down the radar without setting AI off or changing the alarm state.
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @param #boolean Switch If `true` or `nil`, emission is enabled. If `false`, emission is turned off.
|
||||||
|
-- @return #UNIT self
|
||||||
|
function UNIT:SetEmission(Switch)
|
||||||
|
|
||||||
|
if Switch==nil then
|
||||||
|
Switch=true
|
||||||
|
end
|
||||||
|
|
||||||
|
local DCSUnit = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSUnit then
|
||||||
|
DCSUnit:enableEmission(Switch)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sets the passed group or unit objects radar emitters ON. Can be used on sam sites for example to shut down the radar without setting AI off or changing the alarm state.
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @return #UNIT self
|
||||||
|
function UNIT:EnableEmission()
|
||||||
|
self:SetEmission(true)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sets the passed group or unit objects radar emitters OFF. Can be used on sam sites for example to shut down the radar without setting AI off or changing the alarm state.
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @return #UNIT self
|
||||||
|
function UNIT:DisableEmission()
|
||||||
|
self:SetEmission(false)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns a list of one @{Wrapper.Unit}.
|
--- Returns a list of one @{Wrapper.Unit}.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #list<Wrapper.Unit#UNIT> A list of one @{Wrapper.Unit}.
|
-- @return #list<Wrapper.Unit#UNIT> A list of one @{Wrapper.Unit}.
|
||||||
@@ -1148,8 +1209,9 @@ end
|
|||||||
|
|
||||||
--- Returns true if the UNIT is in the air.
|
--- Returns true if the UNIT is in the air.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
|
-- @param #boolean NoHeloCheck If true, no additonal checks for helos are performed.
|
||||||
-- @return #boolean Return true if in the air or #nil if the UNIT is not existing or alive.
|
-- @return #boolean Return true if in the air or #nil if the UNIT is not existing or alive.
|
||||||
function UNIT:InAir()
|
function UNIT:InAir(NoHeloCheck)
|
||||||
self:F2( self.UnitName )
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
-- Get DCS unit object.
|
-- Get DCS unit object.
|
||||||
@@ -1166,7 +1228,7 @@ function UNIT:InAir()
|
|||||||
-- If DCS says that it is in air, check if this is really the case, since we might have landed on a building where inAir()=true but actually is not.
|
-- If DCS says that it is in air, check if this is really the case, since we might have landed on a building where inAir()=true but actually is not.
|
||||||
-- This is a workaround since DCS currently does not acknoledge that helos land on buildings.
|
-- This is a workaround since DCS currently does not acknoledge that helos land on buildings.
|
||||||
-- Note however, that the velocity check will fail if the ground is moving, e.g. on an aircraft carrier!
|
-- Note however, that the velocity check will fail if the ground is moving, e.g. on an aircraft carrier!
|
||||||
if UnitInAir==true and UnitCategory == Unit.Category.HELICOPTER then
|
if UnitInAir==true and UnitCategory == Unit.Category.HELICOPTER and (not NoHeloCheck) then
|
||||||
local VelocityVec3 = DCSUnit:getVelocity()
|
local VelocityVec3 = DCSUnit:getVelocity()
|
||||||
local Velocity = UTILS.VecNorm(VelocityVec3)
|
local Velocity = UTILS.VecNorm(VelocityVec3)
|
||||||
local Coordinate = DCSUnit:getPoint()
|
local Coordinate = DCSUnit:getPoint()
|
||||||
@@ -1188,23 +1250,26 @@ do -- Event Handling
|
|||||||
|
|
||||||
--- Subscribe to a DCS Event.
|
--- Subscribe to a DCS Event.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @param Core.Event#EVENTS Event
|
-- @param Core.Event#EVENTS EventID Event ID.
|
||||||
-- @param #function EventFunction (optional) The function to be called when the event occurs for the unit.
|
-- @param #function EventFunction (Optional) The function to be called when the event occurs for the unit.
|
||||||
-- @return #UNIT
|
-- @return #UNIT self
|
||||||
function UNIT:HandleEvent( Event, EventFunction )
|
function UNIT:HandleEvent(EventID, EventFunction)
|
||||||
|
|
||||||
self:EventDispatcher():OnEventForUnit( self:GetName(), EventFunction, self, Event )
|
self:EventDispatcher():OnEventForUnit(self:GetName(), EventFunction, self, EventID)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- UnSubscribe to a DCS event.
|
--- UnSubscribe to a DCS event.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @param Core.Event#EVENTS Event
|
-- @param Core.Event#EVENTS EventID Event ID.
|
||||||
-- @return #UNIT
|
-- @return #UNIT self
|
||||||
function UNIT:UnHandleEvent( Event )
|
function UNIT:UnHandleEvent(EventID)
|
||||||
|
|
||||||
self:EventDispatcher():RemoveForUnit( self:GetName(), self, Event )
|
--self:EventDispatcher():RemoveForUnit( self:GetName(), self, EventID )
|
||||||
|
|
||||||
|
-- Fixes issue #1365 https://github.com/FlightControl-Master/MOOSE/issues/1365
|
||||||
|
self:EventDispatcher():RemoveEvent(self, EventID)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1363,3 +1428,21 @@ function UNIT:GetTemplateFuel()
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- GROUND - Switch on/off radar emissions.
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @param #boolean switch
|
||||||
|
function UNIT:EnableEmission(switch)
|
||||||
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
|
local switch = switch or false
|
||||||
|
|
||||||
|
local DCSUnit = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSUnit then
|
||||||
|
|
||||||
|
DCSUnit:enableEmission(switch)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
Utilities/Enums.lua
|
||||||
Utilities/Routines.lua
|
Utilities/Routines.lua
|
||||||
Utilities/Utils.lua
|
Utilities/Utils.lua
|
||||||
|
Utilities/Enums.lua
|
||||||
|
Utilities/Profiler.lua
|
||||||
|
|
||||||
Core/Base.lua
|
Core/Base.lua
|
||||||
Core/UserFlag.lua
|
Core/UserFlag.lua
|
||||||
@@ -11,6 +14,7 @@ Core/Event.lua
|
|||||||
Core/Settings.lua
|
Core/Settings.lua
|
||||||
Core/Menu.lua
|
Core/Menu.lua
|
||||||
Core/Zone.lua
|
Core/Zone.lua
|
||||||
|
Core/Zone_Detection.lua
|
||||||
Core/Database.lua
|
Core/Database.lua
|
||||||
Core/Set.lua
|
Core/Set.lua
|
||||||
Core/Point.lua
|
Core/Point.lua
|
||||||
@@ -18,8 +22,11 @@ Core/Velocity.lua
|
|||||||
Core/Message.lua
|
Core/Message.lua
|
||||||
Core/Fsm.lua
|
Core/Fsm.lua
|
||||||
Core/Radio.lua
|
Core/Radio.lua
|
||||||
|
Core/RadioQueue.lua
|
||||||
|
Core/RadioSpeech.lua
|
||||||
Core/Spawn.lua
|
Core/Spawn.lua
|
||||||
Core/SpawnStatic.lua
|
Core/SpawnStatic.lua
|
||||||
|
Core/Timer.lua
|
||||||
Core/Goal.lua
|
Core/Goal.lua
|
||||||
Core/Spot.lua
|
Core/Spot.lua
|
||||||
|
|
||||||
@@ -33,6 +40,7 @@ Wrapper/Client.lua
|
|||||||
Wrapper/Static.lua
|
Wrapper/Static.lua
|
||||||
Wrapper/Airbase.lua
|
Wrapper/Airbase.lua
|
||||||
Wrapper/Scenery.lua
|
Wrapper/Scenery.lua
|
||||||
|
Wrapper/Marker.lua
|
||||||
|
|
||||||
Cargo/Cargo.lua
|
Cargo/Cargo.lua
|
||||||
Cargo/CargoUnit.lua
|
Cargo/CargoUnit.lua
|
||||||
@@ -48,6 +56,7 @@ Functional/Escort.lua
|
|||||||
Functional/MissileTrainer.lua
|
Functional/MissileTrainer.lua
|
||||||
Functional/ATC_Ground.lua
|
Functional/ATC_Ground.lua
|
||||||
Functional/Detection.lua
|
Functional/Detection.lua
|
||||||
|
Functional/DetectionZones.lua
|
||||||
Functional/Designate.lua
|
Functional/Designate.lua
|
||||||
Functional/RAT.lua
|
Functional/RAT.lua
|
||||||
Functional/Range.lua
|
Functional/Range.lua
|
||||||
@@ -59,6 +68,8 @@ Functional/Suppression.lua
|
|||||||
Functional/PseudoATC.lua
|
Functional/PseudoATC.lua
|
||||||
Functional/Warehouse.lua
|
Functional/Warehouse.lua
|
||||||
Functional/Fox.lua
|
Functional/Fox.lua
|
||||||
|
Functional/Mantis.lua
|
||||||
|
Functional/Shorad.lua
|
||||||
|
|
||||||
Ops/Airboss.lua
|
Ops/Airboss.lua
|
||||||
Ops/RecoveryTanker.lua
|
Ops/RecoveryTanker.lua
|
||||||
@@ -67,31 +78,35 @@ Ops/ATIS.lua
|
|||||||
|
|
||||||
AI/AI_Balancer.lua
|
AI/AI_Balancer.lua
|
||||||
AI/AI_Air.lua
|
AI/AI_Air.lua
|
||||||
AI/AI_A2A.lua
|
AI/AI_Air_Patrol.lua
|
||||||
|
AI/AI_Air_Engage.lua
|
||||||
AI/AI_A2A_Patrol.lua
|
AI/AI_A2A_Patrol.lua
|
||||||
AI/AI_A2A_Cap.lua
|
AI/AI_A2A_Cap.lua
|
||||||
AI/AI_A2A_Gci.lua
|
AI/AI_A2A_Gci.lua
|
||||||
AI/AI_A2A_Dispatcher.lua
|
AI/AI_A2A_Dispatcher.lua
|
||||||
AI/AI_A2G.lua
|
|
||||||
AI/AI_A2G_Engage.lua
|
|
||||||
AI/AI_A2G_BAI.lua
|
AI/AI_A2G_BAI.lua
|
||||||
AI/AI_A2G_CAS.lua
|
AI/AI_A2G_CAS.lua
|
||||||
AI/AI_A2G_SEAD.lua
|
AI/AI_A2G_SEAD.lua
|
||||||
AI/AI_A2G_Patrol.lua
|
|
||||||
AI/AI_A2G_Dispatcher.lua
|
AI/AI_A2G_Dispatcher.lua
|
||||||
AI/AI_Patrol.lua
|
AI/AI_Patrol.lua
|
||||||
AI/AI_Cap.lua
|
AI/AI_CAP.lua
|
||||||
AI/AI_Cas.lua
|
AI/AI_CAS.lua
|
||||||
AI/AI_Bai.lua
|
AI/AI_BAI.lua
|
||||||
AI/AI_Formation.lua
|
AI/AI_Formation.lua
|
||||||
|
AI/AI_Escort.lua
|
||||||
|
AI/AI_Escort_Request.lua
|
||||||
|
AI/AI_Escort_Dispatcher.lua
|
||||||
|
AI/AI_Escort_Dispatcher_Request.lua
|
||||||
AI/AI_Cargo.lua
|
AI/AI_Cargo.lua
|
||||||
AI/AI_Cargo_APC.lua
|
AI/AI_Cargo_APC.lua
|
||||||
AI/AI_Cargo_Helicopter.lua
|
AI/AI_Cargo_Helicopter.lua
|
||||||
AI/AI_Cargo_Airplane.lua
|
AI/AI_Cargo_Airplane.lua
|
||||||
|
AI/AI_Cargo_Ship.lua
|
||||||
AI/AI_Cargo_Dispatcher.lua
|
AI/AI_Cargo_Dispatcher.lua
|
||||||
AI/AI_Cargo_Dispatcher_APC.lua
|
AI/AI_Cargo_Dispatcher_APC.lua
|
||||||
AI/AI_Cargo_Dispatcher_Helicopter.lua
|
AI/AI_Cargo_Dispatcher_Helicopter.lua
|
||||||
AI/AI_Cargo_Dispatcher_Airplane.lua
|
AI/AI_Cargo_Dispatcher_Airplane.lua
|
||||||
|
AI/AI_Cargo_Dispatcher_Ship.lua
|
||||||
|
|
||||||
Actions/Act_Assign.lua
|
Actions/Act_Assign.lua
|
||||||
Actions/Act_Route.lua
|
Actions/Act_Route.lua
|
||||||
@@ -108,10 +123,11 @@ Tasking/Task_A2G_Dispatcher.lua
|
|||||||
Tasking/Task_A2G.lua
|
Tasking/Task_A2G.lua
|
||||||
Tasking/Task_A2A_Dispatcher.lua
|
Tasking/Task_A2A_Dispatcher.lua
|
||||||
Tasking/Task_A2A.lua
|
Tasking/Task_A2A.lua
|
||||||
Tasking/Task_Cargo.lua
|
Tasking/Task_CARGO.lua
|
||||||
Tasking/Task_Cargo_Transport.lua
|
Tasking/Task_Cargo_Transport.lua
|
||||||
Tasking/Task_Cargo_CSAR.lua
|
Tasking/Task_Cargo_CSAR.lua
|
||||||
Tasking/Task_Cargo_Dispatcher.lua
|
Tasking/Task_Cargo_Dispatcher.lua
|
||||||
Tasking/TaskZoneCapture.lua
|
Tasking/Task_Capture_Zone.lua
|
||||||
|
Tasking/Task_Capture_Dispatcher.lua
|
||||||
|
|
||||||
Globals.lua
|
Globals.lua
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -1,3 +1,5 @@
|
|||||||
|
[](https://ci.appveyor.com/project/Applevangelist/MOOSE)
|
||||||
|
|
||||||
# MOOSE framework
|
# MOOSE framework
|
||||||
|
|
||||||
MOOSE is a **M**ission **O**bject **O**riented **S**cripting **E**nvironment, and is meant for mission designers in DCS World.
|
MOOSE is a **M**ission **O**bject **O**riented **S**cripting **E**nvironment, and is meant for mission designers in DCS World.
|
||||||
@@ -51,8 +53,6 @@ This repository contains all the demonstration missions in packed format (*.miz)
|
|||||||
This repository contains all the demonstration missions in unpacked format. That means that there is no .miz file included, but all the .miz contents are unpacked.
|
This repository contains all the demonstration missions in unpacked format. That means that there is no .miz file included, but all the .miz contents are unpacked.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [MOOSE Web Site](https://flightcontrol-master.github.io/MOOSE_DOCS/)
|
## [MOOSE Web Site](https://flightcontrol-master.github.io/MOOSE_DOCS/)
|
||||||
|
|
||||||
Documentation on the MOOSE class hierarchy, usage guides and background information can be found here for normal users, beta testers and contributors.
|
Documentation on the MOOSE class hierarchy, usage guides and background information can be found here for normal users, beta testers and contributors.
|
||||||
@@ -73,18 +73,6 @@ MOOSE has a living (chat and video) community of users, beta testers and contrib
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [Please DONATE ...](https://donorbox.org/fund-github-subscriptionfor-moose)
|
|
||||||
|
|
||||||
If you appreciate this development, please support to extend the framework. The development of this framework takes a lot of time.
|
|
||||||
A small gift would help me to buy a new small laptop that I can use to extend this framework while commuting to and from work ...
|
|
||||||
Also, your donations will be saved and spent wisely to the advantage of the community!
|
|
||||||
|
|
||||||
If everyone helps with a small amount, it would be really great!
|
|
||||||
|
|
||||||
<a class="dbox-donation-button" href="https://donorbox.org/fund-github-subscriptionfor-moose" style="background:#2d81c5 url(https://raw.githubusercontent.com/FlightControl-Master/MOOSE_DOCS/master/Configuration/Donate.png) no-repeat 37px center; color: #fff;text-decoration: none;font-family: Verdana,sans-serif;display: inline-block;font-size: 16px;padding: 15px 38px 15px 75px; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; box-shadow: 0 1px 0 0 #1f5a89; text-shadow: 0 1px rgba(0, 0, 0, 0.3);" >Donate</a>
|
|
||||||
|
|
||||||
|
|
||||||
Kind regards,
|
Kind regards,
|
||||||
FlightControl (FC)
|
FlightControl (FC)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user