mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f20b830b7 | ||
|
|
0531b8f57e | ||
|
|
98e2997e26 | ||
|
|
bdec6eb82d | ||
|
|
9bdacfbcf7 | ||
|
|
be2eda25df | ||
|
|
fa8e1d2a56 | ||
|
|
5242754c60 | ||
|
|
3dbafd7a19 | ||
|
|
56e751193a | ||
|
|
b2b258cff0 | ||
|
|
75068a2a26 | ||
|
|
d82df93eff | ||
|
|
5168380eac | ||
|
|
a7ffbab850 | ||
|
|
a238294079 | ||
|
|
accb4b45fb | ||
|
|
ba4ff5c9e9 | ||
|
|
171c450576 | ||
|
|
f35078b426 | ||
|
|
8921007805 | ||
|
|
8fd3034503 | ||
|
|
a20b6e8a62 | ||
|
|
4ce6cc7776 | ||
|
|
434296ab11 | ||
|
|
a5232f49c0 | ||
|
|
befc8207f5 | ||
|
|
23947b7c30 | ||
|
|
da91b710a9 | ||
|
|
d656bbc014 | ||
|
|
ed23f11e4a | ||
|
|
068465a8f2 | ||
|
|
4e24a7bf80 | ||
|
|
1ece7238dc | ||
|
|
db53f427e3 | ||
|
|
d2e2c51275 | ||
|
|
691748082b | ||
|
|
b294ef10c8 | ||
|
|
5d40091947 | ||
|
|
7453a6c55d | ||
|
|
153ef7cd08 | ||
|
|
b6a550a247 | ||
|
|
3568f27150 | ||
|
|
c46061466c | ||
|
|
9c7b5e8506 | ||
|
|
b11df6b523 | ||
|
|
66dcd44fb8 | ||
|
|
f35237f86f | ||
|
|
f19c877a11 | ||
|
|
792a487eeb | ||
|
|
f5e8bd0ffc | ||
|
|
cbdbf36f32 | ||
|
|
1116b19b00 | ||
|
|
edb490fa97 | ||
|
|
9fa16c6385 | ||
|
|
a0ee957493 | ||
|
|
f32c303c0a | ||
|
|
6febbbc8e6 | ||
|
|
d5aa9eaf0f | ||
|
|
321b2d761d | ||
|
|
18581e4a78 | ||
|
|
b03905154d | ||
|
|
2fda1709bc | ||
|
|
39f626390a | ||
|
|
aa1e12163d | ||
|
|
abb7f860ae | ||
|
|
cffada1a1e | ||
|
|
f8d91798e3 | ||
|
|
548aa8d5a9 | ||
|
|
1e929d1d19 | ||
|
|
d5f215505e | ||
|
|
851660c793 | ||
|
|
ee57b46c14 | ||
|
|
36eac9fccc | ||
|
|
1f630ab490 | ||
|
|
8f0c6948ac | ||
|
|
eb2380c3f6 | ||
|
|
df3e182de4 | ||
|
|
bda7988118 | ||
|
|
72deb9ee17 | ||
|
|
ced1f30f3f | ||
|
|
47c0006537 | ||
|
|
21e5c124c0 | ||
|
|
3ff374e1b9 | ||
|
|
02000be9af | ||
|
|
663c6cead0 | ||
|
|
6867df58c4 | ||
|
|
639625d3d5 | ||
|
|
0ace200e5a | ||
|
|
e76c26ff59 | ||
|
|
cb11de6f9c | ||
|
|
cdd78e5163 | ||
|
|
a8da02774a | ||
|
|
04258a69c4 | ||
|
|
49882f03d9 |
@@ -1953,7 +1953,7 @@ local function refct_from_id(id) -- refct = refct_from_id(CTypeID)
|
|||||||
unsigned = refct.unsigned,
|
unsigned = refct.unsigned,
|
||||||
size = bit.band(bit.rshift(ctype.info, 16), 127),
|
size = bit.band(bit.rshift(ctype.info, 16), 127),
|
||||||
}
|
}
|
||||||
refct.bool, refct.const, refct.volatile, refct.unsigned = nil, nil, nil, nil
|
refct.bool, refct.const, refct.volatile, refct.unsigned = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if CT[4] then -- Merge sibling attributes onto this type.
|
if CT[4] then -- Merge sibling attributes onto this type.
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
--- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
--- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
|
-- The AI_A2A_CAP is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_CAP process can be started using the **Start** event.
|
||||||
|
|||||||
@@ -33,8 +33,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
-- There are basically two classes available to model an A2A defense system.
|
-- There are basically two classes available to model an A2A defense system.
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
-- The AI_A2A_GCI is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_GCI process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
|
-- The AI_A2A_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_A2A_PATROL process can be started using the **Start** event.
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
--
|
--
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The following class is available to model an A2G defense system.
|
-- The following class is available to model an A2G defense system.
|
||||||
--
|
--
|
||||||
-- AI_A2G_DISPATCHER is the main A2G defense class that models the A2G defense system.
|
-- AI_A2G_DISPATCHER is the main A2G defense class that models the A2G defense system.
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
|
|
||||||
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to SEAD intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event.
|
-- The AI_A2G_SEAD is assigned a @{Wrapper.Group} and this must be done before the AI_A2G_SEAD process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
--
|
||||||
-- # 1) AI_AIR constructor
|
-- # 1) AI_AIR constructor
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
--
|
--
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The following class is available to model an AIR defense system.
|
-- The following class is available to model an AIR defense system.
|
||||||
--
|
--
|
||||||
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
|
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
|
||||||
|
|||||||
@@ -13,14 +13,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_AIR_ENGAGE
|
-- @type AI_AIR_ENGAGE
|
||||||
-- @extends AI.AI_AIR#AI_AIR
|
-- @extends AI.AI_AIR#AI_AIR
|
||||||
|
|
||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event.
|
-- The AI_AIR_ENGAGE is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_ENGAGE process can be started using the **Start** event.
|
||||||
--
|
--
|
||||||
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
-- The AI will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group}
|
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group}
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event.
|
-- The AI_AIR_PATROL is assigned a @{Wrapper.Group} and this must be done before the AI_AIR_PATROL process can be started using the **Start** event.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_AIR_SQUADRON
|
-- @type AI_AIR_SQUADRON
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -21,8 +21,6 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -38,8 +38,6 @@
|
|||||||
|
|
||||||
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
|
|||||||
@@ -33,9 +33,8 @@
|
|||||||
-- @field Wrapper.Group#GROUP Test
|
-- @field Wrapper.Group#GROUP Test
|
||||||
-- @extends Core.Fsm#FSM_SET
|
-- @extends Core.Fsm#FSM_SET
|
||||||
|
|
||||||
--- 
|
|
||||||
--
|
--- Monitors and manages as many replacement AI groups as there are
|
||||||
-- Monitors and manages as many replacement AI groups as there are
|
|
||||||
-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players.
|
-- CLIENTS in a SET\_CLIENT collection, which are not occupied by human players.
|
||||||
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -39,8 +39,6 @@
|
|||||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
|
-- The AI_CAP_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_CAP_ZONE process can be started using the **Start** event.
|
||||||
|
|||||||
@@ -38,9 +38,6 @@
|
|||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
--- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
|
|||||||
@@ -9,14 +9,12 @@
|
|||||||
-- @module AI.AI_Cargo
|
-- @module AI.AI_Cargo
|
||||||
-- @image Cargo.JPG
|
-- @image Cargo.JPG
|
||||||
|
|
||||||
--- @type AI_CARGO
|
-- @type AI_CARGO
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
|
|
||||||
--- Base class for the dynamic cargo handling capability for AI groups.
|
--- Base class for the dynamic cargo handling capability for AI groups.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
-- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
-- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo.
|
-- CARGO derived objects must be declared within the mission to make the AI_CARGO object recognize the cargo.
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI vehicle group.
|
--- Brings a dynamic cargo handling capability for an AI vehicle group.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI airplane group.
|
--- Brings a dynamic cargo handling capability for an AI airplane group.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases.
|
-- Airplane carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation between airbases.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_AIRPLANE module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO_AIRPLANE module uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # The dispatcher concept.
|
-- # The dispatcher concept.
|
||||||
--
|
--
|
||||||
-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
|
|
||||||
--- A dynamic cargo transportation capability for AI groups.
|
--- A dynamic cargo transportation capability for AI groups.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Armoured Personnel APCs (APC), Trucks, Jeeps and other carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module.
|
-- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for AI groups.
|
--- Brings a dynamic cargo handling capability for AI groups.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_DISPATCHER_AIRPLANE module is derived from the AI_CARGO_DISPATCHER module.
|
-- The AI_CARGO_DISPATCHER_AIRPLANE module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
|
|
||||||
--- A dynamic cargo handling capability for AI helicopter groups.
|
--- A dynamic cargo handling capability for AI helicopter groups.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -29,8 +29,6 @@
|
|||||||
|
|
||||||
--- A dynamic cargo transportation capability for AI groups.
|
--- A dynamic cargo transportation capability for AI groups.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation.
|
-- 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.
|
-- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module.
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI helicopter group.
|
--- Brings a dynamic cargo handling capability for an AI helicopter group.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
-- Helicopter carriers can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
|
|
||||||
--- Brings a dynamic cargo handling capability for an AI naval group.
|
--- 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.
|
-- 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.
|
-- 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.
|
-- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo.
|
||||||
|
|||||||
@@ -25,8 +25,6 @@
|
|||||||
--
|
--
|
||||||
-- Allows you to interact with escorting AI on your flight and take the lead.
|
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
||||||
--
|
--
|
||||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||||
|
|||||||
@@ -23,8 +23,6 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
|
|
||||||
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
|
|||||||
@@ -25,8 +25,6 @@
|
|||||||
--
|
--
|
||||||
-- Allows you to interact with escorting AI on your flight and take the lead.
|
-- Allows you to interact with escorting AI on your flight and take the lead.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
-- Each escorting group can be commanded with a complete set of radio commands (radio menu in your flight, and then F10).
|
||||||
--
|
--
|
||||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||||
|
|||||||
@@ -41,8 +41,6 @@
|
|||||||
|
|
||||||
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions.
|
-- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions.
|
||||||
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
||||||
-- The purpose of the class is to:
|
-- The purpose of the class is to:
|
||||||
|
|||||||
@@ -48,8 +48,6 @@
|
|||||||
|
|
||||||
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
|
-- The AI_PATROL_ZONE is assigned a @{Wrapper.Group} and this must be done before the AI_PATROL_ZONE process can be started using the **Start** event.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -11,8 +11,6 @@ do -- ACT_ACCOUNT
|
|||||||
|
|
||||||
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ## ACT_ACCOUNT state machine:
|
-- ## ACT_ACCOUNT state machine:
|
||||||
--
|
--
|
||||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||||
@@ -135,7 +133,7 @@ do -- ACT_ACCOUNT
|
|||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To )
|
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event )
|
||||||
|
|
||||||
self:__NoMore( 1 )
|
self:__NoMore( 1 )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
-- ## ACT_ASSIGN state machine:
|
-- ## ACT_ASSIGN state machine:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
-- ## ACT_ASSIST state machine:
|
-- ## ACT_ASSIST state machine:
|
||||||
--
|
--
|
||||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||||
--
|
--
|
||||||
-- ## ACT_ROUTE state machine:
|
-- ## ACT_ROUTE state machine:
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # 1) MOOSE Cargo System.
|
-- # 1) MOOSE Cargo System.
|
||||||
--
|
--
|
||||||
-- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities.
|
-- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities.
|
||||||
|
|||||||
@@ -22,9 +22,6 @@ do -- CARGO_CRATE
|
|||||||
-- @type CARGO_CRATE
|
-- @type CARGO_CRATE
|
||||||
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
|
-- @extends Cargo.Cargo#CARGO_REPRESENTABLE
|
||||||
|
|
||||||
---
|
|
||||||
-- 
|
|
||||||
--
|
|
||||||
--- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
|
--- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier.
|
||||||
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
|
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ do -- CARGO_GROUP
|
|||||||
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
||||||
|
|
||||||
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
|
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
|
||||||
--
|
|
||||||
-- 
|
|
||||||
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
|
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
|
||||||
--
|
--
|
||||||
-- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
-- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ do -- CARGO_SLINGLOAD
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ do -- CARGO_UNIT
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -157,6 +157,8 @@ ASTAR = {
|
|||||||
-- @field #number surfacetype Surface type.
|
-- @field #number surfacetype Surface type.
|
||||||
-- @field #table valid Cached valid/invalid nodes.
|
-- @field #table valid Cached valid/invalid nodes.
|
||||||
-- @field #table cost Cached cost.
|
-- @field #table cost Cached cost.
|
||||||
|
-- @field Core.Pathline#PATHLINE pathline Pathline that node is part of.
|
||||||
|
-- @field Core.Pathline#PATHLINE.Point pathpoint Pathline point.
|
||||||
|
|
||||||
--- ASTAR infinity.
|
--- ASTAR infinity.
|
||||||
-- @field #number INF
|
-- @field #number INF
|
||||||
@@ -164,7 +166,7 @@ ASTAR.INF=1/0
|
|||||||
|
|
||||||
--- ASTAR class version.
|
--- ASTAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ASTAR.version="0.4.0"
|
ASTAR.version="0.5.0"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -172,6 +174,7 @@ ASTAR.version="0.4.0"
|
|||||||
|
|
||||||
-- TODO: Add more valid neighbour functions.
|
-- TODO: Add more valid neighbour functions.
|
||||||
-- TODO: Write docs.
|
-- TODO: Write docs.
|
||||||
|
-- DONE: Add pathlines for seach/valid neighbours.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
@@ -246,6 +249,9 @@ function ASTAR:AddNode(Node)
|
|||||||
self.nodes[Node.id]=Node
|
self.nodes[Node.id]=Node
|
||||||
self.Nnodes=self.Nnodes+1
|
self.Nnodes=self.Nnodes+1
|
||||||
|
|
||||||
|
self:T3(self.lid..string.format("Adding node UID=%d", Node.id))
|
||||||
|
--Node.coordinate:MarkToAll(string.format("Node ID=%d", Node.id))
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -262,6 +268,47 @@ function ASTAR:AddNodeFromCoordinate(Coordinate)
|
|||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Adds nodes to the table of grid nodes from a PATHLINE.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Pathline#PATHLINE Pathline Pathline or name of pathline. Has to exist.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:AddNodeFromPathlineName(Pathline)
|
||||||
|
|
||||||
|
if type(Pathline)=="string" then
|
||||||
|
Pathline=PATHLINE:FindByName(Pathline)
|
||||||
|
end
|
||||||
|
|
||||||
|
if Pathline then
|
||||||
|
|
||||||
|
for i,_point in pairs(Pathline.points) do
|
||||||
|
local point=_point --Core.Pathline#PATHLINE.Point
|
||||||
|
|
||||||
|
-- Create node from point coordinate.
|
||||||
|
local node=self:AddNodeFromCoordinate(COORDINATE:NewFromVec3(point.vec3))
|
||||||
|
|
||||||
|
-- Add pathline parameters.
|
||||||
|
node.pathline=Pathline
|
||||||
|
node.pathpoint=point
|
||||||
|
|
||||||
|
-- Debug.
|
||||||
|
local name=node.pathline and node.pathline.name or "N/A"
|
||||||
|
local idx=node.pathline and node.pathline:_GetPointIndex(node.pathpoint) or "N/A"
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
self:T(self.lid..string.format("Adding node UID=%d pathline=%s [%s]", node.id, name, tostring(idx)))
|
||||||
|
|
||||||
|
-- Debug mark
|
||||||
|
--node.coordinate:MarkToAll(string.format("Node ID=%d\npathline=%s [%s]", node.id, name, tostring(idx)))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
env.error("FF error pathline")
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if the coordinate of a node has is at a valid surface type.
|
--- Check if the coordinate of a node has is at a valid surface type.
|
||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
-- @param #ASTAR.Node Node The node to be added.
|
-- @param #ASTAR.Node Node The node to be added.
|
||||||
@@ -340,6 +387,18 @@ function ASTAR:SetValidNeighbourRoad(MaxDistance)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set valid neighbours to be on the same pathline or not further apart than 10 meters to jump from one pathline to another.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #number MaxDistance Max allowed distance between nodes of different pathlines in meters. Default is 10 m.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourPathline(MaxDistance)
|
||||||
|
|
||||||
|
self:SetValidNeighbourFunction(ASTAR.Pathline, MaxDistance)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the function which calculates the "cost" to go from one to another node.
|
--- Set the function which calculates the "cost" to go from one to another node.
|
||||||
-- The first to arguments of this function are always the two nodes under consideration. But you can add optional arguments.
|
-- The first to arguments of this function are always the two nodes under consideration. But you can add optional arguments.
|
||||||
-- Very often the distance between nodes is a good measure for the cost.
|
-- Very often the distance between nodes is a good measure for the cost.
|
||||||
@@ -384,7 +443,7 @@ end
|
|||||||
-- @return #ASTAR self
|
-- @return #ASTAR self
|
||||||
function ASTAR:SetCostRoad()
|
function ASTAR:SetCostRoad()
|
||||||
|
|
||||||
self:SetCostFunction(ASTAR)
|
self:SetCostFunction(ASTAR.Road)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -544,6 +603,55 @@ function ASTAR.Road(nodeA, nodeB)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function to check if two nodes are on the same pathline or if nodes are less than 10 meters apart.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @param #number distmax Max distance in meters. Default is 10 m.
|
||||||
|
-- @return #boolean If true, two nodes are connected.
|
||||||
|
function ASTAR.Pathline(nodeA, nodeB, distmax)
|
||||||
|
|
||||||
|
distmax=distmax or 10
|
||||||
|
|
||||||
|
if nodeA.pathline.name==nodeB.pathline.name then
|
||||||
|
|
||||||
|
-- Nodes are on the same pathline. We use the index to check if they are neighbours.
|
||||||
|
|
||||||
|
local pathline=nodeA.pathline
|
||||||
|
|
||||||
|
local idxA=pathline:_GetPointIndex(nodeA.pathpoint)
|
||||||
|
local idxB=pathline:_GetPointIndex(nodeB.pathpoint)
|
||||||
|
|
||||||
|
if math.abs(idxA-idxB)<=1 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Check if nodeB is close to pathline of nodeA.
|
||||||
|
local c, dist, segA=nodeA.pathline:GetClosestPoint3D(nodeB.coordinate)
|
||||||
|
local seg=segA --Core.Pathline#PATHLINE.Segment
|
||||||
|
|
||||||
|
if dist<distmax and (nodeA.pathpoint.uid==seg.p1.uid or nodeA.pathpoint.uid==seg.p2.uid) then
|
||||||
|
--env.info(string.format("FF NodeB=%d [pathline=%s] is close to NodeA=%d [pathline=%s] ==> valid neighbour", nodeB.id, nodeB.pathline.name, nodeA.id, nodeA.pathline.name))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Check if nodeA is close to pathline of nodeB.
|
||||||
|
local c, dist, segB=nodeB.pathline:GetClosestPoint3D(nodeA.coordinate)
|
||||||
|
local seg=segB --Core.Pathline#PATHLINE.Segment
|
||||||
|
|
||||||
|
if dist<distmax and (nodeB.pathpoint.uid==seg.p1.uid or nodeB.pathpoint.uid==seg.p2.uid) then
|
||||||
|
--env.info(string.format("FF NodeA=%d [pathline=%s] is close to NodeB=%d [pathline=%s] ==> valid neighbour", nodeA.id, nodeA.pathline.name, nodeB.id, nodeB.pathline.name))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Function to check if distance between two nodes is less than a threshold distance.
|
--- Function to check if distance between two nodes is less than a threshold distance.
|
||||||
-- @param #ASTAR.Node nodeA First node.
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
-- @param #ASTAR.Node nodeB Other node.
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
@@ -567,7 +675,9 @@ end
|
|||||||
-- @param #ASTAR.Node nodeB Other node.
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
-- @return #number Distance between the two nodes.
|
-- @return #number Distance between the two nodes.
|
||||||
function ASTAR.Dist2D(nodeA, nodeB)
|
function ASTAR.Dist2D(nodeA, nodeB)
|
||||||
local dist=nodeA.coordinate:Get2DDistance(nodeB)
|
local dist=nodeA.coordinate:Get2DDistance(nodeB.coordinate)
|
||||||
|
--local text=string.format("FF Cost Dist2D NodeA=%d-->NodeB=%d = %.1f", nodeA.id, nodeB.id, dist)
|
||||||
|
--env.info(text)
|
||||||
return dist
|
return dist
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -604,7 +714,6 @@ function ASTAR.DistRoad(nodeA, nodeB)
|
|||||||
return dist
|
return dist
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return math.huge
|
return math.huge
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -614,10 +723,11 @@ end
|
|||||||
|
|
||||||
--- Find the closest node from a given coordinate.
|
--- Find the closest node from a given coordinate.
|
||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
-- @param Core.Point#COORDINATE Coordinate.
|
-- @param Core.Point#COORDINATE Coordinate Reference coordinate.
|
||||||
-- @return #ASTAR.Node Cloest node to the coordinate.
|
-- @param #table ExcludeNodes Table of nodes that are excluded.
|
||||||
|
-- @return #ASTAR.Node Closest node to the coordinate.
|
||||||
-- @return #number Distance to closest node in meters.
|
-- @return #number Distance to closest node in meters.
|
||||||
function ASTAR:FindClosestNode(Coordinate)
|
function ASTAR:FindClosestNode(Coordinate, ExcludeNodes)
|
||||||
|
|
||||||
local distMin=math.huge
|
local distMin=math.huge
|
||||||
local closeNode=nil
|
local closeNode=nil
|
||||||
@@ -625,6 +735,8 @@ function ASTAR:FindClosestNode(Coordinate)
|
|||||||
for _,_node in pairs(self.nodes) do
|
for _,_node in pairs(self.nodes) do
|
||||||
local node=_node --#ASTAR.Node
|
local node=_node --#ASTAR.Node
|
||||||
|
|
||||||
|
if ExcludeNodes==nil or self:_IsNodeNotInTable(ExcludeNodes, node) then
|
||||||
|
|
||||||
local dist=node.coordinate:Get2DDistance(Coordinate)
|
local dist=node.coordinate:Get2DDistance(Coordinate)
|
||||||
|
|
||||||
if dist<distMin then
|
if dist<distMin then
|
||||||
@@ -634,42 +746,168 @@ function ASTAR:FindClosestNode(Coordinate)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
return closeNode, distMin
|
return closeNode, distMin
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Find the closest pathline to a given reference coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Reference coordinate.
|
||||||
|
-- @return Core.Pathline#PATHLINE Closest pathline
|
||||||
|
-- @return #number Distance in meters.
|
||||||
|
-- @return DCS#Vec3 Closest point on pathline to the ref coordinate.
|
||||||
|
-- @return Core.Pathline#PATHLINE.Segment Segment.
|
||||||
|
function ASTAR:FindClosestPathline(Coordinate)
|
||||||
|
|
||||||
|
local pathline=nil --Core.Pathline#PATHLINE
|
||||||
|
local dist=math.huge
|
||||||
|
local vec3=nil
|
||||||
|
local S=nil
|
||||||
|
|
||||||
|
for _,_node in pairs(self.nodes) do
|
||||||
|
local node=_node --#ASTAR.Node
|
||||||
|
|
||||||
|
if node.pathline then
|
||||||
|
|
||||||
|
local vec, d, s=node.pathline:GetClosestPoint3D(Coordinate)
|
||||||
|
|
||||||
|
if d<dist then
|
||||||
|
pathline=node.pathline
|
||||||
|
dist=d
|
||||||
|
vec3=vec
|
||||||
|
S=s
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if pathline then
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Closest pathline %s: dist=%.1f", pathline.name, dist))
|
||||||
|
end
|
||||||
|
|
||||||
|
return pathline, dist, vec3, S
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find the closest node to the given coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coord Reference coordinate.
|
||||||
|
-- @param #table ExcludeNodes Nodes that are excluded.
|
||||||
|
-- @return #ASTAR.Node The node that was fround
|
||||||
|
function ASTAR:_FindClosestTerminalNode(Coord, ExcludeNodes)
|
||||||
|
|
||||||
|
-- Find the closest pathline to the ref coordinate.
|
||||||
|
local pathline, dist, vec3, s=self:FindClosestPathline(Coord)
|
||||||
|
|
||||||
|
-- Find the closest node to the given start coordinate.
|
||||||
|
local node, dist2=self:FindClosestNode(Coord)
|
||||||
|
|
||||||
|
if pathline and vec3 and dist and dist2>dist then
|
||||||
|
|
||||||
|
-- Create a node on the closest pathline so we first go straight there and then along the pathline.
|
||||||
|
local node=self:AddNodeFromCoordinate(COORDINATE:NewFromVec3(vec3))
|
||||||
|
|
||||||
|
-- We also need the pathline point.
|
||||||
|
local point=pathline:AddPointFromVec3(vec3, nil, s.p1)
|
||||||
|
|
||||||
|
node.pathline=pathline
|
||||||
|
node.pathpoint=point
|
||||||
|
|
||||||
|
self:T2(self.lid..string.format("Added new node=%d, which is closest to start coord. dist=%.1f m", node.id, dist))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Find the closest node to the given start coordinate.
|
||||||
|
local Node, dist3=self:FindClosestNode(Coord, ExcludeNodes)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("CLOSEST node ID=%d, distance=%.1f", Node.id, dist3))
|
||||||
|
|
||||||
|
return Node, dist3
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Find the start node.
|
--- Find the start node.
|
||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
|
||||||
-- @return #ASTAR self
|
-- @return #ASTAR self
|
||||||
function ASTAR:FindStartNode()
|
function ASTAR:FindStartNode()
|
||||||
|
|
||||||
local node, dist=self:FindClosestNode(self.startCoord)
|
-- Find the closest pathline to the
|
||||||
|
local pathline, dist, vec3, s=self:FindClosestPathline(self.startCoord)
|
||||||
|
|
||||||
self.startNode=node
|
-- Find the closest node to the given start coordinate.
|
||||||
|
local node, dist2=self:FindClosestNode(self.startCoord)
|
||||||
|
|
||||||
if dist>1000 then
|
if pathline and vec3 and dist and dist2>dist then
|
||||||
self:T(self.lid.."Adding start node to node grid!")
|
|
||||||
self:AddNode(node)
|
-- Create a node on the closest pathline so we first go straight there and then along the pathline.
|
||||||
|
local node=self:AddNodeFromCoordinate(COORDINATE:NewFromVec3(vec3))
|
||||||
|
|
||||||
|
-- We also need the pathline point.
|
||||||
|
local point=pathline:AddPointFromVec3(vec3, nil, s.p1)
|
||||||
|
|
||||||
|
node.pathline=pathline
|
||||||
|
node.pathpoint=point
|
||||||
|
|
||||||
|
self:T2(self.lid..string.format("Added new node=%d, which is closest to start coord. dist=%.1f m", node.id, dist))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Find the closest node to the given start coordinate.
|
||||||
|
self.startNode, dist2=self:FindClosestNode(self.startCoord)
|
||||||
|
|
||||||
|
--self.startNode.coordinate:MarkToAll("Start Node")
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("START node ID=%d", self.startNode.id))
|
||||||
|
|
||||||
|
-- Not sure why I did this. The node does not need to be added again as it is already contained in self.nodes!
|
||||||
|
-- if dist>1000 then
|
||||||
|
-- self:T(self.lid.."Adding start node to node grid!")
|
||||||
|
-- self:AddNode(node)
|
||||||
|
-- end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a node.
|
--- Find the end node.
|
||||||
-- @param #ASTAR self
|
-- @param #ASTAR self
|
||||||
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
|
||||||
-- @return #ASTAR self
|
-- @return #ASTAR self
|
||||||
function ASTAR:FindEndNode()
|
function ASTAR:FindEndNode()
|
||||||
|
|
||||||
local node, dist=self:FindClosestNode(self.endCoord)
|
local pathline, dist, vec3, s=self:FindClosestPathline(self.endCoord)
|
||||||
|
|
||||||
self.endNode=node
|
-- Find the closest node to the given start coordinate.
|
||||||
|
local node, dist2=self:FindClosestNode(self.endCoord)
|
||||||
|
|
||||||
if dist>1000 then
|
if pathline and vec3 and dist and dist2>dist then
|
||||||
self:T(self.lid.."Adding end node to node grid!")
|
|
||||||
self:AddNode(node)
|
-- Create a node on the closest pathline so we first go straight there and then along the pathline.
|
||||||
|
local node=self:AddNodeFromCoordinate(COORDINATE:NewFromVec3(vec3))
|
||||||
|
|
||||||
|
-- We also need the point.
|
||||||
|
local point=pathline:AddPointFromVec3(vec3, nil, s.p1)
|
||||||
|
|
||||||
|
-- Add pathline parameters to node.
|
||||||
|
node.pathline=pathline
|
||||||
|
node.pathpoint=point
|
||||||
|
|
||||||
|
self:T2(self.lid..string.format("Added new node=%d, which is closest to END coord: dist=%.1f m", node.id, dist))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Find closest node to the end coordinate (exclude the start coordinate.
|
||||||
|
self.endNode, dist=self:FindClosestNode(self.endCoord, {self.startNode})
|
||||||
|
|
||||||
|
--self.endNode.coordinate:MarkToAll("End Node")
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("END node ID=%d", self.endNode.id))
|
||||||
|
|
||||||
|
-- Not sure why I did this. The node does not need to be added again as it is already contained in self.nodes!
|
||||||
|
-- if dist>1000 then
|
||||||
|
-- self:T(self.lid.."Adding end node to node grid!")
|
||||||
|
-- self:AddNode(node)
|
||||||
|
-- end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -684,13 +922,22 @@ end
|
|||||||
-- @return #table Table of nodes from start to finish.
|
-- @return #table Table of nodes from start to finish.
|
||||||
function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||||
|
|
||||||
self:FindStartNode()
|
-- self:FindStartNode()
|
||||||
self:FindEndNode()
|
-- self:FindEndNode()
|
||||||
|
|
||||||
|
-- Find start Node (closest node to start coordinate).
|
||||||
|
self.startNode=self:_FindClosestTerminalNode(self.startCoord)
|
||||||
|
|
||||||
|
-- Find end node, which is not the start node (excluded).
|
||||||
|
self.endNode=self:_FindClosestTerminalNode(self.endCoord, {self.startNode})
|
||||||
|
|
||||||
local nodes=self.nodes
|
local nodes=self.nodes
|
||||||
local start=self.startNode
|
local start=self.startNode
|
||||||
local goal=self.endNode
|
local goal=self.endNode
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("GetPath Start Node=%d, End Node=%d", start.id, goal.id))
|
||||||
|
|
||||||
-- Sets.
|
-- Sets.
|
||||||
local openset = {}
|
local openset = {}
|
||||||
local closedset = {}
|
local closedset = {}
|
||||||
@@ -747,6 +994,11 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
|||||||
end
|
end
|
||||||
text=text..string.format(", Nvalid=%d [%d cached]", self.nvalid, self.nvalidcache)
|
text=text..string.format(", Nvalid=%d [%d cached]", self.nvalid, self.nvalidcache)
|
||||||
text=text..string.format(", Ncost=%d [%d cached]", self.ncost, self.ncostcache)
|
text=text..string.format(", Ncost=%d [%d cached]", self.ncost, self.ncostcache)
|
||||||
|
text=text..string.format("\nNodes:")
|
||||||
|
for i,_node in ipairs(path) do
|
||||||
|
local node=_node --#ASTAR.Node
|
||||||
|
text=text..string.format("\n[%d] Node ID=%d", i, node.id)
|
||||||
|
end
|
||||||
self:T(self.lid..text)
|
self:T(self.lid..text)
|
||||||
|
|
||||||
return path
|
return path
|
||||||
@@ -763,9 +1015,12 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
|||||||
-- Loop over neighbours.
|
-- Loop over neighbours.
|
||||||
for _,neighbor in pairs(neighbors) do
|
for _,neighbor in pairs(neighbors) do
|
||||||
|
|
||||||
|
-- Node is not in closed set.
|
||||||
if self:_NotIn(closedset, neighbor.id) then
|
if self:_NotIn(closedset, neighbor.id) then
|
||||||
|
|
||||||
local tentative_g_score=g_score[current.id]+self:_DistNodes(current, neighbor)
|
-- Calculate tentative_g_score.
|
||||||
|
--local tentative_g_score=g_score[current.id] + self:_DistNodes(current, neighbor)
|
||||||
|
local tentative_g_score=g_score[current.id] + self:_HeuristicCost(current, neighbor)
|
||||||
|
|
||||||
if self:_NotIn(openset, neighbor.id) or tentative_g_score < g_score[neighbor.id] then
|
if self:_NotIn(openset, neighbor.id) or tentative_g_score < g_score[neighbor.id] then
|
||||||
|
|
||||||
@@ -793,6 +1048,73 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
|||||||
return nil -- no valid path
|
return nil -- no valid path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- A* pathfinding function. This seaches the path along nodes between start and end nodes/coordinates.
|
||||||
|
-- It automatically creates a PATHLINE object that is returned in combination with the nodes of the optimal path.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #boolean ExcludeStartNode If *true*, do not include start node in found path. Default is to include it.
|
||||||
|
-- @param #boolean ExcludeEndNode If *true*, do not include end node in found path. Default is to include it.
|
||||||
|
-- @return Core.Pathline#PATHLINE Pathline.
|
||||||
|
-- @return #table Nodes of path.
|
||||||
|
function ASTAR:GetPathline(ExcludeStartNode, ExcludeEndNode)
|
||||||
|
|
||||||
|
local nodes=self:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||||
|
|
||||||
|
local pathline=nil --Core.Pathline#PATHLINE
|
||||||
|
if nodes then
|
||||||
|
|
||||||
|
pathline=PATHLINE:New("Astar")
|
||||||
|
|
||||||
|
for _,_node in pairs(nodes) do
|
||||||
|
local node=_node --#ASTAR.Node
|
||||||
|
|
||||||
|
local point=pathline:AddPointFromVec3(node.coordinate)
|
||||||
|
point.name=node.pathline.name
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return pathline, nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get pathlines from nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table Nodes Given nodes.
|
||||||
|
-- @return #table Table of PATHLINES used in the path.
|
||||||
|
function ASTAR:GetPathlinesFromNodes(Nodes)
|
||||||
|
|
||||||
|
local pathlines={}
|
||||||
|
|
||||||
|
--for _,_node in pairs(Nodes or {}) do
|
||||||
|
for i=1,#Nodes do
|
||||||
|
local node=Nodes[i] --#ASTAR.Node
|
||||||
|
|
||||||
|
-- Pathline.
|
||||||
|
local pathline=node.pathline
|
||||||
|
|
||||||
|
if pathline and i>1 and i<#Nodes then
|
||||||
|
|
||||||
|
-- Previous and next nodes.
|
||||||
|
local n=Nodes[i-1] --#ASTAR.Node
|
||||||
|
local N=Nodes[i+1] --#ASTAR.Node
|
||||||
|
|
||||||
|
-- Check if previous and next nodes are on the same pathline.
|
||||||
|
-- If only one point in beteen is of another pathline, this is a junction and we dont actually switch to the other pathline.
|
||||||
|
if n.pathline and N.pathline and n.pathline.name==N.pathline.name and n.pathline.name~=pathline.name then
|
||||||
|
pathline=n.pathline
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We do not want to add the same pathline two times in a row.
|
||||||
|
if #pathlines==0 or (#pathlines>0 and pathlines[#pathlines].name~=pathline.name) then
|
||||||
|
table.insert(pathlines, pathline)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return pathlines
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- A* pathfinding helper functions
|
-- A* pathfinding helper functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -811,16 +1133,18 @@ function ASTAR:_HeuristicCost(nodeA, nodeB)
|
|||||||
local cost=nodeA.cost[nodeB.id]
|
local cost=nodeA.cost[nodeB.id]
|
||||||
if cost~=nil then
|
if cost~=nil then
|
||||||
self.ncostcache=self.ncostcache+1
|
self.ncostcache=self.ncostcache+1
|
||||||
|
self:T(self.lid..string.format("Cost nodeA=%d --> nodeB=%d = %.1f (Cashed!)", nodeA.id, nodeB.id, cost))
|
||||||
return cost
|
return cost
|
||||||
end
|
end
|
||||||
|
|
||||||
local cost=nil
|
|
||||||
if self.CostFunc then
|
if self.CostFunc then
|
||||||
cost=self.CostFunc(nodeA, nodeB, unpack(self.CostArg))
|
cost=self.CostFunc(nodeA, nodeB, unpack(self.CostArg))
|
||||||
else
|
else
|
||||||
cost=self:_DistNodes(nodeA, nodeB)
|
cost=self:_DistNodes(nodeA, nodeB)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:T(self.lid..string.format("Cost nodeA=%d --> nodeB=%d = %.1f", nodeA.id, nodeB.id, cost))
|
||||||
|
|
||||||
nodeA.cost[nodeB.id]=cost
|
nodeA.cost[nodeB.id]=cost
|
||||||
nodeB.cost[nodeA.id]=cost -- Symmetric problem.
|
nodeB.cost[nodeA.id]=cost -- Symmetric problem.
|
||||||
|
|
||||||
@@ -834,9 +1158,10 @@ end
|
|||||||
-- @return #boolean If true, transition between nodes is possible.
|
-- @return #boolean If true, transition between nodes is possible.
|
||||||
function ASTAR:_IsValidNeighbour(node, neighbor)
|
function ASTAR:_IsValidNeighbour(node, neighbor)
|
||||||
|
|
||||||
-- Counter.
|
-- Counter of function calls.
|
||||||
self.nvalid=self.nvalid+1
|
self.nvalid=self.nvalid+1
|
||||||
|
|
||||||
|
-- Check if neighbour is in cached set.
|
||||||
local valid=node.valid[neighbor.id]
|
local valid=node.valid[neighbor.id]
|
||||||
if valid~=nil then
|
if valid~=nil then
|
||||||
--env.info(string.format("Node %d has valid=%s neighbour %d", node.id, tostring(valid), neighbor.id))
|
--env.info(string.format("Node %d has valid=%s neighbour %d", node.id, tostring(valid), neighbor.id))
|
||||||
@@ -844,13 +1169,16 @@ function ASTAR:_IsValidNeighbour(node, neighbor)
|
|||||||
return valid
|
return valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check if this is a valid neighbour.
|
||||||
local valid=nil
|
local valid=nil
|
||||||
if self.ValidNeighbourFunc then
|
if self.ValidNeighbourFunc then
|
||||||
valid=self.ValidNeighbourFunc(node, neighbor, unpack(self.ValidNeighbourArg))
|
valid=self.ValidNeighbourFunc(node, neighbor, unpack(self.ValidNeighbourArg))
|
||||||
else
|
else
|
||||||
|
-- If no valid neighbour function is defined, we assume all nodes are valid neighbours.
|
||||||
valid=true
|
valid=true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cache valid neighbour.
|
||||||
node.valid[neighbor.id]=valid
|
node.valid[neighbor.id]=valid
|
||||||
neighbor.valid[node.id]=valid -- Symmetric problem.
|
neighbor.valid[node.id]=valid -- Symmetric problem.
|
||||||
|
|
||||||
@@ -884,6 +1212,9 @@ function ASTAR:_LowestFscore(set, f_score)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Lowest Fscore=%.1f, Node=%s", lowest, tostring(bestNode)))
|
||||||
|
|
||||||
return self.nodes[bestNode]
|
return self.nodes[bestNode]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -928,16 +1259,46 @@ end
|
|||||||
-- @param #table map Map.
|
-- @param #table map Map.
|
||||||
-- @param #ASTAR.Node current_node The current node.
|
-- @param #ASTAR.Node current_node The current node.
|
||||||
-- @return #table Unwinded path.
|
-- @return #table Unwinded path.
|
||||||
function ASTAR:_UnwindPath( flat_path, map, current_node )
|
function ASTAR:_UnwindPath(flat_path, map, current_node)
|
||||||
|
|
||||||
if map [current_node] then
|
local previous_node=map[current_node]
|
||||||
table.insert (flat_path, 1, map[current_node])
|
|
||||||
return self:_UnwindPath(flat_path, map, map[current_node])
|
if previous_node then
|
||||||
|
table.insert(flat_path, 1, previous_node)
|
||||||
|
return self:_UnwindPath(flat_path, map, previous_node)
|
||||||
else
|
else
|
||||||
|
-- No previous node ==> return path.
|
||||||
return flat_path
|
return flat_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Function to check if a certain node is in a given table.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table Nodes Nodes table.
|
||||||
|
-- @param #ASTAR.Node Node The node to check.
|
||||||
|
-- @return #boolean If true, the node is not in the set.
|
||||||
|
function ASTAR:_IsNodeInTable(Nodes, Node)
|
||||||
|
|
||||||
|
for _,_node in pairs(Nodes) do
|
||||||
|
local node=_node --#ASTAR.Node
|
||||||
|
if node.id==Node.id then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to check if a certain node is **not** in a given table.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table Nodes Nodes table.
|
||||||
|
-- @param #ASTAR.Node Node The node to check.
|
||||||
|
-- @return #boolean If true, the node is not in the set.
|
||||||
|
function ASTAR:_IsNodeNotInTable(Nodes, Node)
|
||||||
|
local is=self:_IsNodeInTable(Nodes, Node)
|
||||||
|
return not is
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -974,7 +974,7 @@ do -- Scheduling
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||||
-- @param ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||||
-- @return #string The Schedule ID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||||
|
|
||||||
|
|||||||
@@ -872,8 +872,6 @@ end
|
|||||||
-- @return Wrapper.Group#GROUP The found GROUP.
|
-- @return Wrapper.Group#GROUP The found GROUP.
|
||||||
function DATABASE:FindGroup( GroupName )
|
function DATABASE:FindGroup( GroupName )
|
||||||
|
|
||||||
if type(GroupName) ~= "string" or GroupName == "" then return end
|
|
||||||
|
|
||||||
local GroupFound = self.GROUPS[GroupName]
|
local GroupFound = self.GROUPS[GroupName]
|
||||||
|
|
||||||
if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then
|
if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then
|
||||||
@@ -1699,7 +1697,7 @@ function DATABASE:_EventOnBirth( Event )
|
|||||||
if PlayerName then
|
if PlayerName then
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:I(string.format("Player '%s' joined unit '%s' (%s) of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniTypeName), tostring(Event.IniDCSGroupName)))
|
self:I(string.format("Player '%s' joined unit '%s' of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName)))
|
||||||
|
|
||||||
-- Add client in case it does not exist already.
|
-- Add client in case it does not exist already.
|
||||||
if client == nil or (client and client:CountPlayers() == 0) then
|
if client == nil or (client and client:CountPlayers() == 0) then
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ end
|
|||||||
function MESSAGE:ToGroup( Group, Settings )
|
function MESSAGE:ToGroup( Group, Settings )
|
||||||
self:F( Group.GroupName )
|
self:F( Group.GroupName )
|
||||||
|
|
||||||
if Group and Group:IsAlive() then
|
if Group then
|
||||||
|
|
||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
@@ -231,7 +231,7 @@ end
|
|||||||
function MESSAGE:ToUnit( Unit, Settings )
|
function MESSAGE:ToUnit( Unit, Settings )
|
||||||
self:F( Unit.IdentifiableName )
|
self:F( Unit.IdentifiableName )
|
||||||
|
|
||||||
if Unit and Unit:IsAlive() then
|
if Unit then
|
||||||
|
|
||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
-- * Path from A to B
|
-- * Path from A to B
|
||||||
-- * Arbitrary number of points
|
-- * Arbitrary number of points
|
||||||
-- * Automatically from lines drawtool
|
-- * Automatically from lines drawtool
|
||||||
|
-- * Draw line or mark points on F10 map
|
||||||
|
-- * Find closest points to path
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -21,6 +23,7 @@
|
|||||||
-- @field #string lid Class id string for output to DCS log file.
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
-- @field #string name Name of the path line.
|
-- @field #string name Name of the path line.
|
||||||
-- @field #table points List of 3D points defining the path.
|
-- @field #table points List of 3D points defining the path.
|
||||||
|
-- @field #number counter Running number counting the point IDs.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- *The shortest distance between two points is a straight line.* -- Archimedes
|
--- *The shortest distance between two points is a straight line.* -- Archimedes
|
||||||
@@ -59,27 +62,39 @@ PATHLINE = {
|
|||||||
ClassName = "PATHLINE",
|
ClassName = "PATHLINE",
|
||||||
lid = nil,
|
lid = nil,
|
||||||
points = {},
|
points = {},
|
||||||
|
counter = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Point of line.
|
--- Point of line.
|
||||||
-- @type PATHLINE.Point
|
-- @type PATHLINE.Point
|
||||||
|
-- @field #number uid Unique ID of this point.
|
||||||
|
-- @field #string mother Name of the pathline this point belongs to.
|
||||||
|
-- @field #string name Name of this point.
|
||||||
-- @field DCS#Vec3 vec3 3D position.
|
-- @field DCS#Vec3 vec3 3D position.
|
||||||
-- @field DCS#Vec2 vec2 2D position.
|
-- @field DCS#Vec2 vec2 2D position.
|
||||||
-- @field #number surfaceType Surface type.
|
-- @field #number surfaceType Surface type.
|
||||||
-- @field #number landHeight Land height in meters.
|
-- @field #number landHeight Land height in meters.
|
||||||
-- @field #number depth Water depth in meters.
|
-- @field #number depth Water depth in meters.
|
||||||
-- @field #number markerID Marker ID.
|
-- @field #number markerID Marker ID.
|
||||||
|
-- @field #number lineID Marker of pathline ID.
|
||||||
|
|
||||||
|
--- Segment of line.
|
||||||
|
-- @type PATHLINE.Segment
|
||||||
|
-- @field #PATHLINE.Point p1 First point.
|
||||||
|
-- @field #PATHLINE.Point p2 Second point.
|
||||||
|
|
||||||
|
|
||||||
--- PATHLINE class version.
|
--- PATHLINE class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PATHLINE.version="0.1.1"
|
PATHLINE.version="0.3.0"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: A lot...
|
-- TODO: Read/write to JSON file
|
||||||
|
-- TODO: Translate/rotate pathline
|
||||||
|
-- TODO: Add color.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
@@ -96,7 +111,7 @@ function PATHLINE:New(Name)
|
|||||||
|
|
||||||
self.name=Name or "Unknown Path"
|
self.name=Name or "Unknown Path"
|
||||||
|
|
||||||
self.lid=string.format("PATHLINE %s | ", Name)
|
self.lid=string.format("PATHLINE %s | ", self.name)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -151,15 +166,30 @@ end
|
|||||||
--- Add a point to the path from a given 2D position. The third dimension is determined from the land height.
|
--- Add a point to the path from a given 2D position. The third dimension is determined from the land height.
|
||||||
-- @param #PATHLINE self
|
-- @param #PATHLINE self
|
||||||
-- @param DCS#Vec2 Vec2 The 2D vector (x,y) to add.
|
-- @param DCS#Vec2 Vec2 The 2D vector (x,y) to add.
|
||||||
|
-- @param #number Index Index to add this point, *e.g.* 1 for first point or 2 for second point. Default is at the end.
|
||||||
|
-- @param #PATHLINE.Point Point Add point after given point. Default is at the end or at given index.
|
||||||
-- @return #PATHLINE self
|
-- @return #PATHLINE self
|
||||||
function PATHLINE:AddPointFromVec2(Vec2)
|
function PATHLINE:AddPointFromVec2(Vec2, Index, Point)
|
||||||
|
|
||||||
if Vec2 then
|
if Vec2 then
|
||||||
|
|
||||||
|
-- Create a new point.
|
||||||
local point=self:_CreatePoint(Vec2)
|
local point=self:_CreatePoint(Vec2)
|
||||||
|
|
||||||
|
if Index then
|
||||||
|
-- Add at given index.
|
||||||
|
table.insert(self.points, Index, point)
|
||||||
|
else
|
||||||
|
if Point then
|
||||||
|
-- Get index of given point.
|
||||||
|
local i=self:_GetPointIndex(Point)
|
||||||
|
-- Add new point after given point.
|
||||||
|
table.insert(self.points, i+1, point)
|
||||||
|
else
|
||||||
|
-- Add add the end.
|
||||||
table.insert(self.points, point)
|
table.insert(self.points, point)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -168,18 +198,32 @@ end
|
|||||||
--- Add a point to the path from a given 3D position.
|
--- Add a point to the path from a given 3D position.
|
||||||
-- @param #PATHLINE self
|
-- @param #PATHLINE self
|
||||||
-- @param DCS#Vec3 Vec3 The 3D vector (x,y) to add.
|
-- @param DCS#Vec3 Vec3 The 3D vector (x,y) to add.
|
||||||
-- @return #PATHLINE self
|
-- @param #number Index Index to add this point, *e.g.* 1 for first point or 2 for second point. Default is at the end.
|
||||||
function PATHLINE:AddPointFromVec3(Vec3)
|
-- @param #PATHLINE.Point Point Add point after given point. Default is at the end or at given index.
|
||||||
|
-- @return #PATHLINE.Point Point that was added.
|
||||||
|
function PATHLINE:AddPointFromVec3(Vec3, Index, Point)
|
||||||
|
|
||||||
if Vec3 then
|
if Vec3 then
|
||||||
|
|
||||||
local point=self:_CreatePoint(Vec3)
|
local point=self:_CreatePoint(Vec3)
|
||||||
|
|
||||||
|
if Index then
|
||||||
|
-- Add add given index.
|
||||||
|
table.insert(self.points, Index, point)
|
||||||
|
else
|
||||||
|
if Point then
|
||||||
|
local i=self:_GetPointIndex(Point)
|
||||||
|
table.insert(self.points, i+1, point)
|
||||||
|
else
|
||||||
|
-- Add add the end.
|
||||||
table.insert(self.points, point)
|
table.insert(self.points, point)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return point
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get name of pathline.
|
--- Get name of pathline.
|
||||||
@@ -199,14 +243,31 @@ end
|
|||||||
|
|
||||||
--- Get points of pathline. Not that points are tables, that contain more information as just the 2D or 3D position but also the surface type etc.
|
--- Get points of pathline. Not that points are tables, that contain more information as just the 2D or 3D position but also the surface type etc.
|
||||||
-- @param #PATHLINE self
|
-- @param #PATHLINE self
|
||||||
-- @return #list <#PATHLINE.Point> List of points.
|
-- @return #list <Core.Pathline#PATHLINE.Point> List of points.
|
||||||
function PATHLINE:GetPoints()
|
function PATHLINE:GetPoints()
|
||||||
return self.points
|
return self.points
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get segments of pathline.
|
||||||
|
-- @param #PATHLINE self
|
||||||
|
-- @return #list <Core.Pathline#PATHLINE.Segment> List of points.
|
||||||
|
function PATHLINE:GetSetments()
|
||||||
|
|
||||||
|
local segments={}
|
||||||
|
|
||||||
|
for i=1,#self.points-1 do
|
||||||
|
local segment={} --#PATHLINE.Segment
|
||||||
|
segment.p1=self.points[i]
|
||||||
|
segment.p2=self.points[i+1]
|
||||||
|
table.insert(segments, segment)
|
||||||
|
end
|
||||||
|
|
||||||
|
return segments
|
||||||
|
end
|
||||||
|
|
||||||
--- Get 3D points of pathline.
|
--- Get 3D points of pathline.
|
||||||
-- @param #PATHLINE self
|
-- @param #PATHLINE self
|
||||||
-- @return <DCS#Vec3> List of DCS#Vec3 points.
|
-- @return #list <DCS#Vec3> List of DCS#Vec3 points.
|
||||||
function PATHLINE:GetPoints3D()
|
function PATHLINE:GetPoints3D()
|
||||||
|
|
||||||
local vecs={}
|
local vecs={}
|
||||||
@@ -221,7 +282,7 @@ end
|
|||||||
|
|
||||||
--- Get 2D points of pathline.
|
--- Get 2D points of pathline.
|
||||||
-- @param #PATHLINE self
|
-- @param #PATHLINE self
|
||||||
-- @return <DCS#Vec2> List of DCS#Vec2 points.
|
-- @return #list <DCS#Vec2> List of DCS#Vec2 points.
|
||||||
function PATHLINE:GetPoints2D()
|
function PATHLINE:GetPoints2D()
|
||||||
|
|
||||||
local vecs={}
|
local vecs={}
|
||||||
@@ -244,7 +305,7 @@ function PATHLINE:GetCoordinates()
|
|||||||
for _,_point in pairs(self.points) do
|
for _,_point in pairs(self.points) do
|
||||||
local point=_point --#PATHLINE.Point
|
local point=_point --#PATHLINE.Point
|
||||||
local coord=COORDINATE:NewFromVec3(point.vec3)
|
local coord=COORDINATE:NewFromVec3(point.vec3)
|
||||||
table.insert(vecs,coord)
|
table.insert(vecs, coord)
|
||||||
end
|
end
|
||||||
|
|
||||||
return vecs
|
return vecs
|
||||||
@@ -305,14 +366,16 @@ end
|
|||||||
--- Mark points on F10 map.
|
--- Mark points on F10 map.
|
||||||
-- @param #PATHLINE self
|
-- @param #PATHLINE self
|
||||||
-- @param #boolean Switch If `true` or nil, set marks. If `false`, remove marks.
|
-- @param #boolean Switch If `true` or nil, set marks. If `false`, remove marks.
|
||||||
-- @return <DCS#Vec3> List of DCS#Vec3 points.
|
-- @return #PATHLINE self
|
||||||
function PATHLINE:MarkPoints(Switch)
|
function PATHLINE:MarkPoints(Switch)
|
||||||
|
|
||||||
for i,_point in pairs(self.points) do
|
for i,_point in pairs(self.points) do
|
||||||
local point=_point --#PATHLINE.Point
|
local point=_point --#PATHLINE.Point
|
||||||
|
|
||||||
if Switch==false then
|
if Switch==false then
|
||||||
|
|
||||||
if point.markerID then
|
if point.markerID then
|
||||||
UTILS.RemoveMark(point.markerID, Delay)
|
UTILS.RemoveMark(point.markerID)
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -323,15 +386,294 @@ function PATHLINE:MarkPoints(Switch)
|
|||||||
|
|
||||||
point.markerID=UTILS.GetMarkID()
|
point.markerID=UTILS.GetMarkID()
|
||||||
|
|
||||||
local text=string.format("Pathline %s: Point #%d\nSurface Type=%d\nHeight=%.1f m\nDepth=%.1f m", self.name, i, point.surfaceType, point.landHeight, point.depth)
|
local text=string.format("Pathline %s: Point #%d [UID=%d]\nSurface Type=%d\nHeight=%.1f m\nDepth=%.1f m", self.name, i, point.uid, point.surfaceType, point.landHeight, point.depth)
|
||||||
|
|
||||||
trigger.action.markToAll(point.markerID, text, point.vec3, "")
|
trigger.action.markToAll(point.markerID, text, point.vec3, "")
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Draw line on F10 map.
|
||||||
|
-- @param #PATHLINE self
|
||||||
|
-- @param #boolean Switch If `true` or nil, draw pathline. If `false`, remove drawing.
|
||||||
|
-- @param #number Coalition Coalition side. Default -1 for all.
|
||||||
|
-- @param #table Color RGB color and alpha `{r, g, b, a}`. Default {0, 1, 0, 0.5}.
|
||||||
|
-- @param #number LineType Line type. Default 1=solid.
|
||||||
|
-- @return #PATHLINE self
|
||||||
|
function PATHLINE:Draw(Switch, Coalition, Color, LineType)
|
||||||
|
|
||||||
|
Coalition=Coalition or -1
|
||||||
|
Color=Color or {0, 1, 0, 0.5}
|
||||||
|
LineType=LineType or 1
|
||||||
|
|
||||||
|
if Switch==false then
|
||||||
|
|
||||||
|
for i,_point in pairs(self.points) do
|
||||||
|
local point=_point --#PATHLINE.Point
|
||||||
|
|
||||||
|
if point.lineID then
|
||||||
|
UTILS.RemoveMark(point.lineID)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
for i=2,#self.points do
|
||||||
|
|
||||||
|
local p1=self.points[i-1] --#PATHLINE.Point
|
||||||
|
local p2=self.points[i] --#PATHLINE.Point
|
||||||
|
|
||||||
|
if p2.lineID then
|
||||||
|
UTILS.RemoveMark(p2.lineID)
|
||||||
|
end
|
||||||
|
|
||||||
|
p2.lineID=UTILS.GetMarkID()
|
||||||
|
|
||||||
|
trigger.action.lineToAll(Coalition, p2.lineID, p1.vec3, p2.vec3, Color, LineType)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the closest point on the pathline for a given reference point.
|
||||||
|
-- @param #PATHLINE self
|
||||||
|
-- @param DCS#Vec2 Vec2 Reference Point in 2D.
|
||||||
|
-- @return DCS#Vec2 Cloest point on pathline.
|
||||||
|
-- @return #number Distance from closest point to ref point in meters.
|
||||||
|
-- @return #PATHLINE.Segment Closest segment of ref point.
|
||||||
|
function PATHLINE:GetClosestPoint2D(Vec2)
|
||||||
|
|
||||||
|
local P=nil --DCS#Vec2
|
||||||
|
local D=math.huge
|
||||||
|
local S={} --#PATHLINE.Segment
|
||||||
|
|
||||||
|
for i=2,#self.points do
|
||||||
|
|
||||||
|
local A=self.points[i-1] --#PATHLINE.Point
|
||||||
|
local B=self.points[i] --#PATHLINE.Point
|
||||||
|
|
||||||
|
local a=A.vec2
|
||||||
|
local b=B.vec2
|
||||||
|
|
||||||
|
local ab=UTILS.Vec2Substract(b, a)
|
||||||
|
local ap=UTILS.Vec2Substract(Vec2, a)
|
||||||
|
|
||||||
|
local proj=UTILS.Vec2Dot(ap, ab)
|
||||||
|
|
||||||
|
local lab=UTILS.Vec2Norm(ab)
|
||||||
|
|
||||||
|
local f=proj/lab/lab
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("FF Proj=%.1f, |ab|=%.1f, f=%.1f", proj, lab, f)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
-- Cases for finite segment.
|
||||||
|
local p=nil --DCS#Vec2
|
||||||
|
if f<0 then
|
||||||
|
p=a
|
||||||
|
elseif f>1 then
|
||||||
|
p=b
|
||||||
|
else
|
||||||
|
local r=UTILS.Vec2Mult(ab, f)
|
||||||
|
p=UTILS.Vec2Add(a, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Distance.
|
||||||
|
local d=UTILS.VecDist2D(p, Vec2)
|
||||||
|
|
||||||
|
if d<=D then
|
||||||
|
D=d
|
||||||
|
P=p
|
||||||
|
S.p1=A
|
||||||
|
S.p2=B
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return P, D, S
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the closest point on the pathline for a given reference point.
|
||||||
|
-- This point does not necessarily is a node of the pathline. In general it will be somewhere in between the nodes defining the pathline.
|
||||||
|
-- @param #PATHLINE self
|
||||||
|
-- @param DCS#Vec3 Vec3 Reference Point in 3D. Can also be a `COORDINATE`.
|
||||||
|
-- @return DCS#Vec3 Closest point on pathline.
|
||||||
|
-- @return #number Distance from closest point to ref point in meters.
|
||||||
|
-- @return #PATHLINE.Segment Closest segment of ref point.
|
||||||
|
function PATHLINE:GetClosestPoint3D(Vec3)
|
||||||
|
|
||||||
|
local P=nil --DCS#Vec3
|
||||||
|
local D=math.huge
|
||||||
|
local S={} --#PATHLINE.Segment
|
||||||
|
|
||||||
|
if not Vec3 then
|
||||||
|
self:E(self.lid.."ERROR: input Vec3 is nil!")
|
||||||
|
return nil, nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=2,#self.points do
|
||||||
|
|
||||||
|
local A=self.points[i-1] --#PATHLINE.Point
|
||||||
|
local B=self.points[i] --#PATHLINE.Point
|
||||||
|
|
||||||
|
local a=A.vec3
|
||||||
|
local b=B.vec3
|
||||||
|
|
||||||
|
local ab=UTILS.VecSubstract(b, a)
|
||||||
|
local ap=UTILS.VecSubstract(Vec3, a)
|
||||||
|
|
||||||
|
local proj=UTILS.VecDot(ap, ab)
|
||||||
|
|
||||||
|
local lab=UTILS.VecNorm(ab)
|
||||||
|
|
||||||
|
local f=proj/lab/lab
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Proj=%.1f, |ab|=%.1f, f=%.1f", proj, lab, f))
|
||||||
|
|
||||||
|
-- Cases for finite segment.
|
||||||
|
local p=nil --DCS#Vec2
|
||||||
|
if f<0 then
|
||||||
|
p=a
|
||||||
|
elseif f>1 then
|
||||||
|
p=b
|
||||||
|
else
|
||||||
|
local r=UTILS.VecMult(ab, f)
|
||||||
|
p=UTILS.VecAdd(a, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Distance.
|
||||||
|
local d=UTILS.VecDist3D(p, Vec3)
|
||||||
|
|
||||||
|
if d<=D then
|
||||||
|
D=d
|
||||||
|
P=p
|
||||||
|
S.p1=A
|
||||||
|
S.p2=B
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return P, D, S
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Write PATHLINE to JSON file.
|
||||||
|
-- **NOTE**: Requires `io` and `lfs` to be de-sanitized!
|
||||||
|
-- @param #PATHLINE self
|
||||||
|
-- @param #string FileName Name of the file. Default is the name of the pathline.
|
||||||
|
-- @return #PATHLINE self
|
||||||
|
function PATHLINE:WriteJSON(FileName)
|
||||||
|
|
||||||
|
if io and lfs then
|
||||||
|
|
||||||
|
-- JSON script.
|
||||||
|
local json=loadfile("Scripts\\JSON.lua")()
|
||||||
|
|
||||||
|
local data={}
|
||||||
|
|
||||||
|
-- We store the name and the points.
|
||||||
|
data.name=self.name
|
||||||
|
data.points=self.points
|
||||||
|
for i,_point in pairs(self.points) do
|
||||||
|
local point=_point --#PATHLINE.Point
|
||||||
|
--point.markerID=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Encode data to raw JSON. Encode converts a lua table into JSON string that can be written to file.
|
||||||
|
local raw_json=json:encode(data)
|
||||||
|
|
||||||
|
-- Debug data.
|
||||||
|
self:T(data)
|
||||||
|
|
||||||
|
-- Write in "User/Saved Games/" Folder.
|
||||||
|
local filepath=lfs.writedir() .. FileName
|
||||||
|
|
||||||
|
-- Open file for writing.
|
||||||
|
local f = io.open(filepath, "wb")
|
||||||
|
if f then
|
||||||
|
f:write(raw_json)
|
||||||
|
f:close()
|
||||||
|
self:T(self.lid .. string.format("Saving PATHLINE %s file %s", self.name, tostring(filepath)))
|
||||||
|
else
|
||||||
|
self:E(self.lid .. string.format( "ERROR: Could not save PATHLINE to file %s", tostring(filepath)))
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E(self.lid .. string.format( "ERROR: Could not save results because IO and/or LFS are not de-sanitized!"))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Read PATHLINE from JSON file.
|
||||||
|
-- **NOTE**: Requires `io` and `lfs` to be de-sanitized!
|
||||||
|
-- @param #PATHLINE self
|
||||||
|
-- @param #string FileName Name of the file.
|
||||||
|
-- @return #PATHLINE self
|
||||||
|
function PATHLINE:NewFromJSON(FileName)
|
||||||
|
|
||||||
|
if io and lfs then
|
||||||
|
|
||||||
|
-- JSON script.
|
||||||
|
local json=loadfile("Scripts\\JSON.lua")()
|
||||||
|
|
||||||
|
local data={}
|
||||||
|
|
||||||
|
-- Write in "User/Saved Games/" Folder.
|
||||||
|
local filepath=lfs.writedir() .. FileName
|
||||||
|
|
||||||
|
--env.info(filepath)
|
||||||
|
|
||||||
|
-- Open file in binary mode for reading.
|
||||||
|
local f = io.open(filepath, "rb")
|
||||||
|
if f then
|
||||||
|
data = f:read("*all")
|
||||||
|
f:close()
|
||||||
|
else
|
||||||
|
env.info(string.format("WARNING: Could not load PATHLINE from file %s!", tostring(filepath)))
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Decode JSON data to get a lua table.
|
||||||
|
local data=json:decode(data)
|
||||||
|
|
||||||
|
if data and data.name then
|
||||||
|
|
||||||
|
-- Create a new pathline instance.
|
||||||
|
local self=PATHLINE:New(data.name)
|
||||||
|
|
||||||
|
for i=1,#data.points do
|
||||||
|
local point=data.points[i] --#PATHLINE.Point
|
||||||
|
|
||||||
|
-- Create new point from data.
|
||||||
|
local p=self:AddPointFromVec3(point.vec3)
|
||||||
|
|
||||||
|
-- Set name.
|
||||||
|
p.name=point.name
|
||||||
|
|
||||||
|
-- Remove marker ID.
|
||||||
|
p.markerID=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
else
|
||||||
|
BASE:E("ERROR: Cannot find pathline name in data from JSON file. File may be corrupted!")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
BASE:E("ERROR: IO and/or LFS not de-sanitized! Cannot read file.")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Private functions
|
-- Private functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -339,11 +681,18 @@ end
|
|||||||
--- Get 3D points of pathline.
|
--- Get 3D points of pathline.
|
||||||
-- @param #PATHLINE self
|
-- @param #PATHLINE self
|
||||||
-- @param DCS#Vec3 Vec Position vector. Can also be a DCS#Vec2 in which case the altitude at landheight is taken.
|
-- @param DCS#Vec3 Vec Position vector. Can also be a DCS#Vec2 in which case the altitude at landheight is taken.
|
||||||
-- @return #PATHLINE.Point
|
-- @return #PATHLINE.Point Pathline Point.
|
||||||
function PATHLINE:_CreatePoint(Vec)
|
function PATHLINE:_CreatePoint(Vec)
|
||||||
|
|
||||||
local point={} --#PATHLINE.Point
|
local point={} --#PATHLINE.Point
|
||||||
|
|
||||||
|
self.counter=self.counter+1
|
||||||
|
|
||||||
|
point.uid=self.counter
|
||||||
|
point.mother=self.name
|
||||||
|
|
||||||
|
point.name=string.format("%s #%d", self.name, point.uid)
|
||||||
|
|
||||||
if Vec.z then
|
if Vec.z then
|
||||||
-- Given vec is 3D
|
-- Given vec is 3D
|
||||||
point.vec3=UTILS.DeepCopy(Vec)
|
point.vec3=UTILS.DeepCopy(Vec)
|
||||||
@@ -365,6 +714,23 @@ function PATHLINE:_CreatePoint(Vec)
|
|||||||
return point
|
return point
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get index of point in the lua table.
|
||||||
|
-- @param #PATHLINE self
|
||||||
|
-- @param #PATHLINE.Point Point Given point.
|
||||||
|
-- @return #number index
|
||||||
|
function PATHLINE:_GetPointIndex(Point)
|
||||||
|
|
||||||
|
for i,_point in pairs(self.points) do
|
||||||
|
local point=_point --#PATHLINE.Point
|
||||||
|
|
||||||
|
if point.uid==Point.uid then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
do -- COORDINATE
|
do -- COORDINATE
|
||||||
|
|
||||||
--- Coordinate class
|
---
|
||||||
-- @type COORDINATE
|
-- @type COORDINATE
|
||||||
-- @field #string ClassName Name of the class
|
-- @field #string ClassName Name of the class
|
||||||
-- @field #number x Component of the 3D vector.
|
-- @field #number x Component of the 3D vector.
|
||||||
@@ -59,10 +59,6 @@ do -- COORDINATE
|
|||||||
-- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange.
|
-- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange.
|
||||||
-- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white.
|
-- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white.
|
||||||
-- * @{#COORDINATE.SmokeGreen}(): To smoke the point in green.
|
-- * @{#COORDINATE.SmokeGreen}(): To smoke the point in green.
|
||||||
-- * @{#COORDINATE.SetSmokeOffsetDirection}(): To set an offset point direction for smoke.
|
|
||||||
-- * @{#COORDINATE.SetSmokeOffsetDistance}(): To set an offset point distance for smoke.
|
|
||||||
-- * @{#COORDINATE.SwitchSmokeOffsetOn}(): To set an offset point for smoke to on.
|
|
||||||
-- * @{#COORDINATE.SwitchSmokeOffsetOff}(): To set an offset point for smoke to off.
|
|
||||||
--
|
--
|
||||||
-- ## 2.2) Flare
|
-- ## 2.2) Flare
|
||||||
--
|
--
|
||||||
@@ -457,6 +453,23 @@ do -- COORDINATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Returns the coordinate from the latitude and longitude given in degrees, minutes and seconds (DMS).
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #string Latitude Latitude in DMS as string, e.g. "`42° 24' 14.3"`". Not that the characters `°`, `'` and `"` are important.
|
||||||
|
-- @param #string Longitude Longitude in DMS as string, e.g. "`42° 24' 14.3"`". Not that the characters `°`, `'` and `"` are important.
|
||||||
|
-- @param #number Altitude (Optional) Altitude in meters. Default is the land height at the coordinate.
|
||||||
|
-- @return #COORDINATE
|
||||||
|
function COORDINATE:NewFromLLDMS(Latitude, Longitude, Altitude)
|
||||||
|
|
||||||
|
local lat=UTILS.LLDMSstringToDD(Latitude)
|
||||||
|
local lon=UTILS.LLDMSstringToDD(Longitude)
|
||||||
|
|
||||||
|
self=COORDINATE:NewFromLLDD(lat, lon, Altitude)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns if the 2 coordinates are at the same 2D position.
|
--- Returns if the 2 coordinates are at the same 2D position.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE Coordinate
|
-- @param #COORDINATE Coordinate
|
||||||
@@ -2122,114 +2135,16 @@ do -- COORDINATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create colored smoke the point. The smoke we last up to 5 min (DCS limitation) but you can optionally specify a shorter duration or stop it manually.
|
--- Smokes the point in a color.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number SmokeColor Color of smoke, e.g. `SMOKECOLOR.Green` for green smoke.
|
-- @param Utilities.Utils#SMOKECOLOR SmokeColor
|
||||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
-- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
||||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
function COORDINATE:Smoke( SmokeColor, name )
|
||||||
-- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
self:F2( { SmokeColor } )
|
||||||
-- @param #boolean Offset (Optional) If true, offset the smokle a bit.
|
self.firename = name or "Smoke-"..math.random(1,100000)
|
||||||
-- @param #number Direction (Optional) If Offset is true this is the direction of the offset, 1-359 (degrees). Default random.
|
|
||||||
-- @param #number Distance (Optional) If Offset is true this is the distance of the offset in meters. Default random 10-20.
|
|
||||||
-- @return #COORDINATE self
|
|
||||||
function COORDINATE:Smoke( SmokeColor, Duration, Delay, Name, Offset,Direction,Distance)
|
|
||||||
self:F2( { SmokeColor, Name, Duration, Delay, Offset } )
|
|
||||||
|
|
||||||
SmokeColor=SmokeColor or SMOKECOLOR.Green
|
|
||||||
|
|
||||||
if Delay and Delay>0 then
|
|
||||||
self:ScheduleOnce(Delay, COORDINATE.Smoke, self, SmokeColor, Duration, 0, Name, Direction,Distance)
|
|
||||||
else
|
|
||||||
|
|
||||||
-- Create a name which is used to stop the smoke manually
|
|
||||||
self.firename = Name or "Smoke-"..math.random(1,100000)
|
|
||||||
|
|
||||||
-- Create smoke
|
|
||||||
if Offset or self.SmokeOffset then
|
|
||||||
local Angle = Direction or self:GetSmokeOffsetDirection()
|
|
||||||
local Distance = Distance or self:GetSmokeOffsetDistance()
|
|
||||||
local newpos = self:Translate(Distance,Angle,true,false)
|
|
||||||
local newvec3 = newpos:GetVec3()
|
|
||||||
trigger.action.smoke( newvec3, SmokeColor, self.firename )
|
|
||||||
else
|
|
||||||
trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename )
|
trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Stop smoke
|
|
||||||
if Duration and Duration>0 then
|
|
||||||
self:ScheduleOnce(Duration, COORDINATE.StopSmoke, self, self.firename )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get the offset direction when using `COORDINATE:Smoke()`.
|
|
||||||
-- @param #COORDINATE self
|
|
||||||
-- @return #number Direction in degrees.
|
|
||||||
function COORDINATE:GetSmokeOffsetDirection()
|
|
||||||
local direction = self.SmokeOffsetDirection or math.random(1,359)
|
|
||||||
return direction
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the offset direction when using `COORDINATE:Smoke()`.
|
|
||||||
-- @param #COORDINATE self
|
|
||||||
-- @param #number Direction (Optional) This is the direction of the offset, 1-359 (degrees). Default random.
|
|
||||||
-- @return #COORDINATE self
|
|
||||||
function COORDINATE:SetSmokeOffsetDirection(Direction)
|
|
||||||
if self then
|
|
||||||
self.SmokeOffsetDirection = Direction or math.random(1,359)
|
|
||||||
return self
|
|
||||||
else
|
|
||||||
COORDINATE.SmokeOffsetDirection = Direction or math.random(1,359)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get the offset distance when using `COORDINATE:Smoke()`.
|
|
||||||
-- @param #COORDINATE self
|
|
||||||
-- @return #number Distance Distance in meters.
|
|
||||||
function COORDINATE:GetSmokeOffsetDistance()
|
|
||||||
local distance = self.SmokeOffsetDistance or math.random(10,20)
|
|
||||||
return distance
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the offset distance when using `COORDINATE:Smoke()`.
|
|
||||||
-- @param #COORDINATE self
|
|
||||||
-- @param #number Distance (Optional) This is the distance of the offset in meters. Default random 10-20.
|
|
||||||
-- @return #COORDINATE self
|
|
||||||
function COORDINATE:SetSmokeOffsetDistance(Distance)
|
|
||||||
if self then
|
|
||||||
self.SmokeOffsetDistance = Distance or math.random(10,20)
|
|
||||||
return self
|
|
||||||
else
|
|
||||||
COORDINATE.SmokeOffsetDistance = Distance or math.random(10,20)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the offset on when using `COORDINATE:Smoke()`.
|
|
||||||
-- @param #COORDINATE self
|
|
||||||
-- @return #COORDINATE self
|
|
||||||
function COORDINATE:SwitchSmokeOffsetOn()
|
|
||||||
if self then
|
|
||||||
self.SmokeOffset = true
|
|
||||||
return self
|
|
||||||
else
|
|
||||||
COORDINATE.SmokeOffset = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the offset off when using `COORDINATE:Smoke()`.
|
|
||||||
-- @param #COORDINATE self
|
|
||||||
-- @return #COORDINATE self
|
|
||||||
function COORDINATE:SwitchSmokeOffsetOff()
|
|
||||||
if self then
|
|
||||||
self.SmokeOffset = false
|
|
||||||
return self
|
|
||||||
else
|
|
||||||
COORDINATE.SmokeOffset = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Stops smoking the point in a color.
|
--- Stops smoking the point in a color.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
-- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
||||||
@@ -2239,83 +2154,49 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- Smoke the COORDINATE Green.
|
--- Smoke the COORDINATE Green.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
function COORDINATE:SmokeGreen()
|
||||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
self:F2()
|
||||||
-- @return #COORDINATE self
|
self:Smoke( SMOKECOLOR.Green )
|
||||||
function COORDINATE:SmokeGreen(Duration, Delay)
|
|
||||||
self:Smoke( SMOKECOLOR.Green, Duration, Delay )
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the COORDINATE Red.
|
--- Smoke the COORDINATE Red.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
function COORDINATE:SmokeRed()
|
||||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
self:F2()
|
||||||
-- @return #COORDINATE self
|
self:Smoke( SMOKECOLOR.Red )
|
||||||
function COORDINATE:SmokeRed(Duration, Delay)
|
|
||||||
self:Smoke( SMOKECOLOR.Red, Duration, Delay )
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the COORDINATE White.
|
--- Smoke the COORDINATE White.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
function COORDINATE:SmokeWhite()
|
||||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
self:F2()
|
||||||
-- @return #COORDINATE self
|
self:Smoke( SMOKECOLOR.White )
|
||||||
function COORDINATE:SmokeWhite(Duration, Delay)
|
|
||||||
self:Smoke( SMOKECOLOR.White, Duration, Delay )
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the COORDINATE Orange.
|
--- Smoke the COORDINATE Orange.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
function COORDINATE:SmokeOrange()
|
||||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
self:F2()
|
||||||
-- @return #COORDINATE self
|
self:Smoke( SMOKECOLOR.Orange )
|
||||||
function COORDINATE:SmokeOrange(Duration, Delay)
|
|
||||||
self:Smoke( SMOKECOLOR.Orange, Duration, Delay )
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the COORDINATE Blue.
|
--- Smoke the COORDINATE Blue.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
function COORDINATE:SmokeBlue()
|
||||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
self:F2()
|
||||||
-- @return #COORDINATE self
|
self:Smoke( SMOKECOLOR.Blue )
|
||||||
function COORDINATE:SmokeBlue(Duration, Delay)
|
|
||||||
self:Smoke( SMOKECOLOR.Blue, Duration, Delay )
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Big smoke and fire at the coordinate.
|
--- Big smoke and fire at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke).
|
-- @param Utilities.Utils#BIGSMOKEPRESET preset Smoke preset (1=small smoke and fire, 2=medium smoke and fire, 3=large smoke and fire, 4=huge smoke and fire, 5=small smoke, 6=medium smoke, 7=large smoke, 8=huge smoke).
|
||||||
-- @param #number Density (Optional) Smoke density. Number in [0,...,1]. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number in [0,...,1]. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
function COORDINATE:BigSmokeAndFire( preset, density, name )
|
||||||
-- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
self:F2( { preset=preset, density=density } )
|
||||||
-- @return #COORDINATE self
|
density=density or 0.5
|
||||||
function COORDINATE:BigSmokeAndFire( Preset, Density, Duration, Delay, Name )
|
self.firename = name or "Fire-"..math.random(1,10000)
|
||||||
self:F2( { preset=Preset, density=Density } )
|
trigger.action.effectSmokeBig( self:GetVec3(), preset, density, self.firename )
|
||||||
|
|
||||||
Preset=Preset or BIGSMOKEPRESET.SmallSmokeAndFire
|
|
||||||
Density=Density or 0.5
|
|
||||||
|
|
||||||
if Delay and Delay>0 then
|
|
||||||
self:ScheduleOnce(Delay, COORDINATE.BigSmokeAndFire, self, Preset, Density, Duration, 0, Name)
|
|
||||||
else
|
|
||||||
|
|
||||||
self.firename = Name or "Fire-"..math.random(1,10000)
|
|
||||||
|
|
||||||
trigger.action.effectSmokeBig( self:GetVec3(), Preset, Density, self.firename )
|
|
||||||
|
|
||||||
-- Stop smoke
|
|
||||||
if Duration and Duration>0 then
|
|
||||||
self:ScheduleOnce(Duration, COORDINATE.StopBigSmokeAndFire, self, self.firename )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stop big smoke and fire at the coordinate.
|
--- Stop big smoke and fire at the coordinate.
|
||||||
@@ -2328,98 +2209,82 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- Small smoke and fire at the coordinate.
|
--- Small smoke and fire at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
function COORDINATE:BigSmokeAndFireSmall( density, name )
|
||||||
-- @param #string Name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
self:F2( { density=density } )
|
||||||
-- @return #COORDINATE self
|
density=density or 0.5
|
||||||
function COORDINATE:BigSmokeAndFireSmall( Density, Duration, Delay, Name )
|
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density, name)
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, Density, Duration, Delay, Name)
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Medium smoke and fire at the coordinate.
|
--- Medium smoke and fire at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
|
||||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @return #COORDINATE self
|
function COORDINATE:BigSmokeAndFireMedium( density, name )
|
||||||
function COORDINATE:BigSmokeAndFireMedium( Density, Duration, Delay, Name )
|
self:F2( { density=density } )
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, Density, Duration, Delay, Name)
|
density=density or 0.5
|
||||||
return self
|
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Large smoke and fire at the coordinate.
|
--- Large smoke and fire at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
|
||||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @return #COORDINATE self
|
function COORDINATE:BigSmokeAndFireLarge( density, name )
|
||||||
function COORDINATE:BigSmokeAndFireLarge( Density, Duration, Delay, Name )
|
self:F2( { density=density } )
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, Density, Duration, Delay, Name)
|
density=density or 0.5
|
||||||
return self
|
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Huge smoke and fire at the coordinate.
|
--- Huge smoke and fire at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
|
||||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @return #COORDINATE self
|
function COORDINATE:BigSmokeAndFireHuge( density, name )
|
||||||
function COORDINATE:BigSmokeAndFireHuge( Density, Duration, Delay, Name )
|
self:F2( { density=density } )
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, Density, Duration, Delay, Name)
|
density=density or 0.5
|
||||||
return self
|
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Small smoke at the coordinate.
|
--- Small smoke at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
|
||||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @return #COORDINATE self
|
function COORDINATE:BigSmokeSmall( density, name )
|
||||||
function COORDINATE:BigSmokeSmall( Density, Duration, Delay, Name )
|
self:F2( { density=density } )
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, Density, Duration, Delay, Name)
|
density=density or 0.5
|
||||||
return self
|
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Medium smoke at the coordinate.
|
--- Medium smoke at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
|
||||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @return #COORDINATE self
|
function COORDINATE:BigSmokeMedium( density, name )
|
||||||
function COORDINATE:BigSmokeMedium( Density, Duration, Delay, Name )
|
self:F2( { density=density } )
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, Density, Duration, Delay, Name)
|
density=density or 0.5
|
||||||
return self
|
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Large smoke at the coordinate.
|
--- Large smoke at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
|
||||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @return #COORDINATE self
|
function COORDINATE:BigSmokeLarge( density, name )
|
||||||
function COORDINATE:BigSmokeLarge( Density, Duration, Delay, Name )
|
self:F2( { density=density } )
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, Density, Duration, Delay, Name)
|
density=density or 0.5
|
||||||
return self
|
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density,name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Huge smoke at the coordinate.
|
--- Huge smoke at the coordinate.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||||
-- @param #number Duration (Optional) Duration of the smoke and fire in seconds.
|
|
||||||
-- @param #number Delay (Optional) Delay before the smoke and fire is started in seconds.
|
|
||||||
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
-- @param #string name (Optional) Name of the fire to stop it later again if not using the same COORDINATE object. Defaults to "Fire-" plus a random 5-digit-number.
|
||||||
-- @return #COORDINATE self
|
function COORDINATE:BigSmokeHuge( density, name )
|
||||||
function COORDINATE:BigSmokeHuge( Density, Duration, Delay, Name )
|
self:F2( { density=density } )
|
||||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, Density, Duration, Delay, Name)
|
density=density or 0.5
|
||||||
return self
|
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density,name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Flares the point in a color.
|
--- Flares the point in a color.
|
||||||
@@ -3073,10 +2938,8 @@ do -- COORDINATE
|
|||||||
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||||
local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
||||||
|
|
||||||
if type(sunrise) == "string" or type(sunset) == "string" then
|
|
||||||
if sunrise == "N/R" then return false end
|
if sunrise == "N/R" then return false end
|
||||||
if sunset == "N/S" then return true end
|
if sunrise == "N/S" then return true end
|
||||||
end
|
|
||||||
|
|
||||||
local time=UTILS.ClockToSeconds(clock)
|
local time=UTILS.ClockToSeconds(clock)
|
||||||
|
|
||||||
@@ -3095,11 +2958,6 @@ do -- COORDINATE
|
|||||||
-- Todays sun set in sec.
|
-- Todays sun set in sec.
|
||||||
local sunset=self:GetSunset(true)
|
local sunset=self:GetSunset(true)
|
||||||
|
|
||||||
if type(sunrise) == "string" or type(sunset) == "string" then
|
|
||||||
if sunrise == "N/R" then return false end
|
|
||||||
if sunset == "N/S" then return true end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Seconds passed since midnight.
|
-- Seconds passed since midnight.
|
||||||
local time=UTILS.SecondsOfToday()
|
local time=UTILS.SecondsOfToday()
|
||||||
|
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
|||||||
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
||||||
|
|
||||||
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
||||||
if Schedule and Schedule.ScheduleID then
|
if Schedule.ScheduleID then
|
||||||
|
|
||||||
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
||||||
|
|
||||||
|
|||||||
@@ -459,8 +459,7 @@ end
|
|||||||
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
||||||
|
|
||||||
-- Spawn the new static at the center of the zone.
|
-- 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 )
|
||||||
local Static = self:SpawnFromCoordinate(Zone:GetCoordinate(), Heading, NewName)
|
|
||||||
|
|
||||||
return Static
|
return Static
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -305,6 +305,20 @@ function ZONE_BASE:GetCoordinate( Height ) --R2.1
|
|||||||
return self.Coordinate
|
return self.Coordinate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the @{Core.Vector#VECTOR} of the zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @param DCS#Distance Height The height in meters to add to the land height where the center of the zone is located.
|
||||||
|
-- @return Core.Vector#VECTOR The vector of the zone.
|
||||||
|
function ZONE_BASE:GetVector( Height )
|
||||||
|
self:F2(self.ZoneName)
|
||||||
|
|
||||||
|
local Vec3 = self:GetVec3( Height )
|
||||||
|
|
||||||
|
local vector=VECTOR:NewFromVec(Vec3)
|
||||||
|
|
||||||
|
return vector
|
||||||
|
end
|
||||||
|
|
||||||
--- Get 2D distance to a coordinate.
|
--- Get 2D distance to a coordinate.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Reference coordinate. Can also be a DCS#Vec2 or DCS#Vec3 object.
|
-- @param Core.Point#COORDINATE Coordinate Reference coordinate. Can also be a DCS#Vec2 or DCS#Vec3 object.
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ end -- env
|
|||||||
|
|
||||||
do -- radio
|
do -- radio
|
||||||
|
|
||||||
--@type radio
|
---@type radio
|
||||||
-- @field #radio.modulation modulation
|
-- @field #radio.modulation modulation
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
-- @module Functional.Mantis
|
-- @module Functional.Mantis
|
||||||
-- @image Functional.Mantis.jpg
|
-- @image Functional.Mantis.jpg
|
||||||
--
|
--
|
||||||
-- Last Update: May 2025
|
-- Last Update: Mar 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **MANTIS** class, extends Core.Base#BASE
|
--- **MANTIS** class, extends Core.Base#BASE
|
||||||
@@ -62,9 +62,7 @@
|
|||||||
-- @field #table FilterZones Table of Core.Zone#ZONE Zones Consider SAM groups in this zone(s) only for this MANTIS instance, must be handed as #table of Zone objects.
|
-- @field #table FilterZones Table of Core.Zone#ZONE Zones Consider SAM groups in this zone(s) only for this MANTIS instance, must be handed as #table of Zone objects.
|
||||||
-- @field #boolean SmokeDecoy If true, smoke short range SAM units as decoy if a plane is in firing range.
|
-- @field #boolean SmokeDecoy If true, smoke short range SAM units as decoy if a plane is in firing range.
|
||||||
-- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White
|
-- @field #number SmokeDecoyColor Color to use, defaults to SMOKECOLOR.White
|
||||||
-- @field #number checkcounter Counter for SAM Table refreshes.
|
-- @field #number checkcounter Counter for SAM Table refreshes
|
||||||
-- @field #number DLinkCacheTime Seconds after which cached contacts in DLink will decay.
|
|
||||||
-- @field #boolean logsamstatus Log SAM status in dcs.log every cycle if true
|
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -76,9 +74,10 @@
|
|||||||
--
|
--
|
||||||
-- * Moose derived Modular, Automatic and Network capable Targeting and Interception System.
|
-- * Moose derived Modular, Automatic and Network capable Targeting and Interception System.
|
||||||
-- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy.
|
-- * Controls a network of SAM sites. Uses detection to switch on the SAM site closest to the enemy.
|
||||||
-- * **Automatic mode** (default) will set-up your SAM site network automatically for you.
|
-- * **Automatic mode** (default since 0.8) will set-up your SAM site network automatically for you
|
||||||
-- * Leverage evasiveness from SEAD, leverage attack range setting.
|
-- * **Classic mode** behaves like before
|
||||||
-- * Automatic setup of SHORAD based on groups of the class "short-range".
|
-- * Leverage evasiveness from SEAD, leverage attack range setting
|
||||||
|
-- * Automatic setup of SHORAD based on groups of the class "short-range"
|
||||||
--
|
--
|
||||||
-- # 0. Base considerations and naming conventions
|
-- # 0. Base considerations and naming conventions
|
||||||
--
|
--
|
||||||
@@ -134,10 +133,10 @@
|
|||||||
--
|
--
|
||||||
-- # 0.1 Set-up in the mission editor
|
-- # 0.1 Set-up in the mission editor
|
||||||
--
|
--
|
||||||
-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
|
-- Set up your SAM sites in the mission editor. Name the groups using a systematic approach like above.
|
||||||
|
-- Set up your EWR system in the mission editor. Name the groups using a systematic approach like above. Can be e.g. AWACS or a combination of AWACS and Search Radars like e.g. EWR 1L13 etc.
|
||||||
-- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself.
|
-- Search Radars usually have "SR" or "STR" in their names. Use the encyclopedia in the mission editor to inform yourself.
|
||||||
-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one unit ** per group (multiple groups) for the SAM location.
|
-- Set up your SHORAD systems. They need to be **close** to (i.e. around) the SAM sites to be effective. Use **one** group per SAM location. SA-15 TOR systems offer a good missile defense.
|
||||||
-- Else, evasive manoevers might club up all defenders in one place. Red SA-15 TOR systems offer a good missile defense.
|
|
||||||
--
|
--
|
||||||
-- [optional] Set up your HQ. Can be any group, e.g. a command vehicle.
|
-- [optional] Set up your HQ. Can be any group, e.g. a command vehicle.
|
||||||
--
|
--
|
||||||
@@ -189,7 +188,7 @@
|
|||||||
--
|
--
|
||||||
-- ## 2.1 Auto mode features
|
-- ## 2.1 Auto mode features
|
||||||
--
|
--
|
||||||
-- ### 2.1.1 You can add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones:
|
-- ### 2.1.1 You can now add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones:
|
||||||
--
|
--
|
||||||
-- -- Parameters are tables of Core.Zone#ZONE objects!
|
-- -- Parameters are tables of Core.Zone#ZONE objects!
|
||||||
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
||||||
@@ -207,6 +206,9 @@
|
|||||||
--
|
--
|
||||||
-- ### 2.1.4 Advanced features
|
-- ### 2.1.4 Advanced features
|
||||||
--
|
--
|
||||||
|
-- -- Option to switch off auto mode **before** you start MANTIS (not recommended)
|
||||||
|
-- mybluemantis.automode = false
|
||||||
|
--
|
||||||
-- -- Option to set the scale of the activation range, i.e. don't activate at the fringes of max range, defaults below.
|
-- -- Option to set the scale of the activation range, i.e. don't activate at the fringes of max range, defaults below.
|
||||||
-- -- also see engagerange below.
|
-- -- also see engagerange below.
|
||||||
-- self.radiusscale[MANTIS.SamType.LONG] = 1.1
|
-- self.radiusscale[MANTIS.SamType.LONG] = 1.1
|
||||||
@@ -219,12 +221,6 @@
|
|||||||
-- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire.
|
-- -- For some scenarios, like Cold War, it might be useful not to activate SAMs if friendly aircraft are around to avoid death by friendly fire.
|
||||||
-- mybluemantis.checkforfriendlies = true
|
-- mybluemantis.checkforfriendlies = true
|
||||||
--
|
--
|
||||||
-- ### 2.1.6 Shoot & Scoot
|
|
||||||
--
|
|
||||||
-- -- Option to make the (driveable) SHORAD units drive around and shuffle positions
|
|
||||||
-- -- We use a SET_ZONE for that, number of zones to consider defaults to three, Random is true for random coordinates and Formation is e.g. "Vee".
|
|
||||||
-- mybluemantis:AddScootZones(ZoneSet, Number, Random, Formation)
|
|
||||||
--
|
|
||||||
-- # 3. Default settings [both modes unless stated otherwise]
|
-- # 3. Default settings [both modes unless stated otherwise]
|
||||||
--
|
--
|
||||||
-- By default, the following settings are active:
|
-- By default, the following settings are active:
|
||||||
@@ -247,7 +243,25 @@
|
|||||||
--
|
--
|
||||||
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
||||||
--
|
--
|
||||||
-- # 5. Integrated SEAD
|
-- # 5. Integrate SHORAD [classic mode, not necessary in automode, not recommended for manual setup]
|
||||||
|
--
|
||||||
|
-- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs manually. 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()
|
||||||
|
--
|
||||||
|
-- If you systematically name your SHORAD groups starting with "Blue SHORAD" you'll need exactly **one** SHORAD instance to manage all SHORAD groups.
|
||||||
|
--
|
||||||
|
-- (Optionally) you can remove the link later on with
|
||||||
|
--
|
||||||
|
-- mymantis:RemoveShorad()
|
||||||
|
--
|
||||||
|
-- # 6. Integrated SEAD
|
||||||
--
|
--
|
||||||
-- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up!
|
-- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up!
|
||||||
-- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
-- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
||||||
@@ -322,8 +336,6 @@ MANTIS = {
|
|||||||
SmokeDecoy = false,
|
SmokeDecoy = false,
|
||||||
SmokeDecoyColor = SMOKECOLOR.White,
|
SmokeDecoyColor = SMOKECOLOR.White,
|
||||||
checkcounter = 1,
|
checkcounter = 1,
|
||||||
DLinkCacheTime = 120,
|
|
||||||
logsamstatus = false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Advanced state enumerator
|
--- Advanced state enumerator
|
||||||
@@ -362,7 +374,7 @@ MANTIS.radiusscale[MANTIS.SamType.POINT] = 3
|
|||||||
MANTIS.SamData = {
|
MANTIS.SamData = {
|
||||||
["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km
|
["Hawk"] = { Range=35, Blindspot=0, Height=12, Type="Medium", Radar="Hawk" }, -- measures in km
|
||||||
["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B
|
["NASAMS"] = { Range=14, Blindspot=0, Height=7, Type="Short", Radar="NSAMS" }, -- AIM 120B
|
||||||
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot str" },
|
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot" },
|
||||||
["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" },
|
["Rapier"] = { Range=10, Blindspot=0, Height=3, Type="Short", Radar="rapier" },
|
||||||
["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" },
|
["SA-2"] = { Range=40, Blindspot=7, Height=25, Type="Medium", Radar="S_75M_Volhov" },
|
||||||
["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
["SA-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
||||||
@@ -370,8 +382,7 @@ MANTIS.SamData = {
|
|||||||
["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" },
|
["SA-6"] = { Range=25, Blindspot=0, Height=8, Type="Medium", Radar="1S91" },
|
||||||
["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"},
|
["SA-10"] = { Range=119, Blindspot=0, Height=18, Type="Long" , Radar="S-300PS 4"},
|
||||||
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
["SA-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
||||||
["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", Radar="Roland" },
|
["Roland"] = { Range=5, Blindspot=0, Height=5, Type="Point", Radar="Roland" },
|
||||||
["Gepard"] = { Range=5, Blindspot=0, Height=4, Type="Point", Radar="Gepard" },
|
|
||||||
["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" },
|
["HQ-7"] = { Range=12, Blindspot=0, Height=3, Type="Short", Radar="HQ-7" },
|
||||||
["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" },
|
["SA-9"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Strela", Point="true" },
|
||||||
["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" },
|
["SA-8"] = { Range=10, Blindspot=0, Height=5, Type="Short", Radar="Osa 9A33" },
|
||||||
@@ -382,7 +393,6 @@ MANTIS.SamData = {
|
|||||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||||
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" },
|
["Linebacker"] = { Range=4, Blindspot=0, Height=3, Type="Point", Radar="Linebacker", Point="true" },
|
||||||
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
|
["Silkworm"] = { Range=90, Blindspot=1, Height=0.2, Type="Long", Radar="Silkworm" },
|
||||||
["HEMTT_C-RAM_Phalanx"] = { Range=2, Blindspot=0, Height=2, Type="Point", Radar="HEMTT_C-RAM_Phalanx", Point="true" },
|
|
||||||
-- units from HDS Mod, multi launcher options is tricky
|
-- units from HDS Mod, multi launcher options is tricky
|
||||||
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
["SA-10B"] = { Range=75, Blindspot=0, Height=18, Type="Medium" , Radar="SA-10B"},
|
||||||
["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" },
|
["SA-17"] = { Range=50, Blindspot=3, Height=30, Type="Medium", Radar="SA-17" },
|
||||||
@@ -615,7 +625,6 @@ do
|
|||||||
self.advAwacs = false
|
self.advAwacs = false
|
||||||
end
|
end
|
||||||
|
|
||||||
self:SetDLinkCacheTime()
|
|
||||||
|
|
||||||
-- Set the string id for output to DCS.log file.
|
-- Set the string id for output to DCS.log file.
|
||||||
self.lid=string.format("MANTIS %s | ", self.name)
|
self.lid=string.format("MANTIS %s | ", self.name)
|
||||||
@@ -649,8 +658,6 @@ do
|
|||||||
table.insert(self.ewr_templates,awacs)
|
table.insert(self.ewr_templates,awacs)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.logsamstatus = false
|
|
||||||
|
|
||||||
self:T({self.ewr_templates})
|
self:T({self.ewr_templates})
|
||||||
|
|
||||||
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition)
|
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition)
|
||||||
@@ -682,7 +689,7 @@ do
|
|||||||
|
|
||||||
-- TODO Version
|
-- TODO Version
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
self.version="0.9.30"
|
self.version="0.9.27"
|
||||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||||
|
|
||||||
--- FSM Functions ---
|
--- FSM Functions ---
|
||||||
@@ -1033,16 +1040,6 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function to set how long INTEL DLINK remembers contacts.
|
|
||||||
-- @param #MANTIS self
|
|
||||||
-- @param #number seconds Remember this many seconds, at least 5 seconds.
|
|
||||||
-- @return #MANTIS self
|
|
||||||
function MANTIS:SetDLinkCacheTime(seconds)
|
|
||||||
self.DLinkCacheTime = math.abs(seconds or 120)
|
|
||||||
if self.DLinkCacheTime < 5 then self.DLinkCacheTime = 5 end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Function to set the detection interval
|
--- Function to set the detection interval
|
||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
-- @param #number interval The interval in seconds
|
-- @param #number interval The interval in seconds
|
||||||
@@ -1434,9 +1431,7 @@ do
|
|||||||
--IntelTwo:SetClusterRadius(5000)
|
--IntelTwo:SetClusterRadius(5000)
|
||||||
IntelTwo:Start()
|
IntelTwo:Start()
|
||||||
|
|
||||||
local CacheTime = self.DLinkCacheTime or 120
|
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,300)
|
||||||
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,CacheTime)
|
|
||||||
|
|
||||||
IntelDlink:__Start(1)
|
IntelDlink:__Start(1)
|
||||||
|
|
||||||
self:SetUsingDLink(IntelDlink)
|
self:SetUsingDLink(IntelDlink)
|
||||||
@@ -1498,7 +1493,7 @@ do
|
|||||||
elseif chm then
|
elseif chm then
|
||||||
SAMData = self.SamDataCH
|
SAMData = self.SamDataCH
|
||||||
end
|
end
|
||||||
--self:I("Looking to auto-match for "..grpname)
|
--self:T("Looking to auto-match for "..grpname)
|
||||||
for _,_unit in pairs(units) do
|
for _,_unit in pairs(units) do
|
||||||
local unit = _unit -- Wrapper.Unit#UNIT
|
local unit = _unit -- Wrapper.Unit#UNIT
|
||||||
local type = string.lower(unit:GetTypeName())
|
local type = string.lower(unit:GetTypeName())
|
||||||
@@ -1699,9 +1694,7 @@ do
|
|||||||
local grpname = group:GetName()
|
local grpname = group:GetName()
|
||||||
local grpcoord = group:GetCoordinate()
|
local grpcoord = group:GetCoordinate()
|
||||||
local grprange, grpheight,type,blind = self:_GetSAMRange(grpname)
|
local grprange, grpheight,type,blind = self:_GetSAMRange(grpname)
|
||||||
-- TODO the below might stop working at some point after some hours, needs testing
|
local radaralive = group:IsSAM()
|
||||||
--local radaralive = group:IsSAM()
|
|
||||||
local radaralive = true
|
|
||||||
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type}) -- make the table lighter, as I don't really use the zone here
|
table.insert( SAM_Tbl, {grpname, grpcoord, grprange, grpheight, blind, type}) -- make the table lighter, as I don't really use the zone here
|
||||||
table.insert( SEAD_Grps, grpname )
|
table.insert( SEAD_Grps, grpname )
|
||||||
if type == MANTIS.SamType.LONG and radaralive then
|
if type == MANTIS.SamType.LONG and radaralive then
|
||||||
@@ -1863,7 +1856,7 @@ do
|
|||||||
end --end alive
|
end --end alive
|
||||||
end --end check
|
end --end check
|
||||||
end --for loop
|
end --for loop
|
||||||
if self.debug or self.verbose or self.logsamstatus then
|
if self.debug or self.verbose then
|
||||||
for _,_status in pairs(self.SamStateTracker) do
|
for _,_status in pairs(self.SamStateTracker) do
|
||||||
if _status == "GREEN" then
|
if _status == "GREEN" then
|
||||||
instatusgreen=instatusgreen+1
|
instatusgreen=instatusgreen+1
|
||||||
@@ -1884,9 +1877,8 @@ do
|
|||||||
-- @param #MANTIS self
|
-- @param #MANTIS self
|
||||||
-- @param Functional.Detection#DETECTION_AREAS detection Detection object
|
-- @param Functional.Detection#DETECTION_AREAS detection Detection object
|
||||||
-- @param #boolean dlink
|
-- @param #boolean dlink
|
||||||
-- @param #boolean reporttolog
|
|
||||||
-- @return #MANTIS self
|
-- @return #MANTIS self
|
||||||
function MANTIS:_Check(detection,dlink,reporttolog)
|
function MANTIS:_Check(detection,dlink)
|
||||||
self:T(self.lid .. "Check")
|
self:T(self.lid .. "Check")
|
||||||
--get detected set
|
--get detected set
|
||||||
local detset = detection:GetDetectedItemCoordinates()
|
local detset = detection:GetDetectedItemCoordinates()
|
||||||
@@ -1913,8 +1905,7 @@ do
|
|||||||
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
local samset = self:_GetSAMTable() -- table of i.1=names, i.2=coordinates, i.3=firing range, i.4=firing height
|
||||||
instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxclassic)
|
instatusred, instatusgreen, activeshorads = self:_CheckLoop(samset,detset,dlink,self.maxclassic)
|
||||||
end
|
end
|
||||||
|
if self.debug or self.verbose then
|
||||||
local function GetReport()
|
|
||||||
local statusreport = REPORT:New("\nMANTIS Status "..self.name)
|
local statusreport = REPORT:New("\nMANTIS Status "..self.name)
|
||||||
statusreport:Add("+-----------------------------+")
|
statusreport:Add("+-----------------------------+")
|
||||||
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
|
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
|
||||||
@@ -1923,15 +1914,7 @@ do
|
|||||||
statusreport:Add(string.format("+ SHORAD active: %2d",activeshorads))
|
statusreport:Add(string.format("+ SHORAD active: %2d",activeshorads))
|
||||||
end
|
end
|
||||||
statusreport:Add("+-----------------------------+")
|
statusreport:Add("+-----------------------------+")
|
||||||
return statusreport
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.debug or self.verbose then
|
|
||||||
local statusreport = GetReport()
|
|
||||||
MESSAGE:New(statusreport:Text(),10):ToAll():ToLog()
|
MESSAGE:New(statusreport:Text(),10):ToAll():ToLog()
|
||||||
elseif reporttolog == true then
|
|
||||||
local statusreport = GetReport()
|
|
||||||
MESSAGE:New(statusreport:Text(),10):ToLog()
|
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2039,7 +2022,7 @@ do
|
|||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
-- check detection
|
-- check detection
|
||||||
if not self.state2flag then
|
if not self.state2flag then
|
||||||
self:_Check(self.Detection,self.DLink,self.logsamstatus)
|
self:_Check(self.Detection,self.DLink)
|
||||||
end
|
end
|
||||||
|
|
||||||
local EWRAlive = self:_CheckAnyEWRAlive()
|
local EWRAlive = self:_CheckAnyEWRAlive()
|
||||||
|
|||||||
@@ -53,8 +53,6 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE.
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE.
|
||||||
-- Therefore, this class is considered to be deprecated and superseded by the [Functional.Fox](https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html) class, which provides the same functionality.
|
-- Therefore, this class is considered to be deprecated and superseded by the [Functional.Fox](https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Functional.Fox.html) class, which provides the same functionality.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ RANGE.MenuF10Root = nil
|
|||||||
|
|
||||||
--- Range script version.
|
--- Range script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RANGE.version = "2.8.1"
|
RANGE.version = "2.8.0"
|
||||||
|
|
||||||
-- TODO list:
|
-- TODO list:
|
||||||
-- TODO: Verbosity level for messages.
|
-- TODO: Verbosity level for messages.
|
||||||
@@ -2032,10 +2032,10 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
|
|||||||
|
|
||||||
-- Smoke impact point of bomb.
|
-- Smoke impact point of bomb.
|
||||||
if playerData and playerData.smokebombimpact and insidezone then
|
if playerData and playerData.smokebombimpact and insidezone then
|
||||||
if playerData.delaysmoke then
|
if playerData and playerData.delaysmoke then
|
||||||
impactcoord:Smoke(playerData.smokecolor, 30, self.TdelaySmoke)
|
timer.scheduleFunction( self._DelayedSmoke, { coord = impactcoord, color = playerData.smokecolor }, timer.getTime() + self.TdelaySmoke )
|
||||||
else
|
else
|
||||||
impactcoord:Smoke(playerData.smokecolor, 30)
|
impactcoord:Smoke( playerData.smokecolor )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2102,12 +2102,7 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
|
|||||||
result.attackHdg = attackHdg
|
result.attackHdg = attackHdg
|
||||||
result.attackVel = attackVel
|
result.attackVel = attackVel
|
||||||
result.attackAlt = attackAlt
|
result.attackAlt = attackAlt
|
||||||
if os and os.date then
|
result.date=os and os.date() or "n/a"
|
||||||
result.date=os.date()
|
|
||||||
else
|
|
||||||
self:E(self.lid.."os or os.date() not available")
|
|
||||||
result.date = "n/a"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add to table.
|
-- Add to table.
|
||||||
table.insert( _results, result )
|
table.insert( _results, result )
|
||||||
@@ -2640,6 +2635,13 @@ end
|
|||||||
-- Display Messages
|
-- Display Messages
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Start smoking a coordinate with a delay.
|
||||||
|
-- @param #table _args Argements passed.
|
||||||
|
function RANGE._DelayedSmoke( _args )
|
||||||
|
_args.coord:Smoke(_args.color)
|
||||||
|
--trigger.action.smoke( _args.coord:GetVec3(), _args.color )
|
||||||
|
end
|
||||||
|
|
||||||
--- Display top 10 stafing results of a specific player.
|
--- Display top 10 stafing results of a specific player.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string _unitName Name of the player unit.
|
-- @param #string _unitName Name of the player unit.
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||||
-- Therefore, this class is considered to be deprecated
|
-- Therefore, this class is considered to be deprecated
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -187,9 +187,9 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Tasking/Task_Cargo_Dispatcher
|
|||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Tasking/Task_Capture_Zone.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Tasking/Task_Capture_Zone.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Tasking/Task_Capture_Dispatcher.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Tasking/Task_Capture_Dispatcher.lua' )
|
||||||
|
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Point.lua' )
|
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Beacons.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Beacons.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Radios.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Point.lua' )
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Towns.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Procedure.lua' )
|
||||||
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/FlightPlan.lua' )
|
||||||
|
|
||||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Globals.lua' )
|
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Globals.lua' )
|
||||||
|
|||||||
@@ -181,7 +181,5 @@ __Moose.Include( 'Tasking\\Task_Capture_Dispatcher.lua' )
|
|||||||
|
|
||||||
__Moose.Include( 'Navigation\\Point.lua' )
|
__Moose.Include( 'Navigation\\Point.lua' )
|
||||||
__Moose.Include( 'Navigation\\Beacons.lua' )
|
__Moose.Include( 'Navigation\\Beacons.lua' )
|
||||||
__Moose.Include( 'Navigation\\Radios.lua' )
|
|
||||||
__Moose.Include( 'Navigation\\Towns.lua' )
|
|
||||||
|
|
||||||
__Moose.Include( 'Globals.lua' )
|
__Moose.Include( 'Globals.lua' )
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- **Main Features:**
|
-- **Main Features:**
|
||||||
--
|
--
|
||||||
-- * Access beacons of the map
|
-- * Beacons of the map
|
||||||
-- * Find closest beacon
|
|
||||||
-- * Get frequencies and channels
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -20,6 +18,7 @@
|
|||||||
-- @module Navigation.Beacons
|
-- @module Navigation.Beacons
|
||||||
-- @image NAVIGATION_Beacons.png
|
-- @image NAVIGATION_Beacons.png
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -33,132 +32,45 @@
|
|||||||
--
|
--
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- *Hope is the beacon that guides lost ships back to the shore.*
|
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # The BEACONS Concept
|
-- # The BEACONS Concept
|
||||||
--
|
--
|
||||||
-- This class is desinged to make information about beacons of a map/theatre easier accessible. The information contains location, type and frequencies of all or specific beacons of the map.
|
-- The NAVFIX class has a great concept!
|
||||||
--
|
--
|
||||||
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `beacons.lua` that can be
|
-- Bla, bla...
|
||||||
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
|
|
||||||
--
|
--
|
||||||
-- # Basic Setup
|
-- # Basic Setup
|
||||||
--
|
--
|
||||||
-- A new `BEACONS` object can be created with the @{#BEACONS.NewFromFile}(*beacons_lua_file*) function.
|
-- A new `BEACONS` object can be created with the @{#BEACONS.New}() function.
|
||||||
--
|
--
|
||||||
-- local beacons=BEACONS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\beacons.lua")
|
-- local beacons=BEACONS:New("G:\Games\DCS World Testing\Mods\terrains\GermanyColdWar\beacons.lua")
|
||||||
-- beacons:MarkerShow()
|
|
||||||
--
|
|
||||||
-- This will load the beacons from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
|
|
||||||
-- you provided is correct and all relevant beacons are present.
|
|
||||||
--
|
|
||||||
-- # User Functions
|
|
||||||
--
|
|
||||||
-- ## F10 Map Markers
|
|
||||||
--
|
|
||||||
-- ## Position
|
|
||||||
--
|
|
||||||
-- ## Get Closest Beacon
|
|
||||||
--
|
--
|
||||||
|
-- This is how it works.
|
||||||
--
|
--
|
||||||
-- @field #BEACONS
|
-- @field #BEACONS
|
||||||
BEACONS = {
|
BEACONS = {
|
||||||
ClassName = "BEACONS",
|
ClassName = "BEACONS",
|
||||||
verbose = 1,
|
verbose = 0,
|
||||||
beacons = {},
|
beacons = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Mission capability.
|
|
||||||
-- @type BEACONS.Beacon
|
|
||||||
-- @field #function display_name Function that returns the localized name.
|
|
||||||
-- @field #number type Beacon type.
|
|
||||||
-- @field #string beaconId Beacon ID.
|
|
||||||
-- @field #string callsign Call sign.
|
|
||||||
-- @field #number frequency Frequency in Hz.
|
|
||||||
-- @field #number channel TACAN, RSBN or PRMG channel depending on type.
|
|
||||||
-- @field #table position Position table.
|
|
||||||
-- @field #number direction Direction in degrees.
|
|
||||||
-- @field #table positionGeo Table with latitude and longitude.
|
|
||||||
-- @field #table sceneObjects Table with scenery objects, e.g. `{t:393396742}`.
|
|
||||||
-- @field #number chartOffsetX No idea what this offset is?!
|
|
||||||
-- @field DCS#Vec3 vec3 Position vector 3D.
|
|
||||||
-- @field #number markerID ID for the F10 marker.
|
|
||||||
-- @field #string typeName Name of becon type.
|
|
||||||
-- @field Wrapper.Scenery#SCENERY scenery The scenery object.
|
|
||||||
|
|
||||||
--- BEACONS class version.
|
--- BEACONS class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
BEACONS.version="0.0.4"
|
BEACONS.version="0.0.0"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: A lot...
|
-- TODO: A lot...
|
||||||
-- DONE: TACAN channel from frequency (was already in beacon.lua as channel)
|
|
||||||
-- DONE: Scenery object
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor(s)
|
-- Constructor(s)
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Create a new BECAONS class instance from a given table.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param #table BeaconTable Table with beacon info.
|
|
||||||
-- @return #BEACONS self
|
|
||||||
function BEACONS:NewFromTable(BeaconTable)
|
|
||||||
|
|
||||||
-- Inherit everything from BASE class.
|
|
||||||
self=BASE:Inherit(self, BASE:New()) -- #BEACONS
|
|
||||||
|
|
||||||
for _,_beacon in pairs(BeaconTable) do
|
|
||||||
local beacon=_beacon --#BEACONS.Beacon
|
|
||||||
|
|
||||||
-- Get 3D vector
|
|
||||||
beacon.vec3={x=beacon.position[1], y=beacon.position[2], z=beacon.position[3]}
|
|
||||||
|
|
||||||
-- Get coordinate
|
|
||||||
beacon.coordinate=COORDINATE:NewFromVec3(beacon.vec3)
|
|
||||||
|
|
||||||
-- Get type name
|
|
||||||
beacon.typeName=self:_GetTypeName(beacon.type)
|
|
||||||
|
|
||||||
-- Find closest scenery object from scan
|
|
||||||
beacon.scenery=beacon.coordinate:FindClosestScenery(20)
|
|
||||||
|
|
||||||
-- Debug stuff for scenery object
|
|
||||||
if false then
|
|
||||||
if beacon.scenery then
|
|
||||||
env.info(string.format("FF Beacon %s %s %s got scenery object %s, %s", beacon.callsign, beacon.beaconId, beacon.typeName, beacon.scenery:GetName(), beacon.scenery:GetTypeName() ))
|
|
||||||
UTILS.PrintTableToLog(beacon.scenery.SceneryObject)
|
|
||||||
UTILS.PrintTableToLog(beacon.sceneObjects)
|
|
||||||
else
|
|
||||||
env.info(string.format("FF NO scenery object %s %s %s ", beacon.callsign, beacon.beaconId, beacon.typeName))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add to table
|
|
||||||
table.insert(self.beacons, beacon)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug output
|
|
||||||
self:I(string.format("Added %d beacons", #self.beacons))
|
|
||||||
|
|
||||||
if self.verbose > 0 then
|
|
||||||
local text="Beacon types:"
|
|
||||||
for typeName,typeID in pairs(BEACON.Type) do
|
|
||||||
local n=self:CountBeacons(typeID)
|
|
||||||
text=text..string.format("\n%s = %d", typeName, n)
|
|
||||||
end
|
|
||||||
self:I(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Create a new BECAONS class instance from a given file.
|
--- Create a new BECAONS class instance from a given file.
|
||||||
-- @param #BEACONS self
|
-- @param #BEACONS self
|
||||||
-- @param #string FileName Full path to the file containing the map beacons.
|
-- @param #string FileName Full path to the file containing the map beacons.
|
||||||
@@ -168,19 +80,6 @@ function BEACONS:NewFromFile(FileName)
|
|||||||
-- Inherit everything from BASE class.
|
-- Inherit everything from BASE class.
|
||||||
self=BASE:Inherit(self, BASE:New()) -- #BEACONS
|
self=BASE:Inherit(self, BASE:New()) -- #BEACONS
|
||||||
|
|
||||||
local exists=UTILS.FileExists(FileName)
|
|
||||||
|
|
||||||
if exists==false then
|
|
||||||
self:E(string.format("ERROR: file with beacon info does not exist!"))
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This will create a global table `beacons`
|
|
||||||
dofile(FileName)
|
|
||||||
|
|
||||||
-- Get beacons from table.
|
|
||||||
self=self:NewFromTable(beacons)
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -188,141 +87,18 @@ end
|
|||||||
-- User Functions
|
-- User Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Get 3D position vector of a specific beacon.
|
--- Add marker all beacons on the F10 map.
|
||||||
-- @param #BEACONS self
|
-- @param #BEACONS self
|
||||||
-- @param #BEACONS.Beacon beacon The beacon data structure.
|
|
||||||
-- @return DCS#Vec3 Position vector.
|
|
||||||
function BEACONS:GetVec3(beacon)
|
|
||||||
return beacon.vec3
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get COORDINATE of a specific beacon.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param #BEACONS.Beacon beacon The beacon data structure.
|
|
||||||
-- @return Core.Point#COORDINATE The coordinate.
|
|
||||||
function BEACONS:GetCoordinate(beacon)
|
|
||||||
local coordinate=COORDINATE:NewFromVec3(beacon.vec3)
|
|
||||||
return coordinate
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Find closest beacon to a given coordinate.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
|
|
||||||
-- @param #number TypeID (Optional) Only search for specific beacon types, *e.g.* `BEACON.Type.TACAN`.
|
|
||||||
-- @param #number DistMax (Optional) Max search distance in meters.
|
|
||||||
-- @param #table ExcludeList (Optional) List of beacons to exclude.
|
|
||||||
-- @return #BEACONS.Beacon The closest beacon.
|
|
||||||
function BEACONS:GetClosestBeacon(Coordinate, TypeID, DistMax, ExcludeList)
|
|
||||||
|
|
||||||
local beacon=nil --#BEACONS.Beacon
|
|
||||||
local distmin=math.huge
|
|
||||||
|
|
||||||
ExcludeList=ExcludeList or {}
|
|
||||||
|
|
||||||
for _,_beacon in pairs(self.beacons) do
|
|
||||||
local bc=_beacon --#BEACONS.Beacon
|
|
||||||
|
|
||||||
if (TypeID==nil or TypeID==bc.type) and (not UTILS.IsInTable(ExcludeList, bc, "beaconId")) then
|
|
||||||
|
|
||||||
local dist=Coordinate:Get2DDistance(bc.vec3)
|
|
||||||
|
|
||||||
if dist<distmin and (DistMax==nil or dist<=DistMax) then
|
|
||||||
distmin=dist
|
|
||||||
beacon=bc
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return beacon
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get table of all beacons, optionally of a given type.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param #number TypeID (Optional) Only return specific beacon types, *e.g.* `BEACON.Type.TACAN`.
|
|
||||||
-- @return #table Table of beacons. Each element is of type #BEACON.Beacon.
|
|
||||||
function BEACONS:GetBeacons(TypeID)
|
|
||||||
|
|
||||||
local beacons={}
|
|
||||||
|
|
||||||
for _,_beacon in pairs(self.beacons) do
|
|
||||||
local bc=_beacon --#BEACONS.Beacon
|
|
||||||
|
|
||||||
if TypeID==nil or TypeID==bc.type then
|
|
||||||
table.insert(beacons, bc)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return beacons
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Count beacons, optionally of a given type.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param #number TypeID (Optional) Only count specific beacon types, *e.g.* `BEACON.Type.TACAN`.
|
|
||||||
-- @return #number Number of beacons.
|
|
||||||
function BEACONS:CountBeacons(TypeID)
|
|
||||||
|
|
||||||
local n=0
|
|
||||||
|
|
||||||
if TypeID then
|
|
||||||
for _,_beacon in pairs(self.beacons) do
|
|
||||||
local bc=_beacon --#BEACONS.Beacon
|
|
||||||
|
|
||||||
if TypeID==bc.type then
|
|
||||||
n=n+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
n=#self.beacons
|
|
||||||
end
|
|
||||||
|
|
||||||
return n
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add markers for all beacons on the F10 map. Optionally, only a specific beacon or a certain beacon type can be marked.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param #BEACONS.Beacon Beacon (Optional) Only this specifc beacon.
|
|
||||||
-- @param #number TypeID (Optional) Only show specific beacon types, *e.g.* `BEACON.Type.TACAN`.
|
|
||||||
-- @return #BEACONS self
|
-- @return #BEACONS self
|
||||||
function BEACONS:MarkerShow(Beacon, TypeID)
|
function BEACONS:MarkerShow()
|
||||||
|
|
||||||
for _,_beacon in pairs(self.beacons) do
|
|
||||||
local beacon=_beacon --#BEACONS.Beacon
|
|
||||||
if Beacon==nil or Beacon.beaconId==beacon.beaconId then
|
|
||||||
if TypeID==nil or beacon.type==TypeID then
|
|
||||||
local text=self:_GetMarkerText(beacon)
|
|
||||||
local coord=COORDINATE:NewFromVec3(beacon.vec3)
|
|
||||||
if beacon.markerID then
|
|
||||||
UTILS.RemoveMark(beacon.markerID)
|
|
||||||
end
|
|
||||||
beacon.markerID=coord:MarkToAll(text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove markers of all beacons from the F10 map. Optionally, remove only marker of a specific beacon or a certain beacon type.
|
--- Remove markers of all beacons from the F10 map.
|
||||||
-- @param #BEACONS self
|
-- @param #BEACONS self
|
||||||
-- @param #BEACONS.Beacon Beacon (Optional) Only this specifc beacon.
|
|
||||||
-- @param #number TypeID (Optional) Only show specific beacon types, *e.g.* `BEACON.Type.TACAN`.
|
|
||||||
-- @return #BEACONS self
|
-- @return #BEACONS self
|
||||||
function BEACONS:MarkerRemove(Beacon, TypeID)
|
function BEACONS:MarkerRemove()
|
||||||
|
|
||||||
for _,_beacon in pairs(self.beacons) do
|
|
||||||
local beacon=_beacon --#BEACONS.Beacon
|
|
||||||
if Beacon==nil or Beacon.beaconId==beacon.beaconId then
|
|
||||||
if TypeID==nil or beacon.type==TypeID then
|
|
||||||
if beacon.markerID then
|
|
||||||
UTILS.RemoveMark(beacon.markerID)
|
|
||||||
beacon.markerID=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -333,63 +109,31 @@ end
|
|||||||
|
|
||||||
--- Get text displayed in the F10 marker.
|
--- Get text displayed in the F10 marker.
|
||||||
-- @param #BEACONS self
|
-- @param #BEACONS self
|
||||||
-- @param #BEACONS.Beacon beacon The beacon data structure.
|
|
||||||
-- @return #string Marker text.
|
-- @return #string Marker text.
|
||||||
function BEACONS:_GetMarkerText(beacon)
|
function BEACONS:_GetMarkerText(beacon)
|
||||||
|
|
||||||
local frequency, funit=self:_GetFrequency(beacon.frequency)
|
local altmin=self.altMin and tostring(self.altMin) or ""
|
||||||
local direction=beacon.direction~=nil and beacon.direction or -1
|
local altmax=self.altMax and tostring(self.altMax) or ""
|
||||||
|
local speedmin=self.speedMin and tostring(self.speedMin) or ""
|
||||||
|
local speedmax=self.speedMax and tostring(self.speedMax) or ""
|
||||||
|
|
||||||
local text=string.format("Beacon %s [ID=%s]", tostring(beacon.typeName), tostring(beacon.beaconId))
|
|
||||||
text=text..string.format("\nCallsign: %s", tostring(beacon.callsign))
|
local text=string.format("NAVFIX %s", self.name)
|
||||||
if UTILS.IsInTable({BEACON.Type.TACAN, BEACON.Type.RSBN, BEACON.Type.PRMG_GLIDESLOPE, BEACON.Type.PRMG_LOCALIZER}, beacon.type) then
|
if self.isIAF then
|
||||||
text=text..string.format("\nChannel: %s", tostring(beacon.channel))
|
text=text..string.format(" (IAF)")
|
||||||
end
|
end
|
||||||
text=text..string.format("\nFrequency: %.3f %s", frequency, funit)
|
if self.isIF then
|
||||||
text=text..string.format("\nDirection: %.1f°", direction)
|
text=text..string.format(" (IF)")
|
||||||
|
end
|
||||||
|
text=text..string.format("\nAltitude [ft]: %s - %s", altmin, altmax)
|
||||||
|
text=text..string.format("\nSpeed [knots]: %s - %s", speedmin, speedmax)
|
||||||
|
text=text..string.format("\nCompulsory: %s", tostring(self.isCompulsory))
|
||||||
|
text=text..string.format("\nFly Over: %s", tostring(self.isFlyover))
|
||||||
|
|
||||||
return text
|
return text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get converted frequency.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param #number freq Frequency in Hz.
|
|
||||||
-- @return #number Frequency in better unit.
|
|
||||||
-- @return #string Unit ("Hz", "kHz", "MHz").
|
|
||||||
function BEACONS:_GetFrequency(freq)
|
|
||||||
|
|
||||||
freq=freq or 0
|
|
||||||
local unit="Hz"
|
|
||||||
|
|
||||||
if freq>=1e6 then
|
|
||||||
freq=freq/1e6
|
|
||||||
unit="MHz"
|
|
||||||
elseif freq>=1e3 then
|
|
||||||
freq=freq/1e3
|
|
||||||
unit="kHz"
|
|
||||||
end
|
|
||||||
|
|
||||||
return freq, unit
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get name of beacon type.
|
|
||||||
-- @param #BEACONS self
|
|
||||||
-- @param #number typeID Beacon type number.
|
|
||||||
-- @return #string Type name.
|
|
||||||
function BEACONS:_GetTypeName(typeID)
|
|
||||||
|
|
||||||
if typeID~=nil then
|
|
||||||
for typeName,_typeID in pairs(BEACON.Type) do
|
|
||||||
if _typeID==typeID then
|
|
||||||
return typeName
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return "Unknown"
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
481
Moose Development/Moose/Navigation/FlightPlan.lua
Normal file
481
Moose Development/Moose/Navigation/FlightPlan.lua
Normal file
@@ -0,0 +1,481 @@
|
|||||||
|
--- **NAVIGATION** - Flight Plan.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Manage navigation aids
|
||||||
|
-- * VOR, NDB
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Ops%20-%20FlightPlan).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Navigation.FlightPlan
|
||||||
|
-- @image NAVIGATION_FlightPlan.png
|
||||||
|
|
||||||
|
|
||||||
|
--- FLIGHTPLAN class.
|
||||||
|
-- @type FLIGHTPLAN
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number verbose Verbosity of output.
|
||||||
|
-- @field #table fixes Navigation fixes.
|
||||||
|
-- @field Core.Pathline#PATHLINE pathline Pathline of the plan.
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE departureAirbase Departure airbase.
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE destinationAirbase Destination airbase.
|
||||||
|
-- @field #number altitudeCruiseMin Minimum cruise altitude in feet MSL.
|
||||||
|
-- @field #number altitudeCruiseMax Maximum cruise altitude in feet MSL.
|
||||||
|
-- @extends Core.Pathline#PATHLINE
|
||||||
|
|
||||||
|
--- *Life is what happens to us while we are making other plans.* -- Allen Saunders
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The FLIGHTPLAN Concept
|
||||||
|
--
|
||||||
|
-- This class has a great concept!
|
||||||
|
--
|
||||||
|
-- # Basic Setup
|
||||||
|
--
|
||||||
|
-- A new `FLIGHTPLAN` object can be created with the @{#FLIGHTPLAN.New}() function.
|
||||||
|
--
|
||||||
|
-- myFlightplan=FLIGHTPLAN:New("Plan A")
|
||||||
|
-- myFleet:SetPortZone(ZonePort1stFleet)
|
||||||
|
-- myFleet:Start()
|
||||||
|
--
|
||||||
|
-- A fleet needs a *port zone*, which is set via the @{#FLIGHTPLAN.SetPortZone}(`PortZone`) function. This is the zone where the naval assets are spawned and return to.
|
||||||
|
--
|
||||||
|
-- Finally, the fleet needs to be started using the @{#FLIGHTPLAN.Start}() function. If the fleet is not started, it will not process any requests.
|
||||||
|
--
|
||||||
|
-- @field #FLIGHTPLAN
|
||||||
|
FLIGHTPLAN = {
|
||||||
|
ClassName = "FLIGHTPLAN",
|
||||||
|
verbose = 0,
|
||||||
|
fixes = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Type of flightplan.
|
||||||
|
-- @type FLIGHTPLAN.Type
|
||||||
|
-- @field #string IFRH Instrument Flying Rules High Altitude.
|
||||||
|
-- @field #string IFRL Instrument Flying Rules Low Altitude.
|
||||||
|
-- @field #string VFR Visual Flight Rules.
|
||||||
|
FLIGHTPLAN.Type={
|
||||||
|
IFRH = "IFR High",
|
||||||
|
IFRL = "IFR Low",
|
||||||
|
VFR = "VFR",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--- FLIGHTPLAN class version.
|
||||||
|
-- @field #string version
|
||||||
|
FLIGHTPLAN.version="0.0.1"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- ToDo list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: How to connect SID, STAR, ENROUTE, TRANSITION, APPROACH. Typical flightplan SID --> ENROUTE --> STAR --> APPROACH
|
||||||
|
-- TODO: Add approach.
|
||||||
|
-- DONE: How to handle the FLIGHTGROUP:_LandAtAirBase
|
||||||
|
-- TODO: Do we always need a holding pattern? https://www.faa.gov/air_traffic/publications/atpubs/aip_html/part2_enr_section_1.5.html#:~:text=If%20no%20holding%20pattern%20is,than%20that%20desired%20by%20ATC.
|
||||||
|
-- DOEN: Read from MSFS file.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new FLIGHTPLAN instance.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param #string Name Name of this flight plan.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:New(Name)
|
||||||
|
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
self=BASE:Inherit(self, PATHLINE:New(Name)) -- #FLIGHTPLAN
|
||||||
|
|
||||||
|
-- Set alias.
|
||||||
|
self.alias=tostring(Name)
|
||||||
|
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("FLIGHTPLAN %s | ", self.alias)
|
||||||
|
|
||||||
|
--self.pathline=PATHLINE:New(Name)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:I(self.lid..string.format("Created FLIGHTPLAN!"))
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a new FLIGHTPLAN instance from another FLIGHTPLAN acting as blue print.
|
||||||
|
-- The newly created flight plan is deep copied from the given one.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param #FLIGHTPLAN FlightPlan Blue print of the flight plan to copy.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:NewFromFlightPlan(FlightPlan)
|
||||||
|
self=UTILS.DeepCopy(FlightPlan)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Create a new FLIGHTPLAN instance from a given file.
|
||||||
|
-- Currently, the file has to be an MSFS 2020 .pln file as, *e.g.*, exported from [Navigraph](https://navigraph.com/).
|
||||||
|
--
|
||||||
|
-- **Note** that the flight plan does only cover the departure, enroute and arrival portions but **not the approach** part!
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param #string FileName Full path to file.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:NewFromFile(FileName)
|
||||||
|
|
||||||
|
if UTILS.FileExists(FileName) then
|
||||||
|
|
||||||
|
self=FLIGHTPLAN._ReadFileMSFS(FileName)
|
||||||
|
|
||||||
|
else
|
||||||
|
error(string.format("ERROR: File not found! File name=%s", tostring(FileName)))
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Add navigation fix to the flight plan.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param Navigation.Point#NAVPOINT NavFix The nav fix.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:AddNavFix(NavFix)
|
||||||
|
|
||||||
|
table.insert(self.fixes, NavFix)
|
||||||
|
|
||||||
|
local point=self:AddPointFromVec3(NavFix.vector:GetVec3(true))
|
||||||
|
|
||||||
|
point.navpoint=NavFix
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set departure airbase.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param #string AirbaseName Name of the airbase or AIRBASE object.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:SetDepartureAirbase(AirbaseName)
|
||||||
|
|
||||||
|
self.departureAirbase=AIRBASE:FindByName(AirbaseName)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set destination airbase.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param #string AirbaseName Name of the airbase or AIRBASE object.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:SetDestinationAirbase(AirbaseName)
|
||||||
|
|
||||||
|
self.destinationAirbase=AIRBASE:FindByName(AirbaseName)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set cruise altitude.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param #number AltMin Minimum altitude in feet MSL.
|
||||||
|
-- @param #number AltMax Maximum altitude in feet MSL. Default is `AltMin`.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:SetCruiseAltitude(AltMin, AltMax)
|
||||||
|
|
||||||
|
self.altitudeCruiseMin=AltMin
|
||||||
|
self.altitudeCruiseMax=AltMax or self.altitudeCruiseMin
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set cruise speed.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @param #number SpeedMin Minimum speed in knots.
|
||||||
|
-- @param #number SpeedMax Maximum speed in knots. Default is `SpeedMin`.
|
||||||
|
-- @return #FLIGHTPLAN self
|
||||||
|
function FLIGHTPLAN:SetCruiseSpeed(SpeedMin, SpeedMax)
|
||||||
|
|
||||||
|
self.speedCruiseMin=SpeedMin
|
||||||
|
self.speedCruiseMax=SpeedMax or self.speedCruiseMin
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the name of this flight plan.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @return #string The name.
|
||||||
|
function FLIGHTPLAN:GetName()
|
||||||
|
return self.alias
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get cruise altitude. This returns a random altitude between the set min/max cruise altitudes.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @return #number Cruise altitude in feet MSL.
|
||||||
|
function FLIGHTPLAN:GetCruiseAltitude()
|
||||||
|
|
||||||
|
local alt=10000
|
||||||
|
if self.altitudeCruiseMin and self.altitudeCruiseMax then
|
||||||
|
alt=math.random(self.altitudeCruiseMin, self.altitudeCruiseMax)
|
||||||
|
elseif self.altitudeCruiseMin then
|
||||||
|
alt=self.altitudeCruiseMin
|
||||||
|
elseif self.altitudeCruiseMax then
|
||||||
|
alt=self.altitudeCruiseMax
|
||||||
|
end
|
||||||
|
|
||||||
|
return alt
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get cruise speed. This returns a random speed between the set min/max cruise speeds.
|
||||||
|
-- @param #FLIGHTPLAN self
|
||||||
|
-- @return #number Cruise speed in knots.
|
||||||
|
function FLIGHTPLAN:GetCruiseSpeed()
|
||||||
|
|
||||||
|
local speed=250
|
||||||
|
|
||||||
|
if self.speedCruiseMin and self.speedCruiseMax then
|
||||||
|
speed=math.random(self.speedCruiseMin, self.speedCruiseMax)
|
||||||
|
elseif self.speedCruiseMin then
|
||||||
|
speed=self.speedCruiseMin
|
||||||
|
elseif self.altitudeCruiseMax then
|
||||||
|
speed=self.speedCruiseMax
|
||||||
|
end
|
||||||
|
|
||||||
|
return speed
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Private Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Read flight plan from a given MSFS 2020 .plt file.
|
||||||
|
-- @param #string FileName Name of the file.
|
||||||
|
-- @return #FLIGHTPLAN The flight plan.
|
||||||
|
function FLIGHTPLAN._ReadFileMSFS(FileName)
|
||||||
|
|
||||||
|
local function readfile(filename)
|
||||||
|
|
||||||
|
local lines = {}
|
||||||
|
|
||||||
|
-- Open file in read binary mode.
|
||||||
|
local file=assert(io.open(filename, "rb"), string.format("File not found! File name = %s", tostring(filename)))
|
||||||
|
|
||||||
|
for line in file:lines() do
|
||||||
|
lines[#lines+1] = line
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Close file.
|
||||||
|
file:close()
|
||||||
|
|
||||||
|
-- Return data
|
||||||
|
return lines
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- This function returns an XML element, i.e. the string between <...> and </...>.
|
||||||
|
local function getXMLelement(line)
|
||||||
|
local element=string.match(line, ">(.+)<")
|
||||||
|
return element
|
||||||
|
end
|
||||||
|
|
||||||
|
--- This function returns Latitude and Longitude
|
||||||
|
local function getLatLong(line)
|
||||||
|
local latlong=getXMLelement(line)
|
||||||
|
-- The format is "N41° 38' 20.00",E41° 33' 19.00",+000000.00" so we still need to process that.
|
||||||
|
local lat,long=string.match(latlong, "(.+),(.+),")
|
||||||
|
return lat,long
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Read data from file.
|
||||||
|
local data=readfile(FileName)
|
||||||
|
|
||||||
|
local flightplan={}
|
||||||
|
local waypoints={}
|
||||||
|
local wp=nil
|
||||||
|
|
||||||
|
local gotwaypoint=false
|
||||||
|
for i,line in pairs(data) do
|
||||||
|
|
||||||
|
|
||||||
|
--print(line)
|
||||||
|
|
||||||
|
-- Title
|
||||||
|
if string.find(line, "<Title>") then
|
||||||
|
flightplan.title=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Departure ICAO
|
||||||
|
if string.find(line, "<DepartureID>") then
|
||||||
|
flightplan.departureICAO=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Destination ICAO
|
||||||
|
if string.find(line, "<DestinationID>") then
|
||||||
|
flightplan.destinationICAO=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FPType
|
||||||
|
if string.find(line, "<FPType>") then
|
||||||
|
flightplan.plantype=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Route type
|
||||||
|
if string.find(line, "<RouteType>") then
|
||||||
|
flightplan.routetype=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cruise alt in feet
|
||||||
|
if string.find(line, "<CruisingAlt>") then
|
||||||
|
flightplan.altCruise=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Departure LLA
|
||||||
|
if string.find(line, "<DepartureLLA>") then
|
||||||
|
local lat,long=getLatLong(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Destination LLA
|
||||||
|
if string.find(line, "<DestinationLLA>") then
|
||||||
|
local lat,long=getLatLong(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Departure Name
|
||||||
|
if string.find(line, "<DepartureName>") then
|
||||||
|
local DepartureName=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- DestinationName
|
||||||
|
if string.find(line, "<DestinationName>") then
|
||||||
|
local DestinationName=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Waypoint stuff
|
||||||
|
---
|
||||||
|
|
||||||
|
-- New waypoint starts.
|
||||||
|
if string.find(line, "ATCWaypoint id") then
|
||||||
|
|
||||||
|
--Get string inside quotes " and ".
|
||||||
|
local wpid=string.match(line, [["(.+)"]])
|
||||||
|
|
||||||
|
-- Create a new wp table.
|
||||||
|
wp={}
|
||||||
|
|
||||||
|
-- Set waypoint name.
|
||||||
|
wp.name=wpid
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Waypoint info ends.
|
||||||
|
if string.find(line, "</ATCWaypoint>") then
|
||||||
|
-- This is the end of the waypoint.
|
||||||
|
|
||||||
|
-- Add info to waypoints table.
|
||||||
|
table.insert(waypoints, wp)
|
||||||
|
|
||||||
|
-- Set waypoint to nil. We create an empty table if the next wp starts.
|
||||||
|
wp=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Waypoint type (Airport, Intersection, NDB, VORTAC)
|
||||||
|
if string.find(line, "<ATCWaypointType>") then
|
||||||
|
local wptype=getXMLelement(line)
|
||||||
|
wp.type=wptype
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Waypoint position.
|
||||||
|
if string.find(line, "<WorldPosition>") then
|
||||||
|
wp.lat, wp.long=getLatLong(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Runway should exist for initial and final WP if it is an airport.
|
||||||
|
if string.find(line, "RunwayNumberFP") then
|
||||||
|
wp.runway=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Runway designator: LEFT, RIGHT, CENTER
|
||||||
|
if string.find(line, "RunwayDesignatorFP") then
|
||||||
|
wp.runwayDesignator=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Segment is Departure
|
||||||
|
if string.find(line, "<DepartureFP>") then
|
||||||
|
wp.segment="Departure"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Segment is Arrival
|
||||||
|
if string.find(line, "<ArrivalFP>") then
|
||||||
|
wp.segment="Arrival"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Segment is Enroute
|
||||||
|
if string.find(line, "<ATCAirway>") then
|
||||||
|
wp.segment="Enroute"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Approach type: VORDME, LOCALIZER
|
||||||
|
if string.find(line, "ApproachTypeFP") then
|
||||||
|
flightplan.approachtype=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Approach type suffic: Z
|
||||||
|
if string.find(line, "SuffixFP") then
|
||||||
|
local SuffixFP=getXMLelement(line)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, value in pairs(flightplan) do
|
||||||
|
env.info(string.format("Flightplan %s=%s", key, tostring(value)))
|
||||||
|
end
|
||||||
|
|
||||||
|
env.info(string.format("Number of waypoints=%d", #waypoints))
|
||||||
|
for i,wp in pairs(waypoints) do
|
||||||
|
env.info(string.format("Waypoint name=%s type=%s segment=%s runway=%s lat=%s long=%s", wp.name, wp.type, tostring(wp.segment), tostring(wp.runway)..tostring(wp.runwayDesignator or ""), wp.lat, wp.long))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create a new flightplan.
|
||||||
|
local fp=FLIGHTPLAN:New(flightplan.title)
|
||||||
|
|
||||||
|
-- Set cruise altitude.
|
||||||
|
fp:SetCruiseAltitude(flightplan.altCruise)
|
||||||
|
|
||||||
|
-- Set departure and destination airports.
|
||||||
|
fp:SetDepartureAirbase(flightplan.departureICAO)
|
||||||
|
fp:SetDestinationAirbase(flightplan.destinationICAO)
|
||||||
|
|
||||||
|
--TODO: Remove first and last waypoint if they are identical to the departure/destination airport!
|
||||||
|
|
||||||
|
for i,wp in pairs(waypoints) do
|
||||||
|
|
||||||
|
-- Create a navpoint.
|
||||||
|
local navpoint=NAVPOINT:NewFromLLDMS(wp.name, wp.type, wp.lat, wp.long)
|
||||||
|
|
||||||
|
navpoint:SetAltMin(flightplan.altCruise)
|
||||||
|
|
||||||
|
-- Add point to flightplan.
|
||||||
|
-- TODO: section departure, enroute, arrival.
|
||||||
|
fp:AddNavFix(navpoint)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return fp
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
333
Moose Development/Moose/Navigation/Procedure.lua
Normal file
333
Moose Development/Moose/Navigation/Procedure.lua
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
--- **NAVIGATION** - Prodedures for Departure (*e.g.* SID), Enroute, Arrival (*e.g.* STAR) and Approach.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Stuff
|
||||||
|
-- * More Stuff
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Template).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Navigation.Procedure
|
||||||
|
-- @image NAVIGATION_Procedure.png
|
||||||
|
|
||||||
|
|
||||||
|
--- APPROACH class.
|
||||||
|
-- @type APPROACH
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number verbose Verbosity of output.
|
||||||
|
-- @field #string apptype Approach type (ILS, VOR, LOC).
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE airbase Airbase of this approach.
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE.Runway runway Runway of this approach.
|
||||||
|
-- @field Navigation.Point#NAVAID navaid Primary navigation aid.
|
||||||
|
-- @field #number wpcounter Running number counting the waypoints to generate its UID.
|
||||||
|
-- @list <#APPROACH.Waypoint> path Path of approach consisting of waypoints.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The APPROACH Concept
|
||||||
|
--
|
||||||
|
-- A typical approach has (up to) four segments. It starts with the initial approach segment, followed by the intermediate approach segment, followed
|
||||||
|
-- by the final approach segment. In case something goes wrong during the final approach, the missed approach segment kicks in.
|
||||||
|
--
|
||||||
|
-- The initial approach segment starts at the initial approach fix (IAF). The segment can contain multiple other fixes, that need to be passed.
|
||||||
|
-- Note, that an approach procedure can have more than one intitial approach segment and IAF.
|
||||||
|
--
|
||||||
|
-- The intermediate approach segment starts at the intermediate fix (IF). The intermediate approach segment blends the initial approach segment into the final approach segment.
|
||||||
|
-- It is the segment in which aircraft configuration, speed, and positioning adjustments are made for entry into the final approach segment.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- https://en.wikipedia.org/wiki/Visual_approach
|
||||||
|
-- https://en.wikipedia.org/wiki/Instrument_approach
|
||||||
|
--
|
||||||
|
-- # Basic Setup
|
||||||
|
--
|
||||||
|
-- A new `APPROACH` object can be created with the @{#APPROACH.New}() function.
|
||||||
|
--
|
||||||
|
-- myTemplate=APPROACH:New()
|
||||||
|
-- myTemplate:SetXYZ(X, Y, Z)
|
||||||
|
--
|
||||||
|
-- This is how it works.
|
||||||
|
--
|
||||||
|
-- @field #APPROACH
|
||||||
|
APPROACH = {
|
||||||
|
ClassName = "APPROACH",
|
||||||
|
verbose = 0,
|
||||||
|
wpcounter = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Type of approach.
|
||||||
|
-- @type APPROACH.Type
|
||||||
|
-- @field #string VFR Visual Flight Rules.
|
||||||
|
-- @field #string VOR VOR
|
||||||
|
-- @field #string NDB NDB
|
||||||
|
APPROACH.Type={
|
||||||
|
VFR="VFR",
|
||||||
|
VOR="VOR",
|
||||||
|
ILS="ILS",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--- Setments of approach.
|
||||||
|
-- @type APPROACH.Segment
|
||||||
|
-- @field #string INITIAL Initial approach segment.
|
||||||
|
-- @field #string INTERMEDIATE Intermediate approach segment.
|
||||||
|
-- @field #string FINAL Final approach segment.
|
||||||
|
-- @field #string MISSED Missed approach segment.
|
||||||
|
APPROACH.Segment={
|
||||||
|
INITIAL="Initial",
|
||||||
|
INTERMEDIATE="Intermediate",
|
||||||
|
FINAL="Final",
|
||||||
|
MISSED="Missed",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Waypoint of the approach.
|
||||||
|
-- @type APPROACH.Waypoint
|
||||||
|
-- @field #number uid Unique ID of the point.
|
||||||
|
-- @field #string segment The segment this point belongs to.
|
||||||
|
-- @field Navigation.Point#NAVFIX navfix The navigation fix that determines the coordinates of this point.
|
||||||
|
|
||||||
|
--- APPROACH class version.
|
||||||
|
-- @field #string version
|
||||||
|
APPROACH.version="0.0.1"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- ToDo list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: A lot...
|
||||||
|
-- Initial approach segment --> Intermediate approach segment: starts at IF --> Final approach segment
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new APPROACH class instance.
|
||||||
|
-- @param #APPROACH self
|
||||||
|
-- @param #string Type Type of approach (ILS, VOR, LOC).
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase The airbase or name of the airbase.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE.Runway Runway The runway or name of the runway.
|
||||||
|
-- @return #APPROACH self
|
||||||
|
function APPROACH:New(Type, Airbase, Runway)
|
||||||
|
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
self=BASE:Inherit(self, BASE:New()) -- #APPROACH
|
||||||
|
|
||||||
|
-- Set approach type.
|
||||||
|
-- TODO: Check if this is a valid/known approach type.
|
||||||
|
self.apptype=Type
|
||||||
|
|
||||||
|
if type(Airbase)=="string" then
|
||||||
|
self.airbase=AIRBASE:FindByName(Airbase)
|
||||||
|
else
|
||||||
|
self.airbase=Airbase
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(Runway)=="string" then
|
||||||
|
self.runway=self.airbase:GetRunwayByName(Runway)
|
||||||
|
else
|
||||||
|
self.runway=Runway
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:I("Created new approach for airbase %s: type=%s, runway=%s", self.airbase:GetName(), self.apptype, self.runway.name)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set the primary navigation aid used in the approach.
|
||||||
|
-- @param #APPROACH self
|
||||||
|
-- @param Navigation.Point#NAVAID NavAid The NAVAID.
|
||||||
|
-- @return #APPROACH self
|
||||||
|
function APPROACH:SetNavAid(NavAid)
|
||||||
|
|
||||||
|
self.navaid=NavAid
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a waypoint to the path of the approach.
|
||||||
|
-- @param #APPROACH self
|
||||||
|
-- @param Navigation.Point#NAVFIX NavFix The navigation fix.
|
||||||
|
-- @param #string Segment The approach segment this fix belongs to.
|
||||||
|
-- @return #APPROACH.Waypoint The waypoint data table.
|
||||||
|
function APPROACH:AddNavFix(NavFix, Segment)
|
||||||
|
|
||||||
|
self.wpcounter=self.wpcounter+1
|
||||||
|
|
||||||
|
local point={} --#APPROACH.Waypoint
|
||||||
|
point.uid=self.wpcounter
|
||||||
|
point.segment=Segment
|
||||||
|
point.navfix=NavFix
|
||||||
|
|
||||||
|
table.insert(self.path, point)
|
||||||
|
|
||||||
|
return point
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Private Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Add private functions here.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- DEPARTURE class.
|
||||||
|
-- @type DEPARTURE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number verbose Verbosity of output.
|
||||||
|
-- @field #string apptype DEPARTURE type (ILS, VOR, LOC).
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE airbase Airbase of this DEPARTURE.
|
||||||
|
-- @field Wrapper.Airbase#AIRBASE.Runway runway Runway of this DEPARTURE.
|
||||||
|
-- @field Navigation.Point#NAVAID navaid Primary navigation aid.
|
||||||
|
-- @field #number wpcounter Running number counting the waypoints to generate its UID.
|
||||||
|
-- @list <#DEPARTURE.Waypoint> path Path of DEPARTURE consisting of waypoints.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The DEPARTURE Concept
|
||||||
|
--
|
||||||
|
-- Bla.
|
||||||
|
--
|
||||||
|
-- @field #DEPARTURE
|
||||||
|
DEPARTURE = {
|
||||||
|
ClassName = "DEPARTURE",
|
||||||
|
verbose = 0,
|
||||||
|
wpcounter = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Type of DEPARTURE.
|
||||||
|
-- @type DEPARTURE.Type
|
||||||
|
-- @field #string VOR VOR
|
||||||
|
-- @field #string NDB NDB
|
||||||
|
DEPARTURE.Type={
|
||||||
|
VOR="VOR",
|
||||||
|
ILS="ILS",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--- Setments of DEPARTURE.
|
||||||
|
-- @type DEPARTURE.Segment
|
||||||
|
-- @field #string INITIAL Initial DEPARTURE segment.
|
||||||
|
-- @field #string INTERMEDIATE Intermediate DEPARTURE segment.
|
||||||
|
-- @field #string FINAL Final DEPARTURE segment.
|
||||||
|
-- @field #string MISSED Missed DEPARTURE segment.
|
||||||
|
DEPARTURE.Segment={
|
||||||
|
INITIAL="Initial",
|
||||||
|
INTERMEDIATE="Intermediate",
|
||||||
|
FINAL="Final",
|
||||||
|
MISSED="Missed",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Waypoint of the DEPARTURE.
|
||||||
|
-- @type DEPARTURE.Waypoint
|
||||||
|
-- @field #number uid Unique ID of the point.
|
||||||
|
-- @field #string segment The segment this point belongs to.
|
||||||
|
-- @field Navigation.Point#NAVFIX navfix The navigation fix that determines the coordinates of this point.
|
||||||
|
|
||||||
|
--- DEPARTURE class version.
|
||||||
|
-- @field #string version
|
||||||
|
DEPARTURE.version="0.0.1"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- ToDo list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: A lot...
|
||||||
|
-- Initial DEPARTURE segment --> Intermediate DEPARTURE segment: starts at IF --> Final DEPARTURE segment
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new DEPARTURE class instance.
|
||||||
|
-- @param #DEPARTURE self
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase The airbase or name of the airbase.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE.Runway Runway The runway or name of the runway.
|
||||||
|
-- @param #string Type Type of DEPARTURE (ILS, VOR, LOC).
|
||||||
|
-- @return #DEPARTURE self
|
||||||
|
function DEPARTURE:New(Airbase, Runway)
|
||||||
|
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
self=BASE:Inherit(self, BASE:New()) -- #DEPARTURE
|
||||||
|
|
||||||
|
if type(Airbase)=="string" then
|
||||||
|
self.airbase=AIRBASE:FindByName(Airbase)
|
||||||
|
else
|
||||||
|
self.airbase=Airbase
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(Runway)=="string" then
|
||||||
|
self.runway=self.airbase:GetRunwayByName(Runway)
|
||||||
|
else
|
||||||
|
self.runway=Runway
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set the primary navigation aid used in the DEPARTURE.
|
||||||
|
-- @param #DEPARTURE self
|
||||||
|
-- @param Navigation.Point#NAVAID NavAid The NAVAID.
|
||||||
|
-- @return #DEPARTURE self
|
||||||
|
function DEPARTURE:SetNavAid(NavAid)
|
||||||
|
|
||||||
|
self.navaid=NavAid
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a waypoint to the path of the DEPARTURE.
|
||||||
|
-- @param #DEPARTURE self
|
||||||
|
-- @param Navigation.Point#NAVFIX NavFix The navigation fix.
|
||||||
|
-- @param #string Segment The DEPARTURE segment this fix belongs to.
|
||||||
|
-- @return #DEPARTURE.Waypoint The waypoint data.
|
||||||
|
function DEPARTURE:AddWaypoint(NavFix, Segment)
|
||||||
|
|
||||||
|
self.wpcounter=self.wpcounter+1
|
||||||
|
|
||||||
|
local point={} --#DEPARTURE.Waypoint
|
||||||
|
point.uid=self.wpcounter
|
||||||
|
point.segment=Segment
|
||||||
|
point.navfix=NavFix
|
||||||
|
|
||||||
|
table.insert(self.path, point)
|
||||||
|
|
||||||
|
return point
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Private Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Add DEPARTURE private functions here.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -1,324 +0,0 @@
|
|||||||
--- **NAVIGATION** - Airbase radios.
|
|
||||||
--
|
|
||||||
-- **Main Features:**
|
|
||||||
--
|
|
||||||
-- * Get radio frequencies of airbases
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- ## Example Missions:
|
|
||||||
--
|
|
||||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Radios).
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- ### Author: **funkyfranky**
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
-- @module Navigation.Radios
|
|
||||||
-- @image NAVIGATION_Radios.png
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- RADIOS class.
|
|
||||||
-- @type RADIOS
|
|
||||||
--
|
|
||||||
-- @field #string ClassName Name of the class.
|
|
||||||
-- @field #number verbose Verbosity of output.
|
|
||||||
-- @field #table radios Radios.
|
|
||||||
--
|
|
||||||
-- @extends Core.Base#BASE
|
|
||||||
|
|
||||||
--- *It's not true I had nothing on, I had the radio on.* -- *Marilyn Monroe*
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- # The RADIOS Concept
|
|
||||||
--
|
|
||||||
-- This class is desinged to make information about radios of a map/theatre easier accessible. The information contains mostly the frequencies of airbases of the map.
|
|
||||||
--
|
|
||||||
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `radio.lua` that can be
|
|
||||||
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
|
|
||||||
--
|
|
||||||
-- # Basic Setup
|
|
||||||
--
|
|
||||||
-- A new `RADIOS` object can be created with the @{#RADIOS.NewFromFile}(*radio_lua_file*) function.
|
|
||||||
--
|
|
||||||
-- local radios=RADIOS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\radios.lua")
|
|
||||||
-- radios:MarkerShow()
|
|
||||||
--
|
|
||||||
-- This will load the radios from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
|
|
||||||
-- you provided is correct and all relevant radios are present.
|
|
||||||
--
|
|
||||||
-- # User Functions
|
|
||||||
--
|
|
||||||
-- ## F10 Map Markers
|
|
||||||
--
|
|
||||||
-- ## Position
|
|
||||||
--
|
|
||||||
-- ## Closest Radio
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- @field #RADIOS
|
|
||||||
RADIOS = {
|
|
||||||
ClassName = "RADIOS",
|
|
||||||
verbose = 0,
|
|
||||||
radios = {},
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Radio item data structure.
|
|
||||||
-- @type RADIOS.Radio
|
|
||||||
-- @field #string radioId Radio ID.
|
|
||||||
-- @field #table role Roles of the radio (usually {"ground", "tower", "approach"}).
|
|
||||||
-- @field #table callsign Callsigns of the radio (usually the airbase name).
|
|
||||||
-- @field #table frequency Frequencies of the radios.
|
|
||||||
-- @field #table position Position table.
|
|
||||||
-- @field #table sceneObjects Scenery objects.
|
|
||||||
-- @field #string name Name of the airbase.
|
|
||||||
-- @field Wrapper.Airbase#AIRBASE airbase Airbase.
|
|
||||||
|
|
||||||
--- Radio item data structure.
|
|
||||||
-- @type RADIOS.Frequency
|
|
||||||
-- @field #number modu Modulation type.
|
|
||||||
-- @field #number freq Frequency in Hz.
|
|
||||||
|
|
||||||
|
|
||||||
--- RADIOS class version.
|
|
||||||
-- @field #string version
|
|
||||||
RADIOS.version="0.0.0"
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- ToDo list
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- TODO: A lot...
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Constructor(s)
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- Create a new RADIOS class instance from a given table.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #table RadioTable Table with radios info.
|
|
||||||
-- @return #RADIOS self
|
|
||||||
function RADIOS:NewFromTable(RadioTable)
|
|
||||||
|
|
||||||
-- Inherit everything from BASE class.
|
|
||||||
self=BASE:Inherit(self, BASE:New()) -- #RADIOS
|
|
||||||
|
|
||||||
local airbasenames=AIRBASE.GetAllAirbaseNames()
|
|
||||||
|
|
||||||
for _,_radio in pairs(RadioTable) do
|
|
||||||
local radio=_radio --#RADIOS.Radio
|
|
||||||
|
|
||||||
--UTILS.PrintTableToLog(radio)
|
|
||||||
--UTILS.PrintTableToLog(radio.callsign)
|
|
||||||
|
|
||||||
-- The table structure of callsign is a bit awkward. We need to get the airbase name.
|
|
||||||
local cs=radio.callsign[1]
|
|
||||||
if cs and cs.common then
|
|
||||||
radio.name=cs.common[1]
|
|
||||||
elseif cs and cs.nato then
|
|
||||||
radio.name=cs.nato[1]
|
|
||||||
else
|
|
||||||
radio.name="Unknown"
|
|
||||||
end
|
|
||||||
|
|
||||||
--UTILS.PrintTableToLog(radio.callsign)
|
|
||||||
|
|
||||||
radio.name=self:_GetAirbaseName(airbasenames, radio.name)
|
|
||||||
|
|
||||||
radio.airbase=AIRBASE:FindByName(radio.name)
|
|
||||||
|
|
||||||
if radio.airbase then
|
|
||||||
radio.coordinate=radio.airbase:GetCoordinate()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add to table
|
|
||||||
table.insert(self.radios, radio)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug output
|
|
||||||
self:I(string.format("Added %d radios", #self.radios))
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Create a new RADIOS class instance from a given file.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #string FileName Full path to the file containing the map radios.
|
|
||||||
-- @return #RADIOS self
|
|
||||||
function RADIOS:NewFromFile(FileName)
|
|
||||||
|
|
||||||
-- Inherit everything from BASE class.
|
|
||||||
self=BASE:Inherit(self, BASE:New()) -- #RADIOS
|
|
||||||
|
|
||||||
local exists=UTILS.FileExists(FileName)
|
|
||||||
|
|
||||||
if exists==false then
|
|
||||||
self:E(string.format("ERROR: file with radios info does not exist! File=%s", tostring(FileName)))
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This will create a global table `radio`
|
|
||||||
dofile(FileName)
|
|
||||||
|
|
||||||
-- Get radios from table.
|
|
||||||
self=self:NewFromTable(radio)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- User Functions
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- Get 3D position vector of a specific radio.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #RADIOS.Radio radio The radio data structure.
|
|
||||||
-- @return DCS#Vec3 Position vector.
|
|
||||||
function RADIOS:GetVec3(radio)
|
|
||||||
return radio.vec3
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get COORDINATE of a specific radio.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #RADIOS.Radio radio The radio data structure.
|
|
||||||
-- @return Core.Point#COORDINATE The coordinate.
|
|
||||||
function RADIOS:GetCoordinate(radio)
|
|
||||||
return radio.coordinate
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add markers for all radios on the F10 map.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #RADIOS.Radio Radio (Optional) Only this specifc radio.
|
|
||||||
-- @return #RADIOS self
|
|
||||||
function RADIOS:MarkerShow(Radio)
|
|
||||||
|
|
||||||
for _,_radio in pairs(self.radios) do
|
|
||||||
local radio=_radio --#RADIOS.Radio
|
|
||||||
if Radio==nil or Radio.radioId==radio.radioId then
|
|
||||||
local coord=self:GetCoordinate(radio)
|
|
||||||
if coord then
|
|
||||||
local text=self:_GetMarkerText(radio)
|
|
||||||
if radio.markerID then
|
|
||||||
UTILS.RemoveMark(radio.markerID)
|
|
||||||
end
|
|
||||||
radio.markerID=coord:MarkToAll(text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Remove markers of all radios from the F10 map.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #RADIOS.Radio Radio (Optional) Only this specifc radio.
|
|
||||||
-- @return #RADIOS self
|
|
||||||
function RADIOS:MarkerRemove(Radio)
|
|
||||||
|
|
||||||
for _,_radio in pairs(self.radios) do
|
|
||||||
local radio=_radio --#RADIOS.Radio
|
|
||||||
if Radio==nil or Radio.radioId==radio.radioId then
|
|
||||||
if radio.markerID then
|
|
||||||
UTILS.RemoveMark(radio.markerID)
|
|
||||||
radio.markerID=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Private Functions
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- Get text displayed in the F10 marker.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #RADIOS.Radio radio The radio data structure.
|
|
||||||
-- @return #string Marker text.
|
|
||||||
function RADIOS:_GetMarkerText(radio)
|
|
||||||
|
|
||||||
local text=string.format("Radio %s", tostring(radio.name))
|
|
||||||
for b,f in pairs(radio.frequency) do
|
|
||||||
local frequency=f --#RADIOS.Frequency
|
|
||||||
local mod=frequency[1]
|
|
||||||
local fre=frequency[2]
|
|
||||||
local freq, funit=self:_GetFrequency(fre)
|
|
||||||
--UTILS.PrintTableToLog(frequency)
|
|
||||||
local band=self:_GetBandName(b)
|
|
||||||
text=text..string.format("\n%s: %.3f %s", band, freq, funit)
|
|
||||||
end
|
|
||||||
|
|
||||||
return text
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Get converted frequency.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #number freq Frequency in Hz.
|
|
||||||
-- @return #number Frequency in better unit.
|
|
||||||
-- @return #string Unit ("Hz", "kHz", "MHz").
|
|
||||||
function RADIOS:_GetFrequency(freq)
|
|
||||||
|
|
||||||
freq=freq or 0
|
|
||||||
local unit="Hz"
|
|
||||||
|
|
||||||
if freq>=1e6 then
|
|
||||||
freq=freq/1e6
|
|
||||||
unit="MHz"
|
|
||||||
elseif freq>=1e3 then
|
|
||||||
freq=freq/1e3
|
|
||||||
unit="kHz"
|
|
||||||
end
|
|
||||||
|
|
||||||
return freq, unit
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get name of frequency band.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #number BandNumber Band as number.
|
|
||||||
-- @return #string Band name.
|
|
||||||
function RADIOS:_GetBandName(BandNumber)
|
|
||||||
|
|
||||||
if BandNumber~=nil then
|
|
||||||
for bandName,bandNumber in pairs(ENUMS.FrequencyBand) do
|
|
||||||
if bandNumber==BandNumber then
|
|
||||||
return bandName
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return "Unknown"
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get name of frequency band.
|
|
||||||
-- @param #RADIOS self
|
|
||||||
-- @param #table airbasenames Names of all airbases.
|
|
||||||
-- @param #string name Name of airbase.
|
|
||||||
-- @return #string Name of airbase
|
|
||||||
function RADIOS:_GetAirbaseName(airbasenames, name)
|
|
||||||
|
|
||||||
local airbase=AIRBASE:FindByName(name)
|
|
||||||
|
|
||||||
if airbase then
|
|
||||||
return name
|
|
||||||
else
|
|
||||||
for _,airbasename in pairs(airbasenames) do
|
|
||||||
if string.find(airbasename, name) then
|
|
||||||
return airbasename
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return "Unknown"
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
108
Moose Development/Moose/Navigation/Template.lua
Normal file
108
Moose Development/Moose/Navigation/Template.lua
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
--- **NAVIGATION** - Template.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Stuff
|
||||||
|
-- * More Stuff
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Template).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Navigation.Template
|
||||||
|
-- @image NAVIGATION_Template.png
|
||||||
|
|
||||||
|
|
||||||
|
--- TEMPLATE class.
|
||||||
|
-- @type TEMPLATE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number verbose Verbosity of output.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The TEMPLATE Concept
|
||||||
|
--
|
||||||
|
-- The TEMPLATE class has a great concept!
|
||||||
|
--
|
||||||
|
-- # Basic Setup
|
||||||
|
--
|
||||||
|
-- A new `TEMPLATE` object can be created with the @{#TEMPLATE.New}() function.
|
||||||
|
--
|
||||||
|
-- myTemplate=TEMPLATE:New()
|
||||||
|
-- myTemplate:SetXYZ(X, Y, Z)
|
||||||
|
--
|
||||||
|
-- This is how it works.
|
||||||
|
--
|
||||||
|
-- @field #TEMPLATE
|
||||||
|
TEMPLATE = {
|
||||||
|
ClassName = "TEMPLATE",
|
||||||
|
verbose = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Type of navaid
|
||||||
|
-- @type TEMPLATE.Type
|
||||||
|
-- @field #string VOR VOR
|
||||||
|
-- @field #string NDB NDB
|
||||||
|
TEMPLATE.TYPE={
|
||||||
|
VOR="VOR",
|
||||||
|
NDB="NDB",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- TEMPLATE class version.
|
||||||
|
-- @field #string version
|
||||||
|
TEMPLATE.version="0.0.1"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- ToDo list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: A lot...
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new TEMPLATE class instance.
|
||||||
|
-- @param #TEMPLATE self
|
||||||
|
-- @return #TEMPLATE self
|
||||||
|
function TEMPLATE:New()
|
||||||
|
|
||||||
|
-- Inherit everything from SCENERY class.
|
||||||
|
self=BASE:Inherit(self, BASE:New()) -- #TEMPLATE
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set frequency.
|
||||||
|
-- @param #TEMPLATE self
|
||||||
|
-- @param #number Frequency Frequency in Hz.
|
||||||
|
-- @return #TEMPLATE self
|
||||||
|
function TEMPLATE:SetFrequency(Frequency)
|
||||||
|
|
||||||
|
self.frequency=Frequency
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Private Functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
--- **NAVIGATION** - Beacons of the map/theatre.
|
|
||||||
--
|
|
||||||
-- **Main Features:**
|
|
||||||
--
|
|
||||||
-- * Find towns of map
|
|
||||||
-- * Road and rail connections
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- ## Example Missions:
|
|
||||||
--
|
|
||||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Towns).
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- ### Author: **funkyfranky**
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
-- @module Navigation.Towns
|
|
||||||
-- @image NAVIGATION_Towns.png
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- TOWNS class.
|
|
||||||
-- @type TOWNS
|
|
||||||
--
|
|
||||||
-- @field #string ClassName Name of the class.
|
|
||||||
-- @field #number verbose Verbosity of output.
|
|
||||||
-- @field #table towns Towns.
|
|
||||||
--
|
|
||||||
-- @extends Core.Base#BASE
|
|
||||||
|
|
||||||
--- *Hope is the beacon that guides lost ships back to the shore.*
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- # The TOWNS Concept
|
|
||||||
--
|
|
||||||
-- This class is desinged to make information about towns of a map/theatre easier accessible. The information contains location and road/rail connections of the towns.
|
|
||||||
--
|
|
||||||
-- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `towns.lua` that can be
|
|
||||||
-- found in the installation directory of DCS for each map or a table that the user needs to provide.
|
|
||||||
--
|
|
||||||
-- # Basic Setup
|
|
||||||
--
|
|
||||||
-- A new `TOWNS` object can be created with the @{#TOWNS.NewFromFile}(*towns_lua_file*) function.
|
|
||||||
--
|
|
||||||
-- local towns=TOWNS:NewFromFile("<DCS_Install_Directory>\Mods\terrains\<Map_Name>\towns.lua")
|
|
||||||
-- towns:MarkerShow()
|
|
||||||
--
|
|
||||||
-- This will load the towns from the `<DCS_Install_Directory>` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file
|
|
||||||
-- you provided is correct and all relevant towns are present.
|
|
||||||
--
|
|
||||||
-- # User Functions
|
|
||||||
--
|
|
||||||
-- ## F10 Map Markers
|
|
||||||
--
|
|
||||||
-- ## Position
|
|
||||||
--
|
|
||||||
-- ## Get Closest Town
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- @field #TOWNS
|
|
||||||
TOWNS = {
|
|
||||||
ClassName = "TOWNS",
|
|
||||||
verbose = 0,
|
|
||||||
towns = {},
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Town data.
|
|
||||||
-- @type TOWNS.Town
|
|
||||||
-- @field #string display_name Displayed name.
|
|
||||||
-- @field #string name Name of the town.
|
|
||||||
-- @field #number latitude Latitude.
|
|
||||||
-- @field #number longitude Longitude
|
|
||||||
-- @field DCS#Vec3 vec3 Position vector 3D.
|
|
||||||
-- @field Core.Point#COORDINATE coordinate The coordinate.
|
|
||||||
-- @field Core.Point#COORDINATE coordRoad The coordinate of the closest road.
|
|
||||||
-- @field Core.Point#COORDINATE coordRail The coordinate of the closest railway.
|
|
||||||
-- @field #number markerID ID for the F10 marker.
|
|
||||||
|
|
||||||
--- TOWNS class version.
|
|
||||||
-- @field #string version
|
|
||||||
TOWNS.version="0.0.1"
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- ToDo list
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- TODO: A lot...
|
|
||||||
-- TODO: Road connection
|
|
||||||
-- TODO: Rail connection
|
|
||||||
-- TODO: Connection between towns
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Constructor(s)
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- Create a new TOWNS class instance from a given table.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #table TownTable Table with all towns data.
|
|
||||||
-- @return #TOWNS self
|
|
||||||
function TOWNS:NewFromTable(TownTable)
|
|
||||||
|
|
||||||
-- Inherit everything from BASE class.
|
|
||||||
self=BASE:Inherit(self, BASE:New()) -- #TOWNS
|
|
||||||
|
|
||||||
for TownName,_town in pairs(TownTable) do
|
|
||||||
local town=_town --#TOWNS.Town
|
|
||||||
|
|
||||||
town.name=TownName
|
|
||||||
|
|
||||||
-- Get coordinate
|
|
||||||
town.coordinate=COORDINATE:NewFromLLDD(town.latitude, town.longitude)
|
|
||||||
|
|
||||||
-- Get coordinate of closest road
|
|
||||||
town.coordRoad=town.coordinate:GetClosestPointToRoad()
|
|
||||||
|
|
||||||
-- Get coordinate of closest rail
|
|
||||||
town.coordRail=town.coordinate:GetClosestPointToRoad(true)
|
|
||||||
|
|
||||||
-- Add to table
|
|
||||||
table.insert(self.towns, town)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug output
|
|
||||||
self:I(string.format("Added %d towns", #self.towns))
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Create a new TOWNS class instance from a given file.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #string FileName Full path to the file containing the towns data.
|
|
||||||
-- @return #TOWNS self
|
|
||||||
function TOWNS:NewFromFile(FileName)
|
|
||||||
|
|
||||||
-- Inherit everything from BASE class.
|
|
||||||
self=BASE:Inherit(self, BASE:New()) -- #TOWNS
|
|
||||||
|
|
||||||
local exists=UTILS.FileExists(FileName)
|
|
||||||
|
|
||||||
if exists==false then
|
|
||||||
self:E(string.format("ERROR: file with towns info does not exist!"))
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- This will create a global table `towns`
|
|
||||||
dofile(FileName)
|
|
||||||
|
|
||||||
-- Get towns from table.
|
|
||||||
self=self:NewFromTable(towns)
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- User Functions
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- Get 3D position vector of a specific town.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town town The town data structure.
|
|
||||||
-- @return DCS#Vec3 Position vector.
|
|
||||||
function TOWNS:GetVec3(town)
|
|
||||||
return town.vec3
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get COORDINATE of a specific town.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town town The town data structure.
|
|
||||||
-- @return Core.Point#COORDINATE The coordinate.
|
|
||||||
function TOWNS:GetCoordinate(town)
|
|
||||||
return town.coordinate
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get closest road coordinate of a town.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town town The town data structure.
|
|
||||||
-- @return Core.Point#COORDINATE The closest road coordinate.
|
|
||||||
function TOWNS:GetCoordRoad(town)
|
|
||||||
return town.coordRoad
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get closest rail coordinate of a town.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town town The town data structure.
|
|
||||||
-- @return Core.Point#COORDINATE The closest rail coordinate.
|
|
||||||
function TOWNS:GetCoordRail(town)
|
|
||||||
return town.coordRail
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get road connection between two towns.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town townA The town data structure.
|
|
||||||
-- @param #TOWNS.Town townB The town data structure.
|
|
||||||
-- @return #table Table containing path coordinates.
|
|
||||||
function TOWNS:GetConnectionRoad(townA, townB)
|
|
||||||
|
|
||||||
local path=townA.coordRoad:GetPathOnRoad(townB.coordRoad)
|
|
||||||
|
|
||||||
return path
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Find closest town to a given coordinate.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param Core.Point#COORDINATE Coordinate The reference coordinate.
|
|
||||||
-- @return #TOWNS.Town The closest town.
|
|
||||||
function TOWNS:GetClosestTown(Coordinate)
|
|
||||||
|
|
||||||
local Town=nil --#TOWNS.Town
|
|
||||||
local distmin=math.huge
|
|
||||||
|
|
||||||
for _,_town in pairs(self.towns) do
|
|
||||||
local town=_town --#TOWNS.Town
|
|
||||||
|
|
||||||
local dist=Coordinate:Get2DDistance(town.coordinate)
|
|
||||||
|
|
||||||
if dist<distmin then
|
|
||||||
distmin=dist
|
|
||||||
Town=town
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return Town
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get table of all towns, optionally of a given type.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @return #table Table of towns. Each element is of type #TOWN.Town.
|
|
||||||
function TOWNS:GetTowns()
|
|
||||||
return self.towns
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add markers for all towns on the F10 map.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town Town (Optional) Only this specifc town.
|
|
||||||
-- @return #TOWNS self
|
|
||||||
function TOWNS:MarkerShow(Town)
|
|
||||||
|
|
||||||
for _,_town in pairs(self.towns) do
|
|
||||||
local town=_town --#TOWNS.Town
|
|
||||||
if Town==nil or Town.name==town.name then
|
|
||||||
local text=self:_GetMarkerText(town)
|
|
||||||
local coord=town.coordinate
|
|
||||||
if town.markerID then
|
|
||||||
UTILS.RemoveMark(town.markerID)
|
|
||||||
end
|
|
||||||
town.markerID=coord:MarkToAll(text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Remove markers of all towns from the F10 map.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town Town (Optional) Only this specifc town.
|
|
||||||
-- @return #TOWNS self
|
|
||||||
function TOWNS:MarkerRemove(Town)
|
|
||||||
|
|
||||||
for _,_town in pairs(self.towns) do
|
|
||||||
local town=_town --#TOWNS.Town
|
|
||||||
if Town==nil or Town.name==town.name then
|
|
||||||
if town.markerID then
|
|
||||||
UTILS.RemoveMark(town.markerID)
|
|
||||||
town.markerID=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-- Private Functions
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--- Get text displayed in the F10 marker.
|
|
||||||
-- @param #TOWNS self
|
|
||||||
-- @param #TOWNS.Town town The town data structure.
|
|
||||||
-- @return #string Marker text.
|
|
||||||
function TOWNS:_GetMarkerText(town)
|
|
||||||
|
|
||||||
local text=string.format("Town %s", town.name)
|
|
||||||
--text=text..string.format("\nCallsign: %s", tostring(beacon.callsign))
|
|
||||||
|
|
||||||
return text
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
@@ -2798,7 +2798,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
_RUNACT = subtitle
|
_RUNACT = subtitle
|
||||||
--alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
|
||||||
-- Runway length.
|
-- Runway length.
|
||||||
if self.rwylength then
|
if self.rwylength then
|
||||||
|
|||||||
@@ -1283,8 +1283,6 @@ AIRBOSS = {
|
|||||||
-- @field #string RHINOE F/A-18E Superhornet (mod).
|
-- @field #string RHINOE F/A-18E Superhornet (mod).
|
||||||
-- @field #string RHINOF F/A-18F Superhornet (mod).
|
-- @field #string RHINOF F/A-18F Superhornet (mod).
|
||||||
-- @field #string GROWLER FEA-18G Superhornet (mod).
|
-- @field #string GROWLER FEA-18G Superhornet (mod).
|
||||||
-- @field #string CORSAIR F4U-1D Corsair.
|
|
||||||
-- @field #string CORSAIR_CW F4U-1D Corsair Mk.4 (clipped wing).
|
|
||||||
AIRBOSS.AircraftCarrier={
|
AIRBOSS.AircraftCarrier={
|
||||||
AV8B="AV8BNA",
|
AV8B="AV8BNA",
|
||||||
HORNET="FA-18C_hornet",
|
HORNET="FA-18C_hornet",
|
||||||
@@ -1301,8 +1299,6 @@ AIRBOSS.AircraftCarrier={
|
|||||||
RHINOE="FA-18E",
|
RHINOE="FA-18E",
|
||||||
RHINOF="FA-18F",
|
RHINOF="FA-18F",
|
||||||
GROWLER="EA-18G",
|
GROWLER="EA-18G",
|
||||||
CORSAIR="F4U-1D",
|
|
||||||
CORSAIR_CW="F4U-1D CW",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Carrier types.
|
--- Carrier types.
|
||||||
@@ -1314,7 +1310,6 @@ AIRBOSS.AircraftCarrier={
|
|||||||
-- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module]
|
-- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module]
|
||||||
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
||||||
-- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!]
|
-- @field #string VINSON USS Carl Vinson (CVN-70) [Deprecated!]
|
||||||
-- @field #string ESSEX Essex class carrier (e.g. USS Yorktown (CV-10)) [Magnitude 3 Carrier Module]
|
|
||||||
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
|
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
|
||||||
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
|
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
|
||||||
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
||||||
@@ -1330,7 +1325,6 @@ AIRBOSS.CarrierType = {
|
|||||||
STENNIS = "Stennis",
|
STENNIS = "Stennis",
|
||||||
FORRESTAL = "Forrestal",
|
FORRESTAL = "Forrestal",
|
||||||
VINSON = "VINSON",
|
VINSON = "VINSON",
|
||||||
ESSEX = "Essex",
|
|
||||||
HERMES = "HERMES81",
|
HERMES = "HERMES81",
|
||||||
INVINCIBLE = "hms_invincible",
|
INVINCIBLE = "hms_invincible",
|
||||||
TARAWA = "LHA_Tarawa",
|
TARAWA = "LHA_Tarawa",
|
||||||
@@ -1918,9 +1912,6 @@ function AIRBOSS:New( carriername, alias )
|
|||||||
-- Set max section members. Default 2.
|
-- Set max section members. Default 2.
|
||||||
self:SetMaxSectionSize()
|
self:SetMaxSectionSize()
|
||||||
|
|
||||||
-- Set max section distance. Default 100 meters.
|
|
||||||
self:SetMaxSectionDistance()
|
|
||||||
|
|
||||||
-- Set max flights per stack. Default is 2.
|
-- Set max flights per stack. Default is 2.
|
||||||
self:SetMaxFlightsPerStack()
|
self:SetMaxFlightsPerStack()
|
||||||
|
|
||||||
@@ -2019,8 +2010,6 @@ function AIRBOSS:New( carriername, alias )
|
|||||||
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
||||||
-- Carl Vinson is legacy now.
|
-- Carl Vinson is legacy now.
|
||||||
self:_InitStennis()
|
self:_InitStennis()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then
|
|
||||||
self:_InitEssex()
|
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
|
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
|
||||||
-- Hermes parameters.
|
-- Hermes parameters.
|
||||||
self:_InitHermes()
|
self:_InitHermes()
|
||||||
@@ -2874,12 +2863,7 @@ end
|
|||||||
function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW)
|
function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW)
|
||||||
|
|
||||||
--Check if V/STOL Carrier
|
--Check if V/STOL Carrier
|
||||||
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
self.carriertype == AIRBOSS.CarrierType.HERMES or
|
|
||||||
self.carriertype == AIRBOSS.CarrierType.TARAWA or
|
|
||||||
self.carriertype == AIRBOSS.CarrierType.AMERICA or
|
|
||||||
self.carriertype == AIRBOSS.CarrierType.JCARLOS or
|
|
||||||
self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
|
||||||
|
|
||||||
-- allow a larger GSE for V/STOL operations --Pene Testing
|
-- allow a larger GSE for V/STOL operations --Pene Testing
|
||||||
self.gle._max=_max or 0.7
|
self.gle._max=_max or 0.7
|
||||||
@@ -2888,8 +2872,8 @@ function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW)
|
|||||||
self.gle._min=_min or -0.5
|
self.gle._min=_min or -0.5
|
||||||
self.gle.Low=Low or -1.2
|
self.gle.Low=Low or -1.2
|
||||||
self.gle.LOW=LOW or -1.5
|
self.gle.LOW=LOW or -1.5
|
||||||
else
|
|
||||||
-- CVN values
|
-- CVN values
|
||||||
|
else
|
||||||
self.gle._max=_max or 0.4
|
self.gle._max=_max or 0.4
|
||||||
self.gle.High=High or 0.8
|
self.gle.High=High or 0.8
|
||||||
self.gle.HIGH=HIGH or 1.5
|
self.gle.HIGH=HIGH or 1.5
|
||||||
@@ -3104,7 +3088,8 @@ function AIRBOSS:EnableSRS(PathToSRS,Port,Culture,Gender,Voice,GoogleCreds,Volum
|
|||||||
self.SRS:SetVolume(Volume or 1)
|
self.SRS:SetVolume(Volume or 1)
|
||||||
--self.SRS:SetModulations(Modulations)
|
--self.SRS:SetModulations(Modulations)
|
||||||
if GoogleCreds then
|
if GoogleCreds then
|
||||||
self.SRS:SetGoogle(GoogleCreds)
|
self.SRS:SetProviderOptionsGoogle(GoogleCreds,GoogleCreds)
|
||||||
|
self.SRS:SetProvider(MSRS.Provider.GOOGLE)
|
||||||
end
|
end
|
||||||
if Voice then
|
if Voice then
|
||||||
self.SRS:SetVoice(Voice)
|
self.SRS:SetVoice(Voice)
|
||||||
@@ -3359,22 +3344,6 @@ function AIRBOSS:SetMaxSectionSize( nmax )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set maximum distance up to which section members are allowed (default: 100 meters).
|
|
||||||
-- @param #AIRBOSS self
|
|
||||||
-- @param #number dmax Max distance in meters (default 100 m). Minimum is 10 m, maximum is 5000 m.
|
|
||||||
-- @return #AIRBOSS self
|
|
||||||
function AIRBOSS:SetMaxSectionDistance( dmax )
|
|
||||||
if dmax then
|
|
||||||
if dmax < 10 then
|
|
||||||
dmax = 10
|
|
||||||
elseif dmax > 5000 then
|
|
||||||
dmax = 5000
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.maxsectiondistance = dmax or 100
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set max number of flights per stack. All members of a section count as one "flight".
|
--- Set max number of flights per stack. All members of a section count as one "flight".
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number nmax Number of max allowed flights per stack. Default is two. Minimum is one, maximum is 4.
|
-- @param #number nmax Number of max allowed flights per stack. Default is two. Minimum is one, maximum is 4.
|
||||||
@@ -3654,6 +3623,7 @@ function AIRBOSS:onafterStart( From, Event, To )
|
|||||||
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._PlayerLeft )
|
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._PlayerLeft )
|
||||||
self:HandleEvent( EVENTS.MissionEnd )
|
self:HandleEvent( EVENTS.MissionEnd )
|
||||||
self:HandleEvent( EVENTS.RemoveUnit )
|
self:HandleEvent( EVENTS.RemoveUnit )
|
||||||
|
self:HandleEvent( EVENTS.UnitLost, self.OnEventRemoveUnit )
|
||||||
|
|
||||||
-- self.StatusScheduler=SCHEDULER:New(self)
|
-- self.StatusScheduler=SCHEDULER:New(self)
|
||||||
-- self.StatusScheduler:Schedule(self, self._Status, {}, 1, 0.5)
|
-- self.StatusScheduler:Schedule(self, self._Status, {}, 1, 0.5)
|
||||||
@@ -4640,51 +4610,6 @@ function AIRBOSS:_InitForrestal()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Init parameters for Essec class carriers.
|
|
||||||
-- @param #AIRBOSS self
|
|
||||||
function AIRBOSS:_InitEssex()
|
|
||||||
|
|
||||||
-- Init Nimitz as default.
|
|
||||||
self:_InitNimitz()
|
|
||||||
|
|
||||||
-- Carrier Parameters.
|
|
||||||
self.carrierparam.sterndist = -126
|
|
||||||
self.carrierparam.deckheight = 19.27 --DCS World\CoreMods\tech\M3 WWII PTO units\Database\Essex_Class_Carrier_1944.lua
|
|
||||||
|
|
||||||
-- Total size of the carrier (approx as rectangle).
|
|
||||||
self.carrierparam.totlength = 268
|
|
||||||
self.carrierparam.totwidthport = 23
|
|
||||||
self.carrierparam.totwidthstarboard = 23
|
|
||||||
|
|
||||||
-- Landing runway.
|
|
||||||
self.carrierparam.rwyangle = 0.0
|
|
||||||
self.carrierparam.rwylength = 265
|
|
||||||
self.carrierparam.rwywidth = 20
|
|
||||||
|
|
||||||
-- Wires.
|
|
||||||
self.carrierparam.wire1 = 21.9
|
|
||||||
self.carrierparam.wire2 = 28.3
|
|
||||||
self.carrierparam.wire3 = 34.7
|
|
||||||
self.carrierparam.wire4 = 41.1
|
|
||||||
self.carrierparam.wire5 = 47.4
|
|
||||||
self.carrierparam.wire6 = 53.7
|
|
||||||
self.carrierparam.wire7 = 59.0
|
|
||||||
|
|
||||||
self.carrierparam.wire8 = 64.1
|
|
||||||
self.carrierparam.wire9 = 72.7
|
|
||||||
self.carrierparam.wire10 = 78.0
|
|
||||||
self.carrierparam.wire11 = 85.5
|
|
||||||
|
|
||||||
self.carrierparam.wire12 = 105.9
|
|
||||||
self.carrierparam.wire13 = 113.3
|
|
||||||
self.carrierparam.wire14 = 121.0
|
|
||||||
self.carrierparam.wire15 = 128.5
|
|
||||||
|
|
||||||
-- Landing distance.
|
|
||||||
self.carrierparam.landingdist = self.carrierparam.sterndist+self.carrierparam.wire3
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Init parameters for R12 HMS Hermes carrier.
|
--- Init parameters for R12 HMS Hermes carrier.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_InitHermes()
|
function AIRBOSS:_InitHermes()
|
||||||
@@ -5388,7 +5313,6 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
|||||||
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
|
local skyhawk = playerData.actype == AIRBOSS.AircraftCarrier.A4EC
|
||||||
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
||||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||||
local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW
|
|
||||||
|
|
||||||
-- Table with AoA values.
|
-- Table with AoA values.
|
||||||
local aoa = {} -- #AIRBOSS.AircraftAoA
|
local aoa = {} -- #AIRBOSS.AircraftAoA
|
||||||
@@ -5433,6 +5357,7 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
|||||||
aoa.Fast = 8.25 -- =17.5/2
|
aoa.Fast = 8.25 -- =17.5/2
|
||||||
aoa.FAST = 8.00 -- =16.5/2
|
aoa.FAST = 8.00 -- =16.5/2
|
||||||
elseif harrier then
|
elseif harrier then
|
||||||
|
|
||||||
-- AV-8B Harrier parameters. Tuning done on the Fast AoA to allow for abeam and ninety at Nozzles 55. Pene testing
|
-- AV-8B Harrier parameters. Tuning done on the Fast AoA to allow for abeam and ninety at Nozzles 55. Pene testing
|
||||||
aoa.SLOW = 16.0
|
aoa.SLOW = 16.0
|
||||||
aoa.Slow = 13.5
|
aoa.Slow = 13.5
|
||||||
@@ -5441,15 +5366,7 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
|||||||
aoa.OnSpeedMin = 9.5
|
aoa.OnSpeedMin = 9.5
|
||||||
aoa.Fast = 8.0
|
aoa.Fast = 8.0
|
||||||
aoa.FAST = 7.5
|
aoa.FAST = 7.5
|
||||||
elseif corsair then
|
|
||||||
-- F4U-1D Corsair parameters.
|
|
||||||
aoa.SLOW = 16.0
|
|
||||||
aoa.Slow = 13.5
|
|
||||||
aoa.OnSpeedMax = 12.5
|
|
||||||
aoa.OnSpeed = 10.0
|
|
||||||
aoa.OnSpeedMin = 9.5
|
|
||||||
aoa.Fast = 8.0
|
|
||||||
aoa.FAST = 7.5
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return aoa
|
return aoa
|
||||||
@@ -5562,7 +5479,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
local tomcat = playerData.actype == AIRBOSS.AircraftCarrier.F14A or playerData.actype == AIRBOSS.AircraftCarrier.F14B
|
||||||
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
local harrier = playerData.actype == AIRBOSS.AircraftCarrier.AV8B
|
||||||
local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
|
local goshawk = playerData.actype == AIRBOSS.AircraftCarrier.T45C
|
||||||
local corsair = playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR or playerData.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW
|
|
||||||
|
|
||||||
-- Return values.
|
-- Return values.
|
||||||
local alt
|
local alt
|
||||||
@@ -5622,9 +5538,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
elseif goshawk then
|
elseif goshawk then
|
||||||
alt = UTILS.FeetToMeters( 800 )
|
alt = UTILS.FeetToMeters( 800 )
|
||||||
speed = UTILS.KnotsToMps( 300 )
|
speed = UTILS.KnotsToMps( 300 )
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 300 )
|
|
||||||
speed = UTILS.KnotsToMps( 120 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif step == AIRBOSS.PatternStep.BREAKENTRY then
|
elseif step == AIRBOSS.PatternStep.BREAKENTRY then
|
||||||
@@ -5638,9 +5551,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
elseif goshawk then
|
elseif goshawk then
|
||||||
alt = UTILS.FeetToMeters( 800 )
|
alt = UTILS.FeetToMeters( 800 )
|
||||||
speed = UTILS.KnotsToMps( 300 )
|
speed = UTILS.KnotsToMps( 300 )
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 200 )
|
|
||||||
speed = UTILS.KnotsToMps( 110 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif step == AIRBOSS.PatternStep.EARLYBREAK then
|
elseif step == AIRBOSS.PatternStep.EARLYBREAK then
|
||||||
@@ -5649,9 +5559,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
alt = UTILS.FeetToMeters( 800 )
|
alt = UTILS.FeetToMeters( 800 )
|
||||||
elseif skyhawk then
|
elseif skyhawk then
|
||||||
alt = UTILS.FeetToMeters( 600 )
|
alt = UTILS.FeetToMeters( 600 )
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 200 )
|
|
||||||
speed = UTILS.KnotsToMps( 100 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif step == AIRBOSS.PatternStep.LATEBREAK then
|
elseif step == AIRBOSS.PatternStep.LATEBREAK then
|
||||||
@@ -5660,9 +5567,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
alt = UTILS.FeetToMeters( 800 )
|
alt = UTILS.FeetToMeters( 800 )
|
||||||
elseif skyhawk then
|
elseif skyhawk then
|
||||||
alt = UTILS.FeetToMeters( 600 )
|
alt = UTILS.FeetToMeters( 600 )
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 150 )
|
|
||||||
speed = UTILS.KnotsToMps( 100 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif step == AIRBOSS.PatternStep.ABEAM then
|
elseif step == AIRBOSS.PatternStep.ABEAM then
|
||||||
@@ -5671,9 +5575,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
alt = UTILS.FeetToMeters( 600 )
|
alt = UTILS.FeetToMeters( 600 )
|
||||||
elseif skyhawk then
|
elseif skyhawk then
|
||||||
alt = UTILS.FeetToMeters( 500 )
|
alt = UTILS.FeetToMeters( 500 )
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 150 )
|
|
||||||
speed = UTILS.KnotsToMps( 90 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
aoa = aoaac.OnSpeed
|
aoa = aoaac.OnSpeed
|
||||||
@@ -5698,9 +5599,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
alt = UTILS.FeetToMeters( 500 )
|
alt = UTILS.FeetToMeters( 500 )
|
||||||
elseif harrier then
|
elseif harrier then
|
||||||
alt = UTILS.FeetToMeters( 425 )
|
alt = UTILS.FeetToMeters( 425 )
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 90 )
|
|
||||||
speed = UTILS.KnotsToMps( 90 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
aoa = aoaac.OnSpeed
|
aoa = aoaac.OnSpeed
|
||||||
@@ -5713,8 +5611,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
alt = UTILS.FeetToMeters( 430 ) -- Tomcat should be a bit higher as it intercepts the GS a bit higher.
|
alt = UTILS.FeetToMeters( 430 ) -- Tomcat should be a bit higher as it intercepts the GS a bit higher.
|
||||||
elseif skyhawk then
|
elseif skyhawk then
|
||||||
alt = UTILS.FeetToMeters( 370 ) -- ?
|
alt = UTILS.FeetToMeters( 370 ) -- ?
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 80 )
|
|
||||||
end
|
end
|
||||||
-- Harrier wont get into wake pos. Runway is not angled and it stays port.
|
-- Harrier wont get into wake pos. Runway is not angled and it stays port.
|
||||||
|
|
||||||
@@ -5730,8 +5626,6 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
alt = UTILS.FeetToMeters( 300 ) -- ?
|
alt = UTILS.FeetToMeters( 300 ) -- ?
|
||||||
elseif harrier then
|
elseif harrier then
|
||||||
alt=UTILS.FeetToMeters(312)-- 300-325 ft
|
alt=UTILS.FeetToMeters(312)-- 300-325 ft
|
||||||
elseif corsair then
|
|
||||||
alt = UTILS.FeetToMeters( 80 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
aoa = aoaac.OnSpeed
|
aoa = aoaac.OnSpeed
|
||||||
@@ -6608,8 +6502,6 @@ function AIRBOSS:_LandAI( flight )
|
|||||||
Speed = UTILS.KnotsToKmph( 175 )
|
Speed = UTILS.KnotsToKmph( 175 )
|
||||||
elseif flight.actype == AIRBOSS.AircraftCarrier.S3B or flight.actype == AIRBOSS.AircraftCarrier.S3BTANKER then
|
elseif flight.actype == AIRBOSS.AircraftCarrier.S3B or flight.actype == AIRBOSS.AircraftCarrier.S3BTANKER then
|
||||||
Speed = UTILS.KnotsToKmph( 140 )
|
Speed = UTILS.KnotsToKmph( 140 )
|
||||||
elseif flight.actype == AIRBOSS.AircraftCarrier.CORSAIR or flight.actype == AIRBOSS.AircraftCarrier.CORSAIR_CW then
|
|
||||||
Speed = UTILS.KnotsToKmph( 100 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Carrier position.
|
-- Carrier position.
|
||||||
@@ -8832,13 +8724,13 @@ function AIRBOSS:OnEventRemoveUnit( EventData )
|
|||||||
|
|
||||||
-- Nil checks.
|
-- Nil checks.
|
||||||
if EventData == nil then
|
if EventData == nil then
|
||||||
self:T( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" )
|
self:E( self.lid .. "ERROR: EventData=nil in event REMOVEUNIT!" )
|
||||||
self:T( EventData )
|
self:E( EventData )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if EventData.IniUnit == nil then
|
if EventData.IniUnit == nil then
|
||||||
self:T( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" )
|
self:E( self.lid .. "ERROR: EventData.IniUnit=nil in event REMOVEUNIT!" )
|
||||||
self:T( EventData )
|
self:E( EventData )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -10405,9 +10297,6 @@ function AIRBOSS:_GetSternCoord()
|
|||||||
elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then
|
elseif self.carriertype == AIRBOSS.CarrierType.FORRESTAL then
|
||||||
-- Forrestal
|
-- Forrestal
|
||||||
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7.5, FB + 90, true, true )
|
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7.5, FB + 90, true, true )
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.ESSEX then
|
|
||||||
-- Forrestal
|
|
||||||
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( -1, FB + 90, true, true )
|
|
||||||
else
|
else
|
||||||
-- Nimitz SC: translate 8 meters starboard wrt Final bearing.
|
-- Nimitz SC: translate 8 meters starboard wrt Final bearing.
|
||||||
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 9.5, FB + 90, true, true )
|
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 9.5, FB + 90, true, true )
|
||||||
@@ -17160,7 +17049,7 @@ function AIRBOSS:_RemoveSectionMember( playerData, sectionmember )
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set all flights within maxsectiondistance meters to be part of my section (default: 100 meters).
|
--- Set all flights within 100 meters to be part of my section.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #string _unitName Name of the player unit.
|
-- @param #string _unitName Name of the player unit.
|
||||||
function AIRBOSS:_SetSection( _unitName )
|
function AIRBOSS:_SetSection( _unitName )
|
||||||
@@ -17178,7 +17067,7 @@ function AIRBOSS:_SetSection( _unitName )
|
|||||||
local mycoord = _unit:GetCoordinate()
|
local mycoord = _unit:GetCoordinate()
|
||||||
|
|
||||||
-- Max distance up to which section members are allowed.
|
-- Max distance up to which section members are allowed.
|
||||||
local dmax = self.maxsectiondistance
|
local dmax = 100
|
||||||
|
|
||||||
-- Check if player is in Marshal or pattern queue already.
|
-- Check if player is in Marshal or pattern queue already.
|
||||||
local text
|
local text
|
||||||
|
|||||||
@@ -1428,7 +1428,7 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ
|
|||||||
mission:_SetLogID()
|
mission:_SetLogID()
|
||||||
|
|
||||||
-- DCS task parameters:
|
-- DCS task parameters:
|
||||||
mission.engageZone=ZoneCAP or Coordinate
|
mission.engageZone=ZoneCAP
|
||||||
mission.engageTargetTypes=TargetTypes or {"Air"}
|
mission.engageTargetTypes=TargetTypes or {"Air"}
|
||||||
|
|
||||||
-- Mission options:
|
-- Mission options:
|
||||||
@@ -1717,7 +1717,7 @@ end
|
|||||||
|
|
||||||
--- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate.
|
--- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate.
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object.
|
-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC or TARGET object.
|
||||||
-- @param #number Altitude Engage altitude in feet. Default 2000 ft.
|
-- @param #number Altitude Engage altitude in feet. Default 2000 ft.
|
||||||
-- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options.
|
-- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
@@ -1749,7 +1749,7 @@ end
|
|||||||
--- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate.
|
--- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate.
|
||||||
-- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing).
|
-- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing).
|
||||||
-- @param #AUFTRAG self
|
-- @param #AUFTRAG self
|
||||||
-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC, SET_GROUP, SET_UNIT, SET_STATIC or TARGET object.
|
-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC or TARGET object.
|
||||||
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
||||||
-- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options.
|
-- @param #number EngageWeaponType Which weapon to use. Defaults to auto, ie ENUMS.WeaponFlag.Auto. See ENUMS.WeaponFlag for options.
|
||||||
-- @return #AUFTRAG self
|
-- @return #AUFTRAG self
|
||||||
@@ -4823,11 +4823,6 @@ function AUFTRAG:CheckGroupsDone()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if (self:IsStarted() or self:IsExecuting()) and self:CountOpsGroups()>0 then
|
|
||||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] and count of alive OPSGROUP > zero. Mission NOT DONE!", self.status, self:GetState()))
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6113,12 +6108,9 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
-- BOMBING Mission --
|
-- BOMBING Mission --
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
local coords = self.engageTarget:GetCoordinates()
|
local DCStask=CONTROLLABLE.TaskBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, Divebomb)
|
||||||
for _, coord in pairs(coords) do
|
|
||||||
local DCStask = CONTROLLABLE.TaskBombing(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
|
|
||||||
|
|
||||||
table.insert(DCStasks, DCStask)
|
table.insert(DCStasks, DCStask)
|
||||||
end
|
|
||||||
|
|
||||||
elseif self.type==AUFTRAG.Type.STRAFING then
|
elseif self.type==AUFTRAG.Type.STRAFING then
|
||||||
|
|
||||||
@@ -6156,15 +6148,7 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
-- CAP Mission --
|
-- CAP Mission --
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
local Vec2 = self.engageZone:GetVec2()
|
local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, self.engageZone:GetVec2(), self.engageZone:GetRadius(), self.engageTargetTypes, Priority)
|
||||||
local Radius
|
|
||||||
if self.engageZone:IsInstanceOf("COORDINATE") then
|
|
||||||
Radius = UTILS.NMToMeters(20)
|
|
||||||
else
|
|
||||||
Radius = self.engageZone:GetRadius()
|
|
||||||
end
|
|
||||||
|
|
||||||
local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, Vec2, Radius, self.engageTargetTypes, Priority)
|
|
||||||
|
|
||||||
table.insert(self.enrouteTasks, DCStask)
|
table.insert(self.enrouteTasks, DCStask)
|
||||||
|
|
||||||
@@ -6319,46 +6303,17 @@ function AUFTRAG:GetDCSMissionTask()
|
|||||||
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.TargetType)
|
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.TargetType)
|
||||||
--table.insert(self.enrouteTasks, DCStask)
|
--table.insert(self.enrouteTasks, DCStask)
|
||||||
|
|
||||||
if self.engageZone then
|
|
||||||
|
|
||||||
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.engageTargetTypes)
|
|
||||||
--table.insert(self.enrouteTasks, DCStask)
|
|
||||||
self.engageZone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
|
||||||
local ScanUnitSet = self.engageZone:GetScannedSetUnit()
|
|
||||||
local SeadUnitSet = SET_UNIT:New()
|
|
||||||
for _,_unit in pairs (ScanUnitSet.Set) do
|
|
||||||
local unit = _unit -- Wrapper.Unit#UNTI
|
|
||||||
if unit and unit:IsAlive() and unit:HasSEAD() then
|
|
||||||
self:T("Adding UNIT for SEAD: "..unit:GetName())
|
|
||||||
local task = CONTROLLABLE.TaskAttackUnit(nil,unit,GroupAttack,AI.Task.WeaponExpend.ALL,1,Direction,self.engageAltitude,4161536)
|
|
||||||
table.insert(DCStasks, task)
|
|
||||||
SeadUnitSet:AddUnit(unit)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.engageTarget = TARGET:New(SeadUnitSet)
|
|
||||||
--local OrbitTask = CONTROLLABLE.TaskOrbitCircle(nil,self.engageAltitude,self.missionSpeed,self.engageZone:GetCoordinate())
|
|
||||||
--local Point = self.engageZone:GetVec2()
|
|
||||||
--local OrbitTask = CONTROLLABLE.TaskOrbitCircleAtVec2(nil,Point,self.engageAltitude,self.missionSpeed)
|
|
||||||
--table.insert(DCStasks, OrbitTask)
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
self:_GetDCSAttackTask(self.engageTarget, DCStasks)
|
self:_GetDCSAttackTask(self.engageTarget, DCStasks)
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif self.type==AUFTRAG.Type.STRIKE then
|
elseif self.type==AUFTRAG.Type.STRIKE then
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
-- STRIKE Mission --
|
-- STRIKE Mission --
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
local coords = self.engageTarget:GetCoordinates()
|
local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
|
||||||
for _, coord in pairs(coords) do
|
|
||||||
local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, coord:GetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
|
|
||||||
|
|
||||||
table.insert(DCStasks, DCStask)
|
table.insert(DCStasks, DCStask)
|
||||||
end
|
|
||||||
|
|
||||||
elseif self.type==AUFTRAG.Type.TANKER or self.type==AUFTRAG.Type.RECOVERYTANKER then
|
elseif self.type==AUFTRAG.Type.TANKER or self.type==AUFTRAG.Type.RECOVERYTANKER then
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
-- @image OPS_CSAR.jpg
|
-- @image OPS_CSAR.jpg
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Last Update May 2025
|
-- Last Update Jan 2025
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||||
@@ -263,7 +263,6 @@ CSAR = {
|
|||||||
rescuedpilots = 0,
|
rescuedpilots = 0,
|
||||||
limitmaxdownedpilots = true,
|
limitmaxdownedpilots = true,
|
||||||
maxdownedpilots = 10,
|
maxdownedpilots = 10,
|
||||||
useFIFOLimitReplacement = false, -- If true, it will remove the oldest downed pilot when a new one is added, if the limit is reached.
|
|
||||||
allheligroupset = nil,
|
allheligroupset = nil,
|
||||||
topmenuname = "CSAR",
|
topmenuname = "CSAR",
|
||||||
ADFRadioPwr = 1000,
|
ADFRadioPwr = 1000,
|
||||||
@@ -314,7 +313,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31
|
|||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="1.0.33"
|
CSAR.version="1.0.30"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -469,7 +468,7 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
-- added 1.0.15
|
-- added 1.0.15
|
||||||
self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
||||||
|
|
||||||
self.ADFRadioPwr = 500
|
self.ADFRadioPwr = 1000
|
||||||
|
|
||||||
-- added 1.0.16
|
-- added 1.0.16
|
||||||
self.PilotWeight = 80
|
self.PilotWeight = 80
|
||||||
@@ -1146,6 +1145,17 @@ function CSAR:_EventHandler(EventData)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- limit no of pilots in the field.
|
||||||
|
if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then
|
||||||
|
self:T("Maxed Downed Pilot!")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case
|
||||||
|
-- might create dual pilots in edge cases
|
||||||
|
|
||||||
|
local wetfeet = false
|
||||||
|
|
||||||
local initdcscoord = nil
|
local initdcscoord = nil
|
||||||
local initcoord = nil
|
local initcoord = nil
|
||||||
@@ -1159,36 +1169,6 @@ function CSAR:_EventHandler(EventData)
|
|||||||
self:T({initdcscoord})
|
self:T({initdcscoord})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove downed pilot if already exists to replace with new one.
|
|
||||||
if _event.IniPlayerName then
|
|
||||||
local PilotTable = self.downedPilots --#CSAR.DownedPilot
|
|
||||||
local _foundPilot = nil
|
|
||||||
for _,_pilot in pairs(PilotTable) do
|
|
||||||
if _pilot.player == _event.IniPlayerName and _pilot.alive == true then
|
|
||||||
_foundPilot = _pilot
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if _foundPilot then
|
|
||||||
self:T("Downed pilot already exists!")
|
|
||||||
_foundPilot.group:Destroy(false)
|
|
||||||
self:_RemoveNameFromDownedPilots(_foundPilot.name)
|
|
||||||
self:_CheckDownedPilotTable()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- limit no of pilots in the field.
|
|
||||||
if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then
|
|
||||||
self:T("Maxed Downed Pilot!")
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: Over water check --- EVENTS.LandingAfterEjection NOT triggered by DCS, so handle csarUsePara = true case
|
|
||||||
-- might create dual pilots in edge cases
|
|
||||||
|
|
||||||
local wetfeet = false
|
|
||||||
|
|
||||||
--local surface = _unit:GetCoordinate():GetSurfaceType()
|
--local surface = _unit:GetCoordinate():GetSurfaceType()
|
||||||
local surface = initcoord:GetSurfaceType()
|
local surface = initcoord:GetSurfaceType()
|
||||||
|
|
||||||
@@ -2136,50 +2116,56 @@ end
|
|||||||
--- (Internal) Determine distance to closest MASH.
|
--- (Internal) Determine distance to closest MASH.
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT
|
-- @param Wrapper.Unit#UNIT _heli Helicopter #UNIT
|
||||||
-- @return #number Distance in meters
|
-- @return #CSAR self
|
||||||
-- @return #string MASH Name as string
|
|
||||||
function CSAR:_GetClosestMASH(_heli)
|
function CSAR:_GetClosestMASH(_heli)
|
||||||
self:T(self.lid .. " _GetClosestMASH")
|
self:T(self.lid .. " _GetClosestMASH")
|
||||||
local _mashset = self.mash -- Core.Set#SET_GROUP
|
local _mashset = self.mash -- Core.Set#SET_GROUP
|
||||||
local MashSets = {}
|
local _mashes = _mashset:GetSetObjects() -- #table
|
||||||
--local _mashes = _mashset.Set-- #table
|
|
||||||
table.insert(MashSets,_mashset.Set)
|
|
||||||
table.insert(MashSets,self.zonemashes.Set)
|
|
||||||
table.insert(MashSets,self.staticmashes.Set)
|
|
||||||
local _shortestDistance = -1
|
local _shortestDistance = -1
|
||||||
local _distance = 0
|
local _distance = 0
|
||||||
local _helicoord = _heli:GetCoordinate()
|
local _helicoord = _heli:GetCoordinate()
|
||||||
local MashName = nil
|
|
||||||
|
local function GetCloseAirbase(coordinate,Coalition,Category)
|
||||||
|
|
||||||
|
local a=coordinate: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)
|
||||||
|
|
||||||
|
if dist<distmin and (Category==nil or Category==DCSairbase:getDesc().category) then
|
||||||
|
distmin=dist
|
||||||
|
airbase=DCSairbase
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
return distmin
|
||||||
|
end
|
||||||
|
|
||||||
if self.allowFARPRescue then
|
if self.allowFARPRescue then
|
||||||
local position = _heli:GetCoordinate()
|
local position = _heli:GetCoordinate()
|
||||||
local afb,distance = position:GetClosestAirbase(nil,self.coalition)
|
local afb,distance = position:GetClosestAirbase(nil,self.coalition)
|
||||||
_shortestDistance = distance
|
_shortestDistance = distance
|
||||||
MashName = (afb ~= nil) and afb:GetName() or "Unknown"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,_mashes in pairs(MashSets) do
|
for _, _mashUnit in pairs(_mashes) do
|
||||||
for _, _mashUnit in pairs(_mashes or {}) do
|
if _mashUnit and _mashUnit:IsAlive() then
|
||||||
local _mashcoord
|
local _mashcoord = _mashUnit:GetCoordinate()
|
||||||
if _mashUnit and (not _mashUnit:IsInstanceOf("ZONE_BASE")) and _mashUnit:IsAlive() then
|
|
||||||
_mashcoord = _mashUnit:GetCoordinate()
|
|
||||||
elseif _mashUnit and _mashUnit:IsInstanceOf("ZONE_BASE") then
|
|
||||||
_mashcoord = _mashUnit:GetCoordinate()
|
|
||||||
end
|
|
||||||
_distance = self:_GetDistance(_helicoord, _mashcoord)
|
_distance = self:_GetDistance(_helicoord, _mashcoord)
|
||||||
if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then
|
if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then
|
||||||
_shortestDistance = _distance
|
_shortestDistance = _distance
|
||||||
MashName = _mashUnit:GetName() or "Unknown"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if _shortestDistance ~= -1 then
|
if _shortestDistance ~= -1 then
|
||||||
return _shortestDistance, MashName
|
return _shortestDistance
|
||||||
else
|
else
|
||||||
return -1
|
return -1
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Display onboarded rescued pilots.
|
--- (Internal) Display onboarded rescued pilots.
|
||||||
@@ -2337,9 +2323,9 @@ end
|
|||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param Wrapper.Group#GROUP _group Group #GROUP object.
|
-- @param Wrapper.Group#GROUP _group Group #GROUP object.
|
||||||
-- @param #number _freq Frequency to use
|
-- @param #number _freq Frequency to use
|
||||||
-- @param #string BeaconName Beacon Name to use
|
-- @param #string _name Beacon Name to use
|
||||||
-- @return #CSAR self
|
-- @return #CSAR self
|
||||||
function CSAR:_AddBeaconToGroup(_group, _freq, BeaconName)
|
function CSAR:_AddBeaconToGroup(_group, _freq, _name)
|
||||||
self:T(self.lid .. " _AddBeaconToGroup")
|
self:T(self.lid .. " _AddBeaconToGroup")
|
||||||
if self.CreateRadioBeacons == false then return end
|
if self.CreateRadioBeacons == false then return end
|
||||||
local _group = _group
|
local _group = _group
|
||||||
@@ -2360,11 +2346,10 @@ function CSAR:_AddBeaconToGroup(_group, _freq, BeaconName)
|
|||||||
if _radioUnit then
|
if _radioUnit then
|
||||||
local name = _radioUnit:GetName()
|
local name = _radioUnit:GetName()
|
||||||
local Frequency = _freq -- Freq in Hertz
|
local Frequency = _freq -- Freq in Hertz
|
||||||
--local name = _radioUnit:GetName()
|
local name = _radioUnit:GetName()
|
||||||
local Sound = "l10n/DEFAULT/"..self.radioSound
|
local Sound = "l10n/DEFAULT/"..self.radioSound
|
||||||
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
|
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
|
||||||
self:I(self.lid..string.format("Added Radio Beacon %d Hertz | Name %s | Position {%d,%d,%d}",Frequency,BeaconName,vec3.x,vec3.y,vec3.z))
|
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000,_name) -- Beacon in MP only runs for exactly 30secs straight
|
||||||
trigger.action.radioTransmission(Sound, vec3, 0, true, Frequency, self.ADFRadioPwr or 500,BeaconName) -- Beacon in MP only runs for exactly 30secs straight
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2385,13 +2370,9 @@ function CSAR:_RefreshRadioBeacons()
|
|||||||
local group = pilot.group
|
local group = pilot.group
|
||||||
local frequency = pilot.frequency or 0 -- thanks to @Thrud
|
local frequency = pilot.frequency or 0 -- thanks to @Thrud
|
||||||
local bname = pilot.BeaconName or pilot.name..math.random(1,100000)
|
local bname = pilot.BeaconName or pilot.name..math.random(1,100000)
|
||||||
--trigger.action.stopRadioTransmission(bname)
|
|
||||||
if group and group:IsAlive() and frequency > 0 then
|
|
||||||
--self:_AddBeaconToGroup(group,frequency,bname)
|
|
||||||
else
|
|
||||||
if frequency > 0 then
|
|
||||||
trigger.action.stopRadioTransmission(bname)
|
trigger.action.stopRadioTransmission(bname)
|
||||||
end
|
if group and group:IsAlive() and frequency > 0 then
|
||||||
|
self:_AddBeaconToGroup(group,frequency,bname)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2422,21 +2403,6 @@ function CSAR:_ReachedPilotLimit()
|
|||||||
local islimited = self.limitmaxdownedpilots
|
local islimited = self.limitmaxdownedpilots
|
||||||
local count = self:_CountActiveDownedPilots()
|
local count = self:_CountActiveDownedPilots()
|
||||||
if islimited and (count >= limit) then
|
if islimited and (count >= limit) then
|
||||||
if self.useFIFOLimitReplacement then
|
|
||||||
local oldIndex = -1
|
|
||||||
local oldDownedPilot = nil
|
|
||||||
for _index, _downedpilot in pairs(self.downedPilots) do
|
|
||||||
oldIndex = _index
|
|
||||||
oldDownedPilot = _downedpilot
|
|
||||||
break
|
|
||||||
end
|
|
||||||
if oldDownedPilot then
|
|
||||||
oldDownedPilot.group:Destroy(false)
|
|
||||||
oldDownedPilot.alive = false
|
|
||||||
self:_CheckDownedPilotTable()
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
@@ -2488,10 +2454,9 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
|
|
||||||
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart()
|
self.mash = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart()
|
||||||
|
|
||||||
self.staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterStart()
|
local staticmashes = SET_STATIC:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(self.mashprefix):FilterOnce()
|
||||||
self.zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterStart()
|
local zonemashes = SET_ZONE:New():FilterPrefixes(self.mashprefix):FilterOnce()
|
||||||
|
|
||||||
--[[
|
|
||||||
if staticmashes:Count() > 0 then
|
if staticmashes:Count() > 0 then
|
||||||
for _,_mash in pairs(staticmashes.Set) do
|
for _,_mash in pairs(staticmashes.Set) do
|
||||||
self.mash:AddObject(_mash)
|
self.mash:AddObject(_mash)
|
||||||
@@ -2499,13 +2464,10 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if zonemashes:Count() > 0 then
|
if zonemashes:Count() > 0 then
|
||||||
self:T("Adding zones to self.mash SET")
|
|
||||||
for _,_mash in pairs(zonemashes.Set) do
|
for _,_mash in pairs(zonemashes.Set) do
|
||||||
self.mash:AddObject(_mash)
|
self.mash:AddObject(_mash)
|
||||||
end
|
end
|
||||||
self:T("Objects in SET: "..self.mash:Count())
|
|
||||||
end
|
end
|
||||||
--]]
|
|
||||||
|
|
||||||
if not self.coordinate then
|
if not self.coordinate then
|
||||||
local csarhq = self.mash:GetRandom()
|
local csarhq = self.mash:GetRandom()
|
||||||
|
|||||||
@@ -20,12 +20,11 @@
|
|||||||
--
|
--
|
||||||
-- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!)
|
-- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!)
|
||||||
-- ### Repack addition for crates: **Raiden**
|
-- ### Repack addition for crates: **Raiden**
|
||||||
-- ### Additional cool features: **Lekaa**
|
|
||||||
--
|
--
|
||||||
-- @module Ops.CTLD
|
-- @module Ops.CTLD
|
||||||
-- @image OPS_CTLD.jpg
|
-- @image OPS_CTLD.jpg
|
||||||
|
|
||||||
-- Last Update May 2025
|
-- Last Update April 2025
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -866,7 +865,6 @@ do
|
|||||||
-- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook
|
-- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook
|
||||||
-- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook
|
-- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook
|
||||||
-- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew.
|
-- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew.
|
||||||
-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution.
|
|
||||||
--
|
--
|
||||||
-- ## 2.1 CH-47 Chinook support
|
-- ## 2.1 CH-47 Chinook support
|
||||||
--
|
--
|
||||||
@@ -1414,7 +1412,7 @@ CTLD.FixedWingTypes = {
|
|||||||
|
|
||||||
--- CTLD class version.
|
--- CTLD class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CTLD.version="1.3.35"
|
CTLD.version="1.2.33"
|
||||||
|
|
||||||
--- Instantiate a new CTLD.
|
--- Instantiate a new CTLD.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
@@ -1593,7 +1591,6 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
|||||||
self.subcats = {}
|
self.subcats = {}
|
||||||
self.subcatsTroop = {}
|
self.subcatsTroop = {}
|
||||||
self.showstockinmenuitems = false
|
self.showstockinmenuitems = false
|
||||||
self.onestepmenu = false
|
|
||||||
|
|
||||||
-- disallow building in loadzones
|
-- disallow building in loadzones
|
||||||
self.nobuildinloadzones = true
|
self.nobuildinloadzones = true
|
||||||
@@ -2075,9 +2072,6 @@ function CTLD:_EventHandler(EventData)
|
|||||||
local _group = event.IniGroup
|
local _group = event.IniGroup
|
||||||
local _unit = event.IniUnit
|
local _unit = event.IniUnit
|
||||||
self:_RefreshLoadCratesMenu(_group, _unit)
|
self:_RefreshLoadCratesMenu(_group, _unit)
|
||||||
if self:IsFixedWing(_unit) and self.enableFixedWing then
|
|
||||||
self:_RefreshDropCratesMenu(_group, _unit)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
elseif event.id == EVENTS.PlayerLeaveUnit or event.id == EVENTS.UnitLost then
|
elseif event.id == EVENTS.PlayerLeaveUnit or event.id == EVENTS.UnitLost then
|
||||||
-- remove from pilot table
|
-- remove from pilot table
|
||||||
@@ -2919,10 +2913,10 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack)
|
|||||||
if drop then
|
if drop then
|
||||||
text = string.format("Crates for %s have been dropped!",cratename)
|
text = string.format("Crates for %s have been dropped!",cratename)
|
||||||
self:__CratesDropped(1, Group, Unit, droppedcargo)
|
self:__CratesDropped(1, Group, Unit, droppedcargo)
|
||||||
else
|
|
||||||
self:_SendMessage(text, 10, false, Group)
|
|
||||||
end
|
end
|
||||||
|
self:_SendMessage(text, 10, false, Group)
|
||||||
self:_RefreshLoadCratesMenu(Group, Unit)
|
self:_RefreshLoadCratesMenu(Group, Unit)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3570,7 +3564,7 @@ end
|
|||||||
function CTLD:IsFixedWing(Unit)
|
function CTLD:IsFixedWing(Unit)
|
||||||
local typename = Unit:GetTypeName() or "none"
|
local typename = Unit:GetTypeName() or "none"
|
||||||
for _,_name in pairs(self.FixedWingTypes or {}) do
|
for _,_name in pairs(self.FixedWingTypes or {}) do
|
||||||
if _name and (typename==_name or string.find(typename,_name,1,true))then
|
if typename == _name or string.find(typename,_name,1,true) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3582,10 +3576,7 @@ end
|
|||||||
-- @param Wrapper.Unit#UNIT Unit
|
-- @param Wrapper.Unit#UNIT Unit
|
||||||
-- @return #boolean Outcome
|
-- @return #boolean Outcome
|
||||||
function CTLD:IsHook(Unit)
|
function CTLD:IsHook(Unit)
|
||||||
if not Unit then return false end
|
if Unit and string.find(Unit:GetTypeName(),"CH.47") then
|
||||||
local typeName = Unit:GetTypeName()
|
|
||||||
if not typeName then return false end
|
|
||||||
if string.find(typeName, "CH.47") then
|
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
@@ -3775,6 +3766,7 @@ function CTLD:_UnloadCrates(Group, Unit)
|
|||||||
self:T(self.lid .. " _UnloadCrates")
|
self:T(self.lid .. " _UnloadCrates")
|
||||||
|
|
||||||
if not self.dropcratesanywhere then -- #1570
|
if not self.dropcratesanywhere then -- #1570
|
||||||
|
-- check if we are in DROP zone
|
||||||
local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP)
|
local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP)
|
||||||
if not inzone then
|
if not inzone then
|
||||||
self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group)
|
self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group)
|
||||||
@@ -3783,60 +3775,46 @@ function CTLD:_UnloadCrates(Group, Unit)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- Door check
|
||||||
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
||||||
self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group)
|
self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group)
|
||||||
if not self.debug then return self end
|
if not self.debug then return self end
|
||||||
end
|
end
|
||||||
local hoverunload = self:IsCorrectHover(Unit)
|
-- check for hover unload
|
||||||
|
local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters
|
||||||
local IsHerc = self:IsFixedWing(Unit)
|
local IsHerc = self:IsFixedWing(Unit)
|
||||||
local IsHook = self:IsHook(Unit)
|
local IsHook = self:IsHook(Unit)
|
||||||
if IsHerc and (not IsHook) then
|
if IsHerc and (not IsHook) then
|
||||||
|
-- no hover but airdrop here
|
||||||
hoverunload = self:IsCorrectFlightParameters(Unit)
|
hoverunload = self:IsCorrectFlightParameters(Unit)
|
||||||
end
|
end
|
||||||
|
-- check if we\'re landed
|
||||||
local grounded = not self:IsUnitInAir(Unit)
|
local grounded = not self:IsUnitInAir(Unit)
|
||||||
|
-- Get what we have loaded
|
||||||
local unitname = Unit:GetName()
|
local unitname = Unit:GetName()
|
||||||
if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then
|
if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then
|
||||||
local loadedcargo = self.Loaded_Cargo[unitname] or {}
|
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
|
||||||
|
-- looking for crate
|
||||||
local cargotable = loadedcargo.Cargo
|
local cargotable = loadedcargo.Cargo
|
||||||
local droppedCount = {}
|
|
||||||
local neededMap = {}
|
|
||||||
for _,_cargo in pairs (cargotable) do
|
for _,_cargo in pairs (cargotable) do
|
||||||
local cargo = _cargo
|
local cargo = _cargo -- #CTLD_CARGO
|
||||||
local type = cargo:GetType()
|
local type = cargo:GetType() -- #CTLD_CARGO.Enum
|
||||||
if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then
|
if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then
|
||||||
|
-- unload crates
|
||||||
self:_GetCrates(Group, Unit, cargo, 1, true)
|
self:_GetCrates(Group, Unit, cargo, 1, true)
|
||||||
cargo:SetWasDropped(true)
|
cargo:SetWasDropped(true)
|
||||||
cargo:SetHasMoved(true)
|
cargo:SetHasMoved(true)
|
||||||
local cname = cargo:GetName() or "Unknown"
|
|
||||||
droppedCount[cname] = (droppedCount[cname] or 0) + 1
|
|
||||||
if not neededMap[cname] then
|
|
||||||
neededMap[cname] = cargo:GetCratesNeeded() or 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
-- cleanup load list
|
||||||
for cname,count in pairs(droppedCount) do
|
local loaded = {} -- #CTLD.LoadedCargo
|
||||||
local needed = neededMap[cname] or 1
|
|
||||||
if needed > 1 then
|
|
||||||
local full = math.floor(count/needed)
|
|
||||||
local left = count % needed
|
|
||||||
if full > 0 and left == 0 then
|
|
||||||
self:_SendMessage(string.format("Dropped %d %s.",full,cname),10,false,Group)
|
|
||||||
elseif full > 0 and left > 0 then
|
|
||||||
self:_SendMessage(string.format("Dropped %d %s(s), with %d leftover crate(s).",full,cname,left),10,false,Group)
|
|
||||||
else
|
|
||||||
self:_SendMessage(string.format("Dropped %d/%d crate(s) of %s.",count,needed,cname),15,false,Group)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self:_SendMessage(string.format("Dropped %d %s(s).",count,cname),10,false,Group)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local loaded = {}
|
|
||||||
loaded.Troopsloaded = 0
|
loaded.Troopsloaded = 0
|
||||||
loaded.Cratesloaded = 0
|
loaded.Cratesloaded = 0
|
||||||
loaded.Cargo = {}
|
loaded.Cargo = {}
|
||||||
|
|
||||||
for _,_cargo in pairs (cargotable) do
|
for _,_cargo in pairs (cargotable) do
|
||||||
local cargo = _cargo
|
local cargo = _cargo -- #CTLD_CARGO
|
||||||
local type = cargo:GetType()
|
local type = cargo:GetType() -- #CTLD_CARGO.Enum
|
||||||
local size = cargo:GetCratesNeeded()
|
local size = cargo:GetCratesNeeded()
|
||||||
if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then
|
if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then
|
||||||
table.insert(loaded.Cargo,_cargo)
|
table.insert(loaded.Cargo,_cargo)
|
||||||
@@ -3860,15 +3838,14 @@ function CTLD:_UnloadCrates(Group, Unit)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Function to build nearby crates.
|
--- (Internal) Function to build nearby crates.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param Wrapper.Group#GROUP Group
|
-- @param Wrapper.Group#GROUP Group
|
||||||
-- @param Wrapper.Unit#UNIT Unit
|
-- @param Wrapper.Unit#UNIT Unit
|
||||||
-- @param #boolean Engineering If true build is by an engineering team.
|
-- @param #boolean Engineering If true build is by an engineering team.
|
||||||
-- @param #boolean MultiDrop If true and not engineering or FOB, vary position a bit.
|
function CTLD:_BuildCrates(Group, Unit,Engineering)
|
||||||
function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
|
|
||||||
self:T(self.lid .. " _BuildCrates")
|
self:T(self.lid .. " _BuildCrates")
|
||||||
-- avoid users trying to build from flying Hercs
|
-- avoid users trying to build from flying Hercs
|
||||||
if self:IsFixedWing(Unit) and self.enableFixedWing and not Engineering then
|
if self:IsFixedWing(Unit) and self.enableFixedWing and not Engineering then
|
||||||
@@ -3962,13 +3939,12 @@ function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
|
|||||||
if build.CanBuild then
|
if build.CanBuild then
|
||||||
self:_CleanUpCrates(crates,build,number)
|
self:_CleanUpCrates(crates,build,number)
|
||||||
if self.buildtime and self.buildtime > 0 then
|
if self.buildtime and self.buildtime > 0 then
|
||||||
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate(),MultiDrop)
|
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate())
|
||||||
buildtimer:Start(self.buildtime)
|
buildtimer:Start(self.buildtime)
|
||||||
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
|
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
|
||||||
self:__CratesBuildStarted(1,Group,Unit)
|
self:__CratesBuildStarted(1,Group,Unit)
|
||||||
self:_RefreshDropTroopsMenu(Group,Unit)
|
|
||||||
else
|
else
|
||||||
self:_BuildObjectFromCrates(Group,Unit,build,false,nil,MultiDrop)
|
self:_BuildObjectFromCrates(Group,Unit,build)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4007,14 +3983,13 @@ function CTLD:_PackCratesNearby(Group, Unit)
|
|||||||
_Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player
|
_Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player
|
||||||
self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player
|
self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player
|
||||||
self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu
|
self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu
|
||||||
return true
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:_SendMessage("Nothing to pack at this distance pilot!",10,false,Group)
|
return self
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Function to repair nearby vehicles / FOBs
|
--- (Internal) Function to repair nearby vehicles / FOBs
|
||||||
@@ -4107,8 +4082,7 @@ end
|
|||||||
-- @param #CTLD.Buildable Build
|
-- @param #CTLD.Buildable Build
|
||||||
-- @param #boolean Repair If true this is a repair and not a new build
|
-- @param #boolean Repair If true this is a repair and not a new build
|
||||||
-- @param Core.Point#COORDINATE RepairLocation Location for repair (e.g. where the destroyed unit was)
|
-- @param Core.Point#COORDINATE RepairLocation Location for repair (e.g. where the destroyed unit was)
|
||||||
-- @param #boolean MultiDrop if true and not a repair, vary location a bit if not a FOB
|
function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
|
||||||
function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,MultiDrop)
|
|
||||||
self:T(self.lid .. " _BuildObjectFromCrates")
|
self:T(self.lid .. " _BuildObjectFromCrates")
|
||||||
-- Spawn-a-crate-content
|
-- Spawn-a-crate-content
|
||||||
if Group and Group:IsAlive() or (RepairLocation and not Repair) then
|
if Group and Group:IsAlive() or (RepairLocation and not Repair) then
|
||||||
@@ -4125,7 +4099,7 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,Mult
|
|||||||
if type(temptable) == "string" then
|
if type(temptable) == "string" then
|
||||||
temptable = {temptable}
|
temptable = {temptable}
|
||||||
end
|
end
|
||||||
local zone = nil -- Core.Zone#ZONE_RADIUS
|
local zone = nil
|
||||||
if RepairLocation and not Repair then
|
if RepairLocation and not Repair then
|
||||||
-- timed build
|
-- timed build
|
||||||
zone = ZONE_RADIUS:New(string.format("Build zone-%d",math.random(1,10000)),RepairLocation:GetVec2(),100)
|
zone = ZONE_RADIUS:New(string.format("Build zone-%d",math.random(1,10000)),RepairLocation:GetVec2(),100)
|
||||||
@@ -4134,10 +4108,6 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,Mult
|
|||||||
end
|
end
|
||||||
--local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
|
--local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
|
||||||
local randomcoord = Build.Coord or zone:GetRandomCoordinate(35):GetVec2()
|
local randomcoord = Build.Coord or zone:GetRandomCoordinate(35):GetVec2()
|
||||||
if MultiDrop and (not Repair) and canmove then
|
|
||||||
-- coordinate may be the same, avoid
|
|
||||||
local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
|
|
||||||
end
|
|
||||||
if Repair then
|
if Repair then
|
||||||
randomcoord = RepairLocation:GetVec2()
|
randomcoord = RepairLocation:GetVec2()
|
||||||
end
|
end
|
||||||
@@ -4229,91 +4199,11 @@ function CTLD:_CleanUpCrates(Crates,Build,Number)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Helper - Drop **all** loaded crates nearby and build them.
|
|
||||||
-- @param Wrapper.Group#GROUP Group The calling group
|
|
||||||
-- @param Wrapper.Unit#UNIT Unit The calling unit
|
|
||||||
function CTLD:_DropAndBuild(Group,Unit)
|
|
||||||
if self.nobuildinloadzones then
|
|
||||||
if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then
|
|
||||||
self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:_UnloadCrates(Group,Unit)
|
|
||||||
timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false,true) end,{},timer.getTime()+1)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- (Internal) Helper - Drop a **single** crate set and build it.
|
|
||||||
-- @param Wrapper.Group#GROUP Group The calling group
|
|
||||||
-- @param Wrapper.Unit#UNIT Unit The calling unit
|
|
||||||
-- @param number setIndex Index of the crate-set to drop
|
|
||||||
function CTLD:_DropSingleAndBuild(Group,Unit,setIndex)
|
|
||||||
if self.nobuildinloadzones then
|
|
||||||
if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then
|
|
||||||
self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:_UnloadSingleCrateSet(Group,Unit,setIndex)
|
|
||||||
timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false) end,{},timer.getTime()+1)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- (Internal) Helper - Pack crates near the unit and load them.
|
|
||||||
-- @param Wrapper.Group#GROUP Group The calling group
|
|
||||||
-- @param Wrapper.Unit#UNIT Unit The calling unit
|
|
||||||
function CTLD:_PackAndLoad(Group,Unit)
|
|
||||||
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
|
||||||
self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
if not self:_PackCratesNearby(Group,Unit) then
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- (Internal) Helper - Pack crates near the unit and then remove them.
|
|
||||||
-- @param Wrapper.Group#GROUP Group The calling group
|
|
||||||
-- @param Wrapper.Unit#UNIT Unit The calling unit
|
|
||||||
function CTLD:_PackAndRemove(Group,Unit)
|
|
||||||
if not self:_PackCratesNearby(Group,Unit) then
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
timer.scheduleFunction(function() self:_RemoveCratesNearby(Group,Unit) end,{},timer.getTime()+1)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- (Internal) Helper - get and load in one step
|
|
||||||
-- @param Wrapper.Group#GROUP Group The calling group
|
|
||||||
-- @param Wrapper.Unit#UNIT Unit The calling unit
|
|
||||||
function CTLD:_GetAndLoad(Group,Unit,cargoObj)
|
|
||||||
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
|
||||||
self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
self:_GetCrates(Group,Unit,cargoObj)
|
|
||||||
|
|
||||||
timer.scheduleFunction(function() self:_LoadSingleCrateSet(Group,Unit,cargoObj.Name) end,{},timer.getTime()+1)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- @param Wrapper.Group#GROUP Group The player’s group that triggered the action
|
|
||||||
-- @param Wrapper.Unit#UNIT Unit The unit performing the pack-and-load
|
|
||||||
function CTLD:_GetAllAndLoad(Group,Unit)
|
|
||||||
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
|
|
||||||
self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group)
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- (Internal) Housekeeping - Function to refresh F10 menus.
|
--- (Internal) Housekeeping - Function to refresh F10 menus.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:_RefreshF10Menus()
|
function CTLD:_RefreshF10Menus()
|
||||||
self:T(self.lid .. " _RefreshF10Menus")
|
self:T(self.lid .. " _RefreshF10Menus")
|
||||||
self.onestepmenu = self.onestepmenu or false -- hybrid toggle (default = false)
|
|
||||||
|
|
||||||
-- 1) Gather all the pilot groups from our Set
|
-- 1) Gather all the pilot groups from our Set
|
||||||
local PlayerSet = self.PilotGroups
|
local PlayerSet = self.PilotGroups
|
||||||
@@ -4424,6 +4314,7 @@ function CTLD:_RefreshF10Menus()
|
|||||||
local menutext = cargoObj.Name
|
local menutext = cargoObj.Name
|
||||||
if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end
|
if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end
|
||||||
MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj)
|
MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4449,66 +4340,11 @@ function CTLD:_RefreshF10Menus()
|
|||||||
_group.MyTopCratesMenu = topcrates
|
_group.MyTopCratesMenu = topcrates
|
||||||
|
|
||||||
-- Build the “Get Crates” sub-menu items
|
-- Build the “Get Crates” sub-menu items
|
||||||
local cratesmenu = MENU_GROUP:New(_group,"Get Crates",topcrates)
|
local cratesmenu = MENU_GROUP:New(_group, "Get Crates", topcrates)
|
||||||
|
|
||||||
if self.onestepmenu then
|
|
||||||
if self.usesubcats then
|
|
||||||
local subcatmenus = {}
|
|
||||||
for catName,_ in pairs(self.subcats) do
|
|
||||||
subcatmenus[catName] = MENU_GROUP:New(_group,catName,cratesmenu)
|
|
||||||
end
|
|
||||||
for _,cargoObj in pairs(self.Cargo_Crates) do
|
|
||||||
if not cargoObj.DontShowInMenu then
|
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
|
||||||
local stock = cargoObj:GetStock()
|
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
|
||||||
local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory])
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for _,cargoObj in pairs(self.Cargo_Statics) do
|
|
||||||
if not cargoObj.DontShowInMenu then
|
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
|
||||||
local stock = cargoObj:GetStock()
|
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
|
||||||
local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory])
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for _,cargoObj in pairs(self.Cargo_Crates) do
|
|
||||||
if not cargoObj.DontShowInMenu then
|
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
|
||||||
local stock = cargoObj:GetStock()
|
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
|
||||||
local mSet = MENU_GROUP:New(_group,txt,cratesmenu)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for _,cargoObj in pairs(self.Cargo_Statics) do
|
|
||||||
if not cargoObj.DontShowInMenu then
|
|
||||||
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
|
|
||||||
if cargoObj.Location then txt = txt.."[R]" end
|
|
||||||
local stock = cargoObj:GetStock()
|
|
||||||
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
|
|
||||||
local mSet = MENU_GROUP:New(_group,txt,cratesmenu)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get",mSet,self._GetCrates,self,_group,_unit,cargoObj)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if self.usesubcats then
|
if self.usesubcats then
|
||||||
local subcatmenus = {}
|
local subcatmenus = {}
|
||||||
for catName, _ in pairs(self.subcats) do
|
for catName, _ in pairs(self.subcats) do
|
||||||
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case
|
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu)
|
||||||
end
|
end
|
||||||
for _, cargoObj in pairs(self.Cargo_Crates) do
|
for _, cargoObj in pairs(self.Cargo_Crates) do
|
||||||
if not cargoObj.DontShowInMenu then
|
if not cargoObj.DontShowInMenu then
|
||||||
@@ -4548,15 +4384,14 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates)
|
local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates)
|
||||||
_group.MyLoadCratesMenu=loadCratesMenu
|
_group.MyLoadCratesMenu=loadCratesMenu
|
||||||
MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit)
|
MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit)
|
||||||
MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit)
|
MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit)
|
||||||
|
|
||||||
local dropCratesMenu = MENU_GROUP:New(_group,"Drop Crates",topcrates)
|
local dropCratesMenu=MENU_GROUP:New(_group,"Drop Crates",topcrates)
|
||||||
topcrates.DropCratesMenu = dropCratesMenu
|
topcrates.DropCratesMenu=dropCratesMenu
|
||||||
|
|
||||||
if not self.nobuildmenu then
|
if not self.nobuildmenu then
|
||||||
MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit)
|
MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit)
|
||||||
@@ -4566,16 +4401,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates)
|
local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates)
|
||||||
MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit)
|
MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit)
|
||||||
|
|
||||||
if self.onestepmenu then
|
|
||||||
local mPack=MENU_GROUP:New(_group,"Pack crates",topcrates)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Pack",mPack,self._PackCratesNearby,self,_group,_unit)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Pack and Load",mPack,self._PackAndLoad,self,_group,_unit)
|
|
||||||
MENU_GROUP_COMMAND:New(_group,"Pack and Remove",mPack,self._PackAndRemove,self,_group,_unit)
|
|
||||||
MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit)
|
|
||||||
else
|
|
||||||
MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit)
|
MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit)
|
||||||
MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit)
|
MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit)
|
||||||
end
|
|
||||||
|
|
||||||
local uName = _unit:GetName()
|
local uName = _unit:GetName()
|
||||||
local loadedData = self.Loaded_Cargo[uName]
|
local loadedData = self.Loaded_Cargo[uName]
|
||||||
@@ -4596,6 +4423,8 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
-- Misc sub‐menus
|
-- Misc sub‐menus
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
@@ -4624,7 +4453,7 @@ function CTLD:_RefreshF10Menus()
|
|||||||
|
|
||||||
-- Mark we built the menu
|
-- Mark we built the menu
|
||||||
self.MenusDone[_unitName] = true
|
self.MenusDone[_unitName] = true
|
||||||
self:_RefreshLoadCratesMenu(_group,_unit)
|
self:_RefreshLoadCratesMenu(_group, _unit)
|
||||||
self:_RefreshDropCratesMenu(_group,_unit)
|
self:_RefreshDropCratesMenu(_group,_unit)
|
||||||
|
|
||||||
end -- if _group
|
end -- if _group
|
||||||
@@ -4635,53 +4464,45 @@ function CTLD:_RefreshF10Menus()
|
|||||||
end -- for all pilot units
|
end -- for all pilot units
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Function to refresh the menu for load crates. Triggered from land/getcrate/pack and more
|
--- (Internal) Function to refresh the menu for load crates. Triggered from land/getcrate/pack and more
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param Wrapper.Group#GROUP Group The calling group.
|
-- @param Wrapper.Group#GROUP Group The calling group.
|
||||||
-- @param Wrapper.Unit#UNIT Unit The calling unit.
|
-- @param Wrapper.Unit#UNIT Unit The calling unit.
|
||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:_RefreshLoadCratesMenu(Group,Unit)
|
function CTLD:_RefreshLoadCratesMenu(Group, Unit)
|
||||||
if not Group.MyLoadCratesMenu then return end
|
if not Group.MyLoadCratesMenu then return end
|
||||||
Group.MyLoadCratesMenu:RemoveSubMenus()
|
Group.MyLoadCratesMenu:RemoveSubMenus()
|
||||||
|
|
||||||
local d=self.CrateDistance or 35
|
local d = self.CrateDistance or 35
|
||||||
local nearby,n=self:_FindCratesNearby(Group,Unit,d,true,true)
|
local nearby, n = self:_FindCratesNearby(Group, Unit, d, true, true)
|
||||||
if n==0 then
|
if n == 0 then
|
||||||
MENU_GROUP_COMMAND:New(Group,"No crates found! Rescan?",Group.MyLoadCratesMenu,function() self:_RefreshLoadCratesMenu(Group,Unit) end)
|
MENU_GROUP_COMMAND:New(Group, "No crates found! Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
MENU_GROUP_COMMAND:New(Group,"Load ALL",Group.MyLoadCratesMenu,self._LoadCratesNearby,self,Group,Unit)
|
MENU_GROUP_COMMAND:New(Group, "Load ALL", Group.MyLoadCratesMenu, self._LoadCratesNearby, self, Group, Unit)
|
||||||
|
local cargoByName = {}
|
||||||
local cargoByName={}
|
for _, crate in pairs(nearby) do
|
||||||
for _,crate in pairs(nearby) do
|
local cName = crate:GetName()
|
||||||
local name=crate:GetName()
|
cargoByName[cName] = cargoByName[cName] or {}
|
||||||
cargoByName[name]=cargoByName[name] or{}
|
table.insert(cargoByName[cName], crate)
|
||||||
table.insert(cargoByName[name],crate)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local lineIndex=1
|
for cName, cList in pairs(cargoByName) do
|
||||||
for cName,list in pairs(cargoByName) do
|
local needed = cList[1]:GetCratesNeeded() or 1
|
||||||
local needed=list[1]:GetCratesNeeded() or 1
|
local found = #cList
|
||||||
table.sort(list,function(a,b)return a:GetID()<b:GetID() end)
|
|
||||||
local i=1
|
local line
|
||||||
while i<=#list do
|
if found >= needed then
|
||||||
local left=#list-i+1
|
line = string.format("Load %s", cName)
|
||||||
local label
|
|
||||||
if left>=needed then
|
|
||||||
label=string.format("%d. Load %s",lineIndex,cName)
|
|
||||||
i=i+needed
|
|
||||||
else
|
else
|
||||||
label=string.format("%d. Load %s (%d/%d)",lineIndex,cName,left,needed)
|
MENU_GROUP_COMMAND:New(Group, "Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end)
|
||||||
i=#list+1
|
line = string.format("Load %s (%d/%d)", cName, found, needed)
|
||||||
end
|
end
|
||||||
MENU_GROUP_COMMAND:New(Group,label,Group.MyLoadCratesMenu,self._LoadSingleCrateSet,self,Group,Unit,cName)
|
MENU_GROUP_COMMAND:New(Group, line, Group.MyLoadCratesMenu, self._LoadSingleCrateSet, self, Group, Unit, cName)
|
||||||
lineIndex=lineIndex+1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Loads exactly `CratesNeeded` crates for one cargoName in range.
|
-- Loads exactly `CratesNeeded` crates for one cargoName in range.
|
||||||
@@ -4891,17 +4712,7 @@ function CTLD:_UnloadSingleCrateSet(Group, Unit, setIndex)
|
|||||||
cObj:SetWasDropped(true)
|
cObj:SetWasDropped(true)
|
||||||
cObj:SetHasMoved(true)
|
cObj:SetHasMoved(true)
|
||||||
end
|
end
|
||||||
local cname = crateObj:GetName() or "Unknown"
|
|
||||||
local count = #chunk
|
|
||||||
if needed > 1 then
|
|
||||||
if count == needed then
|
|
||||||
self:_SendMessage(string.format("Dropped %d %s.", 1, cname), 10, false, Group)
|
|
||||||
else
|
|
||||||
self:_SendMessage(string.format("Dropped %d/%d crate(s) of %s.", count, needed, cname), 15, false, Group)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self:_SendMessage(string.format("Dropped %d %s(s).", count, cname), 10, false, Group)
|
|
||||||
end
|
|
||||||
-- Rebuild the cargo list to remove the dropped crates
|
-- Rebuild the cargo list to remove the dropped crates
|
||||||
local loadedData = self.Loaded_Cargo[unitName]
|
local loadedData = self.Loaded_Cargo[unitName]
|
||||||
if loadedData and loadedData.Cargo then
|
if loadedData and loadedData.Cargo then
|
||||||
@@ -4934,7 +4745,6 @@ end
|
|||||||
-- @param Wrapper.Unit#UNIT Unit The calling unit.
|
-- @param Wrapper.Unit#UNIT Unit The calling unit.
|
||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
||||||
|
|
||||||
if not Group.CTLDTopmenu then return end
|
if not Group.CTLDTopmenu then return end
|
||||||
local topCrates = Group.MyTopCratesMenu
|
local topCrates = Group.MyTopCratesMenu
|
||||||
if not topCrates then return end
|
if not topCrates then return end
|
||||||
@@ -4970,15 +4780,7 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
-- DEFAULT (“classic”) versus ONE-STEP behaviour
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
if not self.onestepmenu then
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
-- classic menu
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit)
|
MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit)
|
||||||
|
|
||||||
self.CrateGroupList=self.CrateGroupList or{}
|
self.CrateGroupList=self.CrateGroupList or{}
|
||||||
self.CrateGroupList[Unit:GetName()]={}
|
self.CrateGroupList[Unit:GetName()]={}
|
||||||
|
|
||||||
@@ -5013,57 +4815,7 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
|||||||
lineIndex=lineIndex+1
|
lineIndex=lineIndex+1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
else
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
-- one-step (enhanced) menu
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu)
|
|
||||||
MENU_GROUP_COMMAND:New(Group,"Drop",mAll,self._UnloadCrates,self,Group,Unit)
|
|
||||||
if not ( self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) ) then
|
|
||||||
MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit)
|
|
||||||
end
|
|
||||||
|
|
||||||
self.CrateGroupList=self.CrateGroupList or{}
|
|
||||||
self.CrateGroupList[Unit:GetName()]={}
|
|
||||||
|
|
||||||
local lineIndex=1
|
|
||||||
for cName,list in pairs(cargoByName) do
|
|
||||||
local needed=list[1]:GetCratesNeeded() or 1
|
|
||||||
table.sort(list,function(a,b)return a:GetID()<b:GetID()end)
|
|
||||||
local i=1
|
|
||||||
while i<=#list do
|
|
||||||
local left=(#list-i+1)
|
|
||||||
if left>=needed then
|
|
||||||
local chunk={}
|
|
||||||
for n=i,i+needed-1 do
|
|
||||||
table.insert(chunk,list[n])
|
|
||||||
end
|
|
||||||
local label=string.format("%d. %s",lineIndex,cName)
|
|
||||||
table.insert(self.CrateGroupList[Unit:GetName()],chunk)
|
|
||||||
local setIndex=#self.CrateGroupList[Unit:GetName()]
|
|
||||||
local mSet=MENU_GROUP:New(Group,label,dropCratesMenu)
|
|
||||||
MENU_GROUP_COMMAND:New(Group,"Drop",mSet,self._UnloadSingleCrateSet,self,Group,Unit,setIndex)
|
|
||||||
if not ( self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) ) then
|
|
||||||
MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex)
|
|
||||||
end
|
|
||||||
i=i+needed
|
|
||||||
else
|
|
||||||
local chunk={}
|
|
||||||
for n=i,#list do
|
|
||||||
table.insert(chunk,list[n])
|
|
||||||
end
|
|
||||||
local label=string.format("%d. %s %d/%d",lineIndex,cName,left,needed)
|
|
||||||
table.insert(self.CrateGroupList[Unit:GetName()],chunk)
|
|
||||||
local setIndex=#self.CrateGroupList[Unit:GetName()]
|
|
||||||
MENU_GROUP_COMMAND:New(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex)
|
|
||||||
i=#list+1
|
|
||||||
end
|
|
||||||
lineIndex=lineIndex+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- (Internal) Function to unload a single Troop group by ID.
|
--- (Internal) Function to unload a single Troop group by ID.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
@@ -5112,7 +4864,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Drop the FIRST cargo in that chunk
|
-- Drop ONLY the FIRST cargo in that chunk
|
||||||
local foundCargo = chunk[1]
|
local foundCargo = chunk[1]
|
||||||
if not foundCargo then
|
if not foundCargo then
|
||||||
self:_SendMessage(string.format("No troop cargo at chunk %d!", chunkID), 10, false, Group)
|
self:_SendMessage(string.format("No troop cargo at chunk %d!", chunkID), 10, false, Group)
|
||||||
@@ -5173,8 +4925,6 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
|||||||
foundCargo:SetWasDropped(true)
|
foundCargo:SetWasDropped(true)
|
||||||
if cType == CTLD_CARGO.Enum.ENGINEERS then
|
if cType == CTLD_CARGO.Enum.ENGINEERS then
|
||||||
self.Engineers = self.Engineers + 1
|
self.Engineers = self.Engineers + 1
|
||||||
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
|
||||||
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
|
|
||||||
self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group)
|
self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group)
|
||||||
else
|
else
|
||||||
self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group)
|
self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group)
|
||||||
@@ -5912,7 +5662,6 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
|
|||||||
if Zonetype == CTLD.CargoZoneType.SHIP then
|
if Zonetype == CTLD.CargoZoneType.SHIP then
|
||||||
self:T("Checking Type Ship: "..zonename)
|
self:T("Checking Type Ship: "..zonename)
|
||||||
local ZoneUNIT = UNIT:FindByName(zonename)
|
local ZoneUNIT = UNIT:FindByName(zonename)
|
||||||
if not ZoneUNIT then return false end
|
|
||||||
zonecoord = ZoneUNIT:GetCoordinate()
|
zonecoord = ZoneUNIT:GetCoordinate()
|
||||||
zoneradius = czone.shiplength
|
zoneradius = czone.shiplength
|
||||||
zonewidth = czone.shipwidth
|
zonewidth = czone.shipwidth
|
||||||
@@ -5990,23 +5739,16 @@ function CTLD:SmokeZoneNearBy(Unit, Flare)
|
|||||||
for index,cargozone in pairs(zones[i]) do
|
for index,cargozone in pairs(zones[i]) do
|
||||||
local CZone = cargozone --#CTLD.CargoZone
|
local CZone = cargozone --#CTLD.CargoZone
|
||||||
local zonename = CZone.name
|
local zonename = CZone.name
|
||||||
local zone = nil -- Core.Zone#ZONE_RADIUS
|
local zone = nil
|
||||||
local airbasezone = false
|
|
||||||
if i == 4 then
|
if i == 4 then
|
||||||
zone = UNIT:FindByName(zonename)
|
zone = UNIT:FindByName(zonename)
|
||||||
else
|
else
|
||||||
zone = ZONE:FindByName(zonename)
|
zone = ZONE:FindByName(zonename)
|
||||||
if not zone then
|
if not zone then
|
||||||
zone = AIRBASE:FindByName(zonename):GetZone()
|
zone = AIRBASE:FindByName(zonename):GetZone()
|
||||||
airbasezone = true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local zonecoord = zone:GetCoordinate()
|
local zonecoord = zone:GetCoordinate()
|
||||||
-- Avoid smoke/flares on runways
|
|
||||||
if (i==1 or 1==3) and airbasezone==true and zone:IsInstanceOf("ZONE_BASE") then
|
|
||||||
zonecoord = zone:GetRandomCoordinate(inner,outer,{land.SurfaceType.LAND})
|
|
||||||
end
|
|
||||||
if zonecoord then
|
|
||||||
local active = CZone.active
|
local active = CZone.active
|
||||||
local color = CZone.color
|
local color = CZone.color
|
||||||
local distance = self:_GetDistance(zonecoord,unitcoord)
|
local distance = self:_GetDistance(zonecoord,unitcoord)
|
||||||
@@ -6025,7 +5767,6 @@ function CTLD:SmokeZoneNearBy(Unit, Flare)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
if not smoked then
|
if not smoked then
|
||||||
local distance = UTILS.MetersToNM(self.smokedistance)
|
local distance = UTILS.MetersToNM(self.smokedistance)
|
||||||
self:_SendMessage(string.format("Negative, need to be closer than %dnm to a zone!",distance), 10, false, Group)
|
self:_SendMessage(string.format("Negative, need to be closer than %dnm to a zone!",distance), 10, false, Group)
|
||||||
@@ -7242,8 +6983,7 @@ end
|
|||||||
-- right subtype?
|
-- right subtype?
|
||||||
if Event == subtype and not task:IsDone() then
|
if Event == subtype and not task:IsDone() then
|
||||||
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
|
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
|
||||||
self:T2({Name=Groupname,Property=task:GetProperty("ExtractName")})
|
--self:T2({Name=Groupname,Property=task:GetProperty("ExtractName")})
|
||||||
if task:GetProperty("ExtractName") then
|
|
||||||
local okaygroup = string.find(Groupname,task:GetProperty("ExtractName"),1,true)
|
local okaygroup = string.find(Groupname,task:GetProperty("ExtractName"),1,true)
|
||||||
if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and okaygroup then
|
if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and okaygroup then
|
||||||
if task.Clients:HasUniqueID(playername) then
|
if task.Clients:HasUniqueID(playername) then
|
||||||
@@ -7251,9 +6991,6 @@ end
|
|||||||
task:__Success(-1)
|
task:__Success(-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
self:T({Text="'ExtractName' Property not set",Name=Groupname,Property=task.Type})
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -70,7 +70,6 @@
|
|||||||
-- @field #boolean DespawnAfterLanding
|
-- @field #boolean DespawnAfterLanding
|
||||||
-- @field #boolean DespawnAfterHolding
|
-- @field #boolean DespawnAfterHolding
|
||||||
-- @field #list<Ops.Auftrag#AUFTRAG> ListOfAuftrag
|
-- @field #list<Ops.Auftrag#AUFTRAG> ListOfAuftrag
|
||||||
-- @field #string defaulttakeofftype Take off type
|
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
||||||
@@ -224,8 +223,7 @@ EASYGCICAP = {
|
|||||||
ReadyFlightGroups = {},
|
ReadyFlightGroups = {},
|
||||||
DespawnAfterLanding = false,
|
DespawnAfterLanding = false,
|
||||||
DespawnAfterHolding = true,
|
DespawnAfterHolding = true,
|
||||||
ListOfAuftrag = {},
|
ListOfAuftrag = {}
|
||||||
defaulttakeofftype = "hot",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Internal Squadron data type
|
--- Internal Squadron data type
|
||||||
@@ -261,7 +259,7 @@ EASYGCICAP = {
|
|||||||
|
|
||||||
--- EASYGCICAP class version.
|
--- EASYGCICAP class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
EASYGCICAP.version="0.1.23"
|
EASYGCICAP.version="0.1.18"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -314,7 +312,6 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
|||||||
self.DespawnAfterLanding = false
|
self.DespawnAfterLanding = false
|
||||||
self.DespawnAfterHolding = true
|
self.DespawnAfterHolding = true
|
||||||
self.ListOfAuftrag = {}
|
self.ListOfAuftrag = {}
|
||||||
self.defaulttakeofftype = "hot"
|
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
||||||
@@ -403,16 +400,6 @@ function EASYGCICAP:SetDefaultRepeatOnFailure(Retries)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add default take off type for the airwings.
|
|
||||||
-- @param #EASYGCICAP self
|
|
||||||
-- @param #string Takeoff Can be "hot", "cold", or "air" - default is "hot".
|
|
||||||
-- @return #EASYGCICAP self
|
|
||||||
function EASYGCICAP:SetDefaultTakeOffType(Takeoff)
|
|
||||||
self:T(self.lid.."SetDefaultTakeOffType")
|
|
||||||
self.defaulttakeofftype = Takeoff or "hot"
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set default CAP Speed in knots
|
--- Set default CAP Speed in knots
|
||||||
-- @param #EASYGCICAP self
|
-- @param #EASYGCICAP self
|
||||||
-- @param #number Speed Speed defaults to 300
|
-- @param #number Speed Speed defaults to 300
|
||||||
@@ -582,13 +569,6 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
local DespawnAfterLanding = self.DespawnAfterLanding
|
local DespawnAfterLanding = self.DespawnAfterLanding
|
||||||
local DespawnAfterHolding = self.DespawnAfterHolding
|
local DespawnAfterHolding = self.DespawnAfterHolding
|
||||||
|
|
||||||
-- Check STATIC name
|
|
||||||
local check = STATIC:FindByName(Airbasename,false)
|
|
||||||
if check == nil then
|
|
||||||
MESSAGE:New(self.lid.."There's no warehouse static on the map (wrong naming?) for airbase "..tostring(Airbasename).."!",30,"CHECK"):ToAllIf(self.debug):ToLog()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Create Airwing
|
-- Create Airwing
|
||||||
local CAP_Wing = AIRWING:New(Airbasename,Alias)
|
local CAP_Wing = AIRWING:New(Airbasename,Alias)
|
||||||
CAP_Wing:SetVerbosityLevel(0)
|
CAP_Wing:SetVerbosityLevel(0)
|
||||||
@@ -616,8 +596,9 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
if #self.ManagedREC > 0 then
|
if #self.ManagedREC > 0 then
|
||||||
CAP_Wing:SetNumberRecon(1)
|
CAP_Wing:SetNumberRecon(1)
|
||||||
end
|
end
|
||||||
|
--local PatrolCoordinateKutaisi = ZONE:New(CapZoneName):GetCoordinate()
|
||||||
CAP_Wing:SetTakeoffType(self.defaulttakeofftype)
|
--CAP_Wing:AddPatrolPointCAP(PatrolCoordinateKutaisi,self.capalt,UTILS.KnotsToAltKIAS(self.capspeed,self.capalt),self.capdir,self.capleg)
|
||||||
|
CAP_Wing:SetTakeoffHot()
|
||||||
CAP_Wing:SetLowFuelThreshold(0.3)
|
CAP_Wing:SetLowFuelThreshold(0.3)
|
||||||
CAP_Wing.RandomAssetScore = math.random(50,100)
|
CAP_Wing.RandomAssetScore = math.random(50,100)
|
||||||
CAP_Wing:Start()
|
CAP_Wing:Start()
|
||||||
@@ -625,9 +606,6 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
local Intel = self.Intel
|
local Intel = self.Intel
|
||||||
|
|
||||||
local TankerInvisible = self.TankerInvisible
|
local TankerInvisible = self.TankerInvisible
|
||||||
local engagerange = self.engagerange
|
|
||||||
local GoZoneSet = self.GoZoneSet
|
|
||||||
local NoGoZoneSet = self.NoGoZoneSet
|
|
||||||
|
|
||||||
function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission)
|
function CAP_Wing:onbeforeFlightOnMission(From, Event, To, Flightgroup, Mission)
|
||||||
local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP
|
local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP
|
||||||
@@ -641,7 +619,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
|||||||
flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch()
|
flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch()
|
||||||
if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then
|
if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then
|
||||||
flightgroup:SetDetection(true)
|
flightgroup:SetDetection(true)
|
||||||
flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet)
|
flightgroup:SetEngageDetectedOn(self.engagerange,{"Air"},self.GoZoneSet,self.NoGoZoneSet)
|
||||||
flightgroup:SetOutOfAAMRTB()
|
flightgroup:SetOutOfAAMRTB()
|
||||||
if CapFormation then
|
if CapFormation then
|
||||||
flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation)
|
flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation)
|
||||||
@@ -785,11 +763,6 @@ function EASYGCICAP:_SetTankerPatrolPoints()
|
|||||||
self:T(self.lid.."_SetTankerPatrolPoints")
|
self:T(self.lid.."_SetTankerPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedTK) do
|
for _,_data in pairs(self.ManagedTK) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
self:T("Airbasename = "..data.AirbaseName)
|
|
||||||
if not self.wings[data.AirbaseName] then
|
|
||||||
MESSAGE:New(self.lid.."You are trying to create a TANKER point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
@@ -809,11 +782,6 @@ function EASYGCICAP:_SetAwacsPatrolPoints()
|
|||||||
self:T(self.lid.."_SetAwacsPatrolPoints")
|
self:T(self.lid.."_SetAwacsPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedEWR) do
|
for _,_data in pairs(self.ManagedEWR) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
self:T("Airbasename = "..data.AirbaseName)
|
|
||||||
if not self.wings[data.AirbaseName] then
|
|
||||||
MESSAGE:New(self.lid.."You are trying to create an AWACS point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
@@ -833,11 +801,6 @@ function EASYGCICAP:_SetCAPPatrolPoints()
|
|||||||
self:T(self.lid.."_SetCAPPatrolPoints")
|
self:T(self.lid.."_SetCAPPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedCP) do
|
for _,_data in pairs(self.ManagedCP) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
self:T("Airbasename = "..data.AirbaseName)
|
|
||||||
if not self.wings[data.AirbaseName] then
|
|
||||||
MESSAGE:New(self.lid.."You are trying to create a CAP point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
@@ -857,11 +820,6 @@ function EASYGCICAP:_SetReconPatrolPoints()
|
|||||||
self:T(self.lid.."_SetReconPatrolPoints")
|
self:T(self.lid.."_SetReconPatrolPoints")
|
||||||
for _,_data in pairs(self.ManagedREC) do
|
for _,_data in pairs(self.ManagedREC) do
|
||||||
local data = _data --#EASYGCICAP.CapPoint
|
local data = _data --#EASYGCICAP.CapPoint
|
||||||
self:T("Airbasename = "..data.AirbaseName)
|
|
||||||
if not self.wings[data.AirbaseName] then
|
|
||||||
MESSAGE:New(self.lid.."You are trying to create a RECON point for which there is no wing! "..tostring(data.AirbaseName),30,"CHECK"):ToAllIf(self.debug):ToLog()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
local Wing = self.wings[data.AirbaseName][1] -- Ops.Airwing#AIRWING
|
||||||
local Coordinate = data.Coordinate
|
local Coordinate = data.Coordinate
|
||||||
local Altitude = data.Altitude
|
local Altitude = data.Altitude
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -259,7 +259,7 @@ function FLIGHTGROUP:New(group)
|
|||||||
local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #FLIGHTGROUP
|
local self=BASE:Inherit(self, OPSGROUP:New(group)) -- #FLIGHTGROUP
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("FLIGHTGROUP %s | ", self.groupname or "N/A")
|
self.lid=string.format("FLIGHTGROUP %s | ", self.groupname)
|
||||||
|
|
||||||
-- Defaults
|
-- Defaults
|
||||||
self:SetDefaultROE()
|
self:SetDefaultROE()
|
||||||
@@ -2003,9 +2003,6 @@ function FLIGHTGROUP:onafterElementAirborne(From, Event, To, Element)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T2(self.lid..string.format("Element airborne %s", Element.name))
|
self:T2(self.lid..string.format("Element airborne %s", Element.name))
|
||||||
|
|
||||||
-- Set parking spot to free. Also for FC. This is usually done after taxiing but doing it here in case the group is teleported.
|
|
||||||
self:_SetElementParkingFree(Element)
|
|
||||||
|
|
||||||
-- Set element status.
|
-- Set element status.
|
||||||
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.AIRBORNE)
|
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.AIRBORNE)
|
||||||
|
|
||||||
|
|||||||
@@ -2324,7 +2324,7 @@ INTEL_DLINK = {
|
|||||||
verbose = 0,
|
verbose = 0,
|
||||||
lid = nil,
|
lid = nil,
|
||||||
alias = nil,
|
alias = nil,
|
||||||
cachetime = 120,
|
cachetime = 300,
|
||||||
interval = 20,
|
interval = 20,
|
||||||
contacts = {},
|
contacts = {},
|
||||||
clusters = {},
|
clusters = {},
|
||||||
@@ -2333,7 +2333,7 @@ INTEL_DLINK = {
|
|||||||
|
|
||||||
--- Version string
|
--- Version string
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
INTEL_DLINK.version = "0.0.2"
|
INTEL_DLINK.version = "0.0.1"
|
||||||
|
|
||||||
--- Function to instantiate a new object
|
--- Function to instantiate a new object
|
||||||
-- @param #INTEL_DLINK self
|
-- @param #INTEL_DLINK self
|
||||||
@@ -2384,15 +2384,15 @@ function INTEL_DLINK:New(Intels, Alias, Interval, Cachetime)
|
|||||||
self.alias="SPECTRE"
|
self.alias="SPECTRE"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cache time
|
||||||
|
self.cachetime = Cachetime or 300
|
||||||
|
|
||||||
-- Interval
|
-- Interval
|
||||||
self.interval = Interval or 20
|
self.interval = Interval or 20
|
||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("INTEL_DLINK %s | ", self.alias)
|
self.lid=string.format("INTEL_DLINK %s | ", self.alias)
|
||||||
|
|
||||||
-- Cache time
|
|
||||||
self:SetDLinkCacheTime(Cachetime or 120)
|
|
||||||
|
|
||||||
-- Start State.
|
-- Start State.
|
||||||
self:SetStartState("Stopped")
|
self:SetStartState("Stopped")
|
||||||
|
|
||||||
@@ -2477,16 +2477,6 @@ function INTEL_DLINK:onafterStart(From, Event, To)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function to set how long INTEL DLINK remembers contacts.
|
|
||||||
-- @param #INTEL_DLINK self
|
|
||||||
-- @param #number seconds Remember this many seconds. Defaults to 180.
|
|
||||||
-- @return #INTEL_DLINK self
|
|
||||||
function INTEL_DLINK:SetDLinkCacheTime(seconds)
|
|
||||||
self.cachetime = math.abs(seconds or 120)
|
|
||||||
self:I(self.lid.."Caching for "..self.cachetime.." seconds.")
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Function to collect data from the various #INTEL
|
--- Function to collect data from the various #INTEL
|
||||||
-- @param #INTEL_DLINK self
|
-- @param #INTEL_DLINK self
|
||||||
-- @param #string From The From state
|
-- @param #string From The From state
|
||||||
|
|||||||
@@ -445,6 +445,7 @@ OPSGROUP.TaskType={
|
|||||||
-- @field Wrapper.Marker#MARKER marker Marker on the F10 map.
|
-- @field Wrapper.Marker#MARKER marker Marker on the F10 map.
|
||||||
-- @field #string formation Ground formation. Similar to action but on/off road.
|
-- @field #string formation Ground formation. Similar to action but on/off road.
|
||||||
-- @field #number missionUID Mission UID (Auftragsnr) this waypoint belongs to.
|
-- @field #number missionUID Mission UID (Auftragsnr) this waypoint belongs to.
|
||||||
|
-- @field Navigation.FlightPlan#FLIGHTPLAN flightplan Flightplan this waypoint belongs to.
|
||||||
|
|
||||||
--- Cargo Carrier status.
|
--- Cargo Carrier status.
|
||||||
-- @type OPSGROUP.CarrierStatus
|
-- @type OPSGROUP.CarrierStatus
|
||||||
@@ -573,6 +574,11 @@ function OPSGROUP:New(group)
|
|||||||
|
|
||||||
-- Set DCS group and controller.
|
-- Set DCS group and controller.
|
||||||
self.dcsgroup=self:GetDCSGroup()
|
self.dcsgroup=self:GetDCSGroup()
|
||||||
|
|
||||||
|
if not self.dcsgroup then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
self.controller=self.dcsgroup:getController()
|
self.controller=self.dcsgroup:getController()
|
||||||
|
|
||||||
-- Category.
|
-- Category.
|
||||||
@@ -5589,13 +5595,10 @@ function OPSGROUP:onafterUnpauseMission(From, Event, To)
|
|||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:T(self.lid..string.format("Unpausing mission %s [%s]", mission:GetName(), mission:GetType()))
|
self:T(self.lid..string.format("Unpausing mission %s [%s]", mission:GetName(), mission:GetType()))
|
||||||
|
|
||||||
-- Set state of mission, e.g. for not teleporting again
|
|
||||||
mission.unpaused=true
|
|
||||||
|
|
||||||
-- Start mission.
|
-- Start mission.
|
||||||
self:MissionStart(mission)
|
self:MissionStart(mission)
|
||||||
|
|
||||||
-- Remove mission from pausedmissions queue
|
-- Remove mission from
|
||||||
for i,mid in pairs(self.pausedmissions) do
|
for i,mid in pairs(self.pausedmissions) do
|
||||||
--self:T(self.lid..string.format("Checking paused mission", mid))
|
--self:T(self.lid..string.format("Checking paused mission", mid))
|
||||||
if mid==mission.auftragsnummer then
|
if mid==mission.auftragsnummer then
|
||||||
@@ -6235,7 +6238,7 @@ function OPSGROUP:RouteToMission(mission, delay)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check if group is mobile. Note that some immobile units report a speed of 1 m/s = 3.6 km/h.
|
-- Check if group is mobile. Note that some immobile units report a speed of 1 m/s = 3.6 km/h.
|
||||||
if (self.speedMax<=3.6 or mission.teleport) and not mission.unpaused then
|
if self.speedMax<=3.6 or mission.teleport then
|
||||||
|
|
||||||
-- Teleport to waypoint coordinate. Mission will not be paused.
|
-- Teleport to waypoint coordinate. Mission will not be paused.
|
||||||
self:Teleport(waypointcoord, nil, true)
|
self:Teleport(waypointcoord, nil, true)
|
||||||
@@ -11352,9 +11355,9 @@ function OPSGROUP:_SimpleTaskFunction(Function, uid)
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enhance waypoint table.
|
--- Enhanced waypoint table.
|
||||||
-- @param #OPSGROUP self
|
-- @param #OPSGROUP self
|
||||||
-- @param #OPSGROUP.Waypoint Waypoint data.
|
-- @param #OPSGROUP.Waypoint waypoint Waypoint data.
|
||||||
-- @return #OPSGROUP.Waypoint Modified waypoint data.
|
-- @return #OPSGROUP.Waypoint Modified waypoint data.
|
||||||
function OPSGROUP:_CreateWaypoint(waypoint)
|
function OPSGROUP:_CreateWaypoint(waypoint)
|
||||||
|
|
||||||
@@ -13610,20 +13613,24 @@ end
|
|||||||
-- @return Core.Point#COORDINATE The coordinate of the object.
|
-- @return Core.Point#COORDINATE The coordinate of the object.
|
||||||
function OPSGROUP:_CoordinateFromObject(Object)
|
function OPSGROUP:_CoordinateFromObject(Object)
|
||||||
|
|
||||||
|
env.info("FF coordfrom object")
|
||||||
if Object then
|
if Object then
|
||||||
if Object:IsInstanceOf("COORDINATE") then
|
if VECTOR._IsVector(Object) then
|
||||||
|
env.info("FF VECTOR")
|
||||||
|
return Object:GetCoordinate()
|
||||||
|
elseif Object:IsInstanceOf("COORDINATE") then
|
||||||
return Object
|
return Object
|
||||||
else
|
else
|
||||||
if Object:IsInstanceOf("POSITIONABLE") or Object:IsInstanceOf("ZONE_BASE") then
|
if Object:IsInstanceOf("POSITIONABLE") or Object:IsInstanceOf("ZONE_BASE") then
|
||||||
self:T(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate")
|
self:E(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate")
|
||||||
local coord=Object:GetCoordinate()
|
local coord=Object:GetCoordinate()
|
||||||
return coord
|
return coord
|
||||||
else
|
else
|
||||||
self:T(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!")
|
self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:T(self.lid.."ERROR: Object passed is nil!")
|
self:E(self.lid.."ERROR: Object passed is nil!")
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
-- @field #number threatlevelCapture Threat level necessary to capture a zone.
|
-- @field #number threatlevelCapture Threat level necessary to capture a zone.
|
||||||
-- @field Core.Set#SET_UNIT ScanUnitSet Set of scanned units.
|
-- @field Core.Set#SET_UNIT ScanUnitSet Set of scanned units.
|
||||||
-- @field Core.Set#SET_GROUP ScanGroupSet Set of scanned groups.
|
-- @field Core.Set#SET_GROUP ScanGroupSet Set of scanned groups.
|
||||||
-- @field #number UpdateSeconds Run status every this many seconds.
|
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Gentlemen, when the enemy is committed to a mistake we must not interrupt him too soon.* --- Horation Nelson
|
--- *Gentlemen, when the enemy is committed to a mistake we must not interrupt him too soon.* --- Horation Nelson
|
||||||
@@ -78,7 +77,6 @@ OPSZONE = {
|
|||||||
Tnut = 0,
|
Tnut = 0,
|
||||||
chiefs = {},
|
chiefs = {},
|
||||||
Missions = {},
|
Missions = {},
|
||||||
UpdateSeconds = 120,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- OPSZONE.MISSION
|
--- OPSZONE.MISSION
|
||||||
@@ -99,7 +97,7 @@ OPSZONE.ZoneType={
|
|||||||
|
|
||||||
--- OPSZONE class version.
|
--- OPSZONE class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
OPSZONE.version="0.6.2"
|
OPSZONE.version="0.6.1"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -735,8 +733,7 @@ function OPSZONE:onafterStart(From, Event, To)
|
|||||||
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self)
|
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self)
|
||||||
|
|
||||||
-- Status update.
|
-- Status update.
|
||||||
local EveryUpdateIn = self.UpdateSeconds or 120
|
self.timerStatus:Start(1, 120)
|
||||||
self.timerStatus:Start(1, EveryUpdateIn)
|
|
||||||
|
|
||||||
-- Handle base captured event.
|
-- Handle base captured event.
|
||||||
if self.airbase then
|
if self.airbase then
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
-- @module Ops.PlayerTask
|
-- @module Ops.PlayerTask
|
||||||
-- @image OPS_PlayerTask.jpg
|
-- @image OPS_PlayerTask.jpg
|
||||||
-- @date Last Update May 2025
|
-- @date Last Update Jan 2025
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -98,7 +98,7 @@ PLAYERTASK = {
|
|||||||
|
|
||||||
--- PLAYERTASK class version.
|
--- PLAYERTASK class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PLAYERTASK.version="0.1.27"
|
PLAYERTASK.version="0.1.25"
|
||||||
|
|
||||||
--- Generic task condition.
|
--- Generic task condition.
|
||||||
-- @type PLAYERTASK.Condition
|
-- @type PLAYERTASK.Condition
|
||||||
@@ -556,7 +556,6 @@ end
|
|||||||
-- @param #PLAYERTASK self
|
-- @param #PLAYERTASK self
|
||||||
-- @param #SET_BASE CaptureSquadGroupNamePrefix The prefix of the group name that needs to capture the zone.
|
-- @param #SET_BASE CaptureSquadGroupNamePrefix The prefix of the group name that needs to capture the zone.
|
||||||
-- @param #number Coalition The coalition that needs to capture the zone.
|
-- @param #number Coalition The coalition that needs to capture the zone.
|
||||||
-- @param #boolean CheckClientInZone If true, a CLIENT assigned to this task also needs to be in the zone for the task to be successful.
|
|
||||||
-- @return #PLAYERTASK self
|
-- @return #PLAYERTASK self
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- We can use either STATIC, SET_STATIC, SCENERY or SET_SCENERY as target objects.
|
-- -- We can use either STATIC, SET_STATIC, SCENERY or SET_SCENERY as target objects.
|
||||||
@@ -571,20 +570,20 @@ end
|
|||||||
--
|
--
|
||||||
-- -- We set CaptureSquadGroupNamePrefix the group name prefix as set in the ME or the spawn of the group that need to be present at the OpsZone like a capture squad,
|
-- -- We set CaptureSquadGroupNamePrefix the group name prefix as set in the ME or the spawn of the group that need to be present at the OpsZone like a capture squad,
|
||||||
-- -- and set the capturing Coalition in order to trigger a successful task.
|
-- -- and set the capturing Coalition in order to trigger a successful task.
|
||||||
-- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE, false)
|
-- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE)
|
||||||
--
|
--
|
||||||
-- playerTaskManager:AddPlayerTaskToQueue(mytask)
|
-- playerTaskManager:AddPlayerTaskToQueue(mytask)
|
||||||
function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone)
|
function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition)
|
||||||
local task = self
|
local task = self
|
||||||
task:AddConditionSuccess(
|
task:AddConditionSuccess(
|
||||||
function(target)
|
function(target)
|
||||||
if target:IsInstanceOf("OPSZONE") then
|
if target:IsInstanceOf("OPSZONE") then
|
||||||
return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true)
|
return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, true)
|
||||||
elseif target:IsInstanceOf("SET_OPSZONE") then
|
elseif target:IsInstanceOf("SET_OPSZONE") then
|
||||||
local successes = 0
|
local successes = 0
|
||||||
local isClientInZone = false
|
local isClientInZone = false
|
||||||
target:ForEachZone(function(opszone)
|
target:ForEachZone(function(opszone)
|
||||||
if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true) then
|
if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition) then
|
||||||
successes = successes + 1
|
successes = successes + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -980,12 +979,6 @@ function PLAYERTASK:onafterStatus(From, Event, To)
|
|||||||
|
|
||||||
if status == "Stopped" then return self end
|
if status == "Stopped" then return self end
|
||||||
|
|
||||||
-- update marker in case target is moving
|
|
||||||
if self.TargetMarker then
|
|
||||||
local coordinate = self.Target:GetCoordinate()
|
|
||||||
self.TargetMarker:UpdateCoordinate(coordinate,0.5)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check Target status
|
-- Check Target status
|
||||||
local targetdead = false
|
local targetdead = false
|
||||||
|
|
||||||
@@ -1909,7 +1902,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
|||||||
|
|
||||||
--- PLAYERTASK class version.
|
--- PLAYERTASK class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
PLAYERTASKCONTROLLER.version="0.1.70"
|
PLAYERTASKCONTROLLER.version="0.1.69"
|
||||||
|
|
||||||
--- Create and run a new TASKCONTROLLER instance.
|
--- Create and run a new TASKCONTROLLER instance.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
@@ -1951,7 +1944,7 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter)
|
|||||||
self.taskinfomenu = false
|
self.taskinfomenu = false
|
||||||
self.activehasinfomenu = false
|
self.activehasinfomenu = false
|
||||||
self.MenuName = nil
|
self.MenuName = nil
|
||||||
self.menuitemlimit = 6
|
self.menuitemlimit = 5
|
||||||
self.holdmenutime = 30
|
self.holdmenutime = 30
|
||||||
|
|
||||||
self.MarkerReadOnly = false
|
self.MarkerReadOnly = false
|
||||||
@@ -2422,7 +2415,7 @@ function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode,Holdi
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
self:E(self.lid.."No OPSGROUP/SET_OPSGROUP object passed or object is not alive!")
|
self:E(self.lid.."No FLIGHTGROUP object passed or FLIGHTGROUP is not alive!")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.autolase = nil
|
self.autolase = nil
|
||||||
@@ -2581,7 +2574,7 @@ function PLAYERTASKCONTROLLER:SetMenuOptions(InfoMenu,ItemLimit,HoldTime)
|
|||||||
if self.activehasinfomenu then
|
if self.activehasinfomenu then
|
||||||
self:EnableTaskInfoMenu()
|
self:EnableTaskInfoMenu()
|
||||||
end
|
end
|
||||||
self.menuitemlimit = ItemLimit+1 or 6
|
self.menuitemlimit = ItemLimit or 5
|
||||||
self.holdmenutime = HoldTime or 30
|
self.holdmenutime = HoldTime or 30
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -3486,7 +3479,7 @@ end
|
|||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
|
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
|
||||||
-- @param #boolean Silent If true, make no "has new task" announcement
|
-- @param #boolean Silent If true, make no "has new task" announcement
|
||||||
-- @param #boolean TaskFilter If true, apply the white/black-list task filters here, also
|
-- @param #boolen TaskFilter If true, apply the white/black-list task filters here, also
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
-- @usage
|
-- @usage
|
||||||
-- Example to create a PLAYERTASK of type CTLD and give Players 10 minutes to complete:
|
-- Example to create a PLAYERTASK of type CTLD and give Players 10 minutes to complete:
|
||||||
@@ -3710,7 +3703,6 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
else
|
else
|
||||||
CoordText = Coordinate:ToStringA2A(Client,nil,self.ShowMagnetic)
|
CoordText = Coordinate:ToStringA2A(Client,nil,self.ShowMagnetic)
|
||||||
end
|
end
|
||||||
--self:I("CoordText = "..CoordText)
|
|
||||||
-- Threat Level
|
-- Threat Level
|
||||||
local ThreatLevel = task.Target:GetThreatLevelMax()
|
local ThreatLevel = task.Target:GetThreatLevelMax()
|
||||||
--local ThreatLevelText = "high"
|
--local ThreatLevelText = "high"
|
||||||
@@ -3845,8 +3837,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
Text = string.gsub(Text,"9","niner")
|
Text = string.gsub(Text,"9","niner")
|
||||||
CoordText = "MGRS;"..Text
|
CoordText = "MGRS;"..Text
|
||||||
if self.PathToGoogleKey then
|
if self.PathToGoogleKey then
|
||||||
--CoordText = string.format("<say-as interpret-as=\'characters\'>%s</say-as>",CoordText)
|
CoordText = string.format("<say-as interpret-as='characters'>%s</say-as>",CoordText)
|
||||||
--doesn't seem to work any longer
|
|
||||||
end
|
end
|
||||||
--self:I(self.lid.." | ".. CoordText)
|
--self:I(self.lid.." | ".. CoordText)
|
||||||
end
|
end
|
||||||
@@ -3864,12 +3855,10 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
|||||||
CoordText = string.gsub(ttstext," BR, "," Bee, Arr, ")
|
CoordText = string.gsub(ttstext," BR, "," Bee, Arr, ")
|
||||||
end
|
end
|
||||||
elseif task:HasFreetext() then
|
elseif task:HasFreetext() then
|
||||||
|
|
||||||
-- add tts freetext
|
-- add tts freetext
|
||||||
local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale)
|
local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale)
|
||||||
ttstext = ttstext .. string.format("; %s: ",brieftxt)..task:GetFreetextTTS()
|
ttstext = ttstext .. string.format("; %s: ",brieftxt)..task:GetFreetextTTS()
|
||||||
end
|
end
|
||||||
--self:I("**** TTS Text ****\n"..ttstext.."\n*****")
|
|
||||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,2)
|
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,2)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -4368,7 +4357,7 @@ function PLAYERTASKCONTROLLER:SwitchDetectStatics(OnOff)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Add an accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
--- [User] Add accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set.
|
-- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
@@ -4382,7 +4371,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZone(AcceptZone)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Add an accept SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
--- [User] Add accept SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Core.Set#SET_ZONE AcceptZoneSet Add a SET_ZONE to the accept zone set.
|
-- @param Core.Set#SET_ZONE AcceptZoneSet Add a SET_ZONE to the accept zone set.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
@@ -4396,7 +4385,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZoneSet(AcceptZoneSet)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Add a reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
--- [User] Add reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set.
|
-- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
@@ -4410,7 +4399,7 @@ function PLAYERTASKCONTROLLER:AddRejectZone(RejectZone)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Add a reject SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
--- [User] Add reject SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Core.Set#SET_ZONE RejectZoneSet Add a zone to the reject zone set.
|
-- @param Core.Set#SET_ZONE RejectZoneSet Add a zone to the reject zone set.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
@@ -4424,37 +4413,9 @@ function PLAYERTASKCONTROLLER:AddRejectZoneSet(RejectZoneSet)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Add a conflict zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
--- [User] Remove accept zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Core.Zone#ZONE ConflictZone Add a zone to the conflict zone set.
|
-- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
|
||||||
function PLAYERTASKCONTROLLER:AddConflictZone(ConflictZone)
|
|
||||||
self:T(self.lid.."AddConflictZone")
|
|
||||||
if self.Intel then
|
|
||||||
self.Intel:AddConflictZone(ConflictZone)
|
|
||||||
else
|
|
||||||
self:E(self.lid.."*****NO detection has been set up (yet)!")
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- [User] Add a conflict SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
|
||||||
-- @param Core.Set#SET_ZONE ConflictZoneSet Add a zone to the conflict zone set.
|
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
|
||||||
function PLAYERTASKCONTROLLER:AddConflictZoneSet(ConflictZoneSet)
|
|
||||||
self:T(self.lid.."AddConflictZoneSet")
|
|
||||||
if self.Intel then
|
|
||||||
self.Intel.conflictzoneset:AddSet(ConflictZoneSet)
|
|
||||||
else
|
|
||||||
self:E(self.lid.."*****NO detection has been set up (yet)!")
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- [User] Remove an accept zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
|
||||||
-- @param Core.Zone#ZONE AcceptZone Remove this zone from the accept zone set.
|
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone)
|
function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone)
|
||||||
self:T(self.lid.."RemoveAcceptZone")
|
self:T(self.lid.."RemoveAcceptZone")
|
||||||
@@ -4466,11 +4427,11 @@ function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Remove a reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
--- [User] Remove reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param Core.Zone#ZONE RejectZone Remove this zone from the reject zone set.
|
-- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set.
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
-- @return #PLAYERTASKCONTROLLER self
|
||||||
function PLAYERTASKCONTROLLER:RemoveRejectZone(RejectZone)
|
function PLAYERTASKCONTROLLER:RemoveRejectZoneSet(RejectZone)
|
||||||
self:T(self.lid.."RemoveRejectZone")
|
self:T(self.lid.."RemoveRejectZone")
|
||||||
if self.Intel then
|
if self.Intel then
|
||||||
self.Intel:RemoveRejectZone(RejectZone)
|
self.Intel:RemoveRejectZone(RejectZone)
|
||||||
@@ -4480,20 +4441,6 @@ function PLAYERTASKCONTROLLER:RemoveRejectZone(RejectZone)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- [User] Remove a conflict zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
|
||||||
-- @param Core.Zone#ZONE ConflictZone Remove this zone from the conflict zone set.
|
|
||||||
-- @return #PLAYERTASKCONTROLLER self
|
|
||||||
function PLAYERTASKCONTROLLER:RemoveConflictZone(ConflictZone)
|
|
||||||
self:T(self.lid.."RemoveConflictZone")
|
|
||||||
if self.Intel then
|
|
||||||
self.Intel:RemoveConflictZone(ConflictZone)
|
|
||||||
else
|
|
||||||
self:E(self.lid.."*****NO detection has been set up (yet)!")
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--- [User] Set the top menu name to a custom string.
|
--- [User] Set the top menu name to a custom string.
|
||||||
-- @param #PLAYERTASKCONTROLLER self
|
-- @param #PLAYERTASKCONTROLLER self
|
||||||
-- @param #string Name The name to use as the top menu designation.
|
-- @param #string Name The name to use as the top menu designation.
|
||||||
|
|||||||
@@ -1715,26 +1715,6 @@ function TARGET:GetAverageCoordinate()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get coordinates of all targets. (e.g. for a SET_STATIC)
|
|
||||||
-- @param #TARGET self
|
|
||||||
-- @return #table Table with coordinates of all targets.
|
|
||||||
function TARGET:GetCoordinates()
|
|
||||||
local coordinates={}
|
|
||||||
|
|
||||||
for _,_target in pairs(self.targets) do
|
|
||||||
local target=_target --#TARGET.Object
|
|
||||||
|
|
||||||
local coordinate=self:GetTargetCoordinate(target)
|
|
||||||
if coordinate then
|
|
||||||
table.insert(coordinates, coordinate)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return coordinates
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get heading of target.
|
--- Get heading of target.
|
||||||
-- @param #TARGET self
|
-- @param #TARGET self
|
||||||
-- @return #number Heading of the target in degrees.
|
-- @return #number Heading of the target in degrees.
|
||||||
@@ -1988,21 +1968,6 @@ function TARGET:GetObject(RefCoordinate, Coalitions)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get all target objects.
|
|
||||||
-- @param #TARGET self
|
|
||||||
-- @return #table List of target objects.
|
|
||||||
function TARGET:GetObjects()
|
|
||||||
local objects={}
|
|
||||||
|
|
||||||
for _,_target in pairs(self.targets) do
|
|
||||||
local target=_target --#TARGET.Object
|
|
||||||
|
|
||||||
table.insert(objects, target.Object)
|
|
||||||
end
|
|
||||||
|
|
||||||
return objects
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Count alive objects.
|
--- Count alive objects.
|
||||||
-- @param #TARGET self
|
-- @param #TARGET self
|
||||||
-- @param #TARGET.Object Target Target objective.
|
-- @param #TARGET.Object Target Target objective.
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ MSRS.Voices = {
|
|||||||
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||||
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
["en_GB_Wavenet_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE
|
["en_US_Wavenet_A"] = 'en-US-Wavenet-N', -- [14] MALE
|
||||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
||||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
||||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
|
|
||||||
--- Governs multiple missions, the tasking and the reporting.
|
--- Governs multiple missions, the tasking and the reporting.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Command centers govern missions, communicates the task assignments between human players of the coalition, and manages the menu flow.
|
-- Command centers govern missions, communicates the task assignments between human players of the coalition, and manages the menu flow.
|
||||||
-- It can assign a random task to a player when requested.
|
-- It can assign a random task to a player when requested.
|
||||||
-- The commandcenter provides the facilitites to communicate between human players online, executing a task.
|
-- The commandcenter provides the facilitites to communicate between human players online, executing a task.
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
-- The @{#DETECTION_MANAGER} class defines the core functions to report detected objects to groups.
|
-- The @{#DETECTION_MANAGER} class defines the core functions to report detected objects to groups.
|
||||||
-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour.
|
-- Reportings can be done in several manners, and it is up to the derived classes if DETECTION_MANAGER to model the reporting behaviour.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 1.1) DETECTION_MANAGER constructor:
|
-- 1.1) DETECTION_MANAGER constructor:
|
||||||
-- -----------------------------------
|
-- -----------------------------------
|
||||||
-- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
|
-- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
|
||||||
|
|||||||
@@ -28,8 +28,6 @@
|
|||||||
|
|
||||||
--- Models goals to be achieved and can contain multiple tasks to be executed to achieve the goals.
|
--- Models goals to be achieved and can contain multiple tasks to be executed to achieve the goals.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- A mission contains multiple tasks and can be of different task types.
|
-- A mission contains multiple tasks and can be of different task types.
|
||||||
-- These tasks need to be assigned to human players to be executed.
|
-- These tasks need to be assigned to human players to be executed.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # 1) Tasking from a player perspective.
|
-- # 1) Tasking from a player perspective.
|
||||||
--
|
--
|
||||||
-- Tasking can be controlled by using the "other" menu in the radio menu of the player group.
|
-- Tasking can be controlled by using the "other" menu in the radio menu of the player group.
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
---
|
---
|
||||||
-- # TASKINFO class, extends @{Core.Base#BASE}
|
-- # TASKINFO class, extends @{Core.Base#BASE}
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ## The TASKINFO class implements the methods to contain information and display information of a task.
|
-- ## The TASKINFO class implements the methods to contain information and display information of a task.
|
||||||
--
|
--
|
||||||
-- # Developer Note
|
-- # Developer Note
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ do -- TASK_A2A
|
|||||||
|
|
||||||
--- Defines Air To Air tasks for a @{Core.Set} of Target Units,
|
--- Defines Air To Air tasks for a @{Core.Set} of Target Units,
|
||||||
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
|
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
|
||||||
--
|
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The TASK_A2A is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
-- The TASK_A2A is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||||
--
|
--
|
||||||
-- * **None**: Start of the process
|
-- * **None**: Start of the process
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ do -- TASK_A2A_DISPATCHER
|
|||||||
|
|
||||||
--- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Core.Set} of EWR installation groups.
|
--- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Core.Set} of EWR installation groups.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The EWR will detect units, will group them, and will dispatch @{Tasking.Task}s to groups. Depending on the type of target detected, different tasks will be dispatched.
|
-- The EWR will detect units, will group them, and will dispatch @{Tasking.Task}s to groups. Depending on the type of target detected, different tasks will be dispatched.
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ do -- TASK_A2G
|
|||||||
|
|
||||||
--- The TASK_A2G class defines Air To Ground tasks for a @{Core.Set} of Target Units,
|
--- The TASK_A2G class defines Air To Ground tasks for a @{Core.Set} of Target Units,
|
||||||
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
|
-- based on the tasking capabilities defined in @{Tasking.Task#TASK}.
|
||||||
--
|
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
-- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||||
--
|
--
|
||||||
-- * **None**: Start of the process
|
-- * **None**: Start of the process
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ do -- TASK_A2G_DISPATCHER
|
|||||||
|
|
||||||
--- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Functional.Detection} object.
|
--- Orchestrates dynamic **A2G Task Dispatching** based on the detection results of a linked @{Functional.Detection} object.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- It uses the Tasking System within the MOOSE framework, which is a multi-player Tasking Orchestration system.
|
-- It uses the Tasking System within the MOOSE framework, which is a multi-player Tasking Orchestration system.
|
||||||
-- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon,
|
-- It provides a truly dynamic battle environment for pilots and ground commanders to engage upon,
|
||||||
-- in a true co-operation environment wherein **Multiple Teams** will collaborate in Missions to **achieve a common Mission Goal**.
|
-- in a true co-operation environment wherein **Multiple Teams** will collaborate in Missions to **achieve a common Mission Goal**.
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- ## Test Missions:
|
-- ## Test Missions:
|
||||||
--
|
--
|
||||||
-- Test missions can be located on the main GITHUB site.
|
-- Test missions can be located on the main GITHUB site.
|
||||||
@@ -1178,7 +1176,7 @@ do -- TASK_CARGO
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green
|
---@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green
|
||||||
function TASK_CARGO:SetSmokeColor(SmokeColor)
|
function TASK_CARGO:SetSmokeColor(SmokeColor)
|
||||||
-- Makes sure Coloe is set
|
-- Makes sure Coloe is set
|
||||||
if SmokeColor == nil then
|
if SmokeColor == nil then
|
||||||
|
|||||||
@@ -76,8 +76,6 @@ do -- TASK_CAPTURE_DISPATCHER
|
|||||||
|
|
||||||
--- Implements the dynamic dispatching of capture zone tasks.
|
--- Implements the dynamic dispatching of capture zone tasks.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The **TASK_CAPTURE_DISPATCHER** allows you to setup various tasks for let human
|
-- The **TASK_CAPTURE_DISPATCHER** allows you to setup various tasks for let human
|
||||||
-- players capture zones in a co-operation effort.
|
-- players capture zones in a co-operation effort.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ do -- TASK_ZONE_GOAL
|
|||||||
|
|
||||||
--- # TASK_ZONE_GOAL class, extends @{Tasking.Task#TASK}
|
--- # TASK_ZONE_GOAL class, extends @{Tasking.Task#TASK}
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone.
|
-- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone.
|
||||||
-- The TASK_ZONE_GOAL is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
-- The TASK_ZONE_GOAL is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -44,8 +44,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- Please read through the @{Tasking.Task_CARGO} process to understand the mechanisms of tasking and cargo tasking and handling.
|
-- Please read through the @{Tasking.Task_CARGO} process to understand the mechanisms of tasking and cargo tasking and handling.
|
||||||
--
|
--
|
||||||
-- The cargo will be a downed pilot, which is located somwhere on the battlefield. Use the menus system and facilities to
|
-- The cargo will be a downed pilot, which is located somwhere on the battlefield. Use the menus system and facilities to
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
-- The **TASK_CARGO_DISPATCHER** allows you to setup various tasks for let human
|
-- The **TASK_CARGO_DISPATCHER** allows you to setup various tasks for let human
|
||||||
-- players transport cargo as part of a task.
|
-- players transport cargo as part of a task.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- The cargo dispatcher will implement for you mechanisms to create cargo transportation tasks:
|
-- The cargo dispatcher will implement for you mechanisms to create cargo transportation tasks:
|
||||||
--
|
--
|
||||||
-- * As setup by the mission designer.
|
-- * As setup by the mission designer.
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
--- **Tasking** - Models tasks for players to transport cargo.
|
--- **Tasking** - Models tasks for players to transport cargo.
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- **Specific features:**
|
-- **Specific features:**
|
||||||
--
|
--
|
||||||
-- * Creates a task to transport #Cargo.Cargo to and between deployment zones.
|
-- * Creates a task to transport #Cargo.Cargo to and between deployment zones.
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- 1) @{Tasking.Task_Manager#TASK_MANAGER} class, extends @{Core.Fsm#FSM}
|
-- 1) @{Tasking.Task_Manager#TASK_MANAGER} class, extends @{Core.Fsm#FSM}
|
||||||
-- ===
|
-- ===
|
||||||
-- The @{Tasking.Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups.
|
-- The @{Tasking.Task_Manager#TASK_MANAGER} class defines the core functions to report tasks to groups.
|
||||||
|
|||||||
@@ -1365,28 +1365,3 @@ ENUMS.FARPObjectTypeNamesAndShape ={
|
|||||||
[ENUMS.FARPType.PADSINGLE] = { TypeName="FARP_SINGLE_01", ShapeName="FARP_SINGLE_01"},
|
[ENUMS.FARPType.PADSINGLE] = { TypeName="FARP_SINGLE_01", ShapeName="FARP_SINGLE_01"},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Radio frequency bands (HF, VHF, UHF)
|
|
||||||
-- @type ENUMS.FrequencyBand
|
|
||||||
-- @field #number HF High frequency
|
|
||||||
-- @field #number VHF_LOW Very high frequency
|
|
||||||
-- @field #number VHF_HI Very high frequency
|
|
||||||
-- @field #number UHF Ultra high frequency
|
|
||||||
ENUMS.FrequencyBand = {
|
|
||||||
HF = 0,
|
|
||||||
VHF_LOW = 1,
|
|
||||||
VHF_HI = 2,
|
|
||||||
UHF = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Radio modulation types (AM, FM)
|
|
||||||
-- @type ENUMS.ModulationType
|
|
||||||
-- @field #number AM Amplitude modulation
|
|
||||||
-- @field #number FM Frequency modulation
|
|
||||||
-- @field #number AMFM Amplitude and frequency modulation
|
|
||||||
-- @field #number DISCARD Discard modulation
|
|
||||||
ENUMS.ModulationType = {
|
|
||||||
AM = 0,
|
|
||||||
FM = 1,
|
|
||||||
AMFM = 2,
|
|
||||||
DISCARD = -1,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,35 +12,27 @@
|
|||||||
-- @module Utilities.Utils
|
-- @module Utilities.Utils
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
--- Smoke color enum `trigger.smokeColor`.
|
---
|
||||||
-- @type SMOKECOLOR
|
-- @type SMOKECOLOR
|
||||||
-- @field #number Green Green smoke (0)
|
-- @field Green
|
||||||
-- @field #number Red Red smoke (1)
|
-- @field Red
|
||||||
-- @field #number White White smoke (2)
|
-- @field White
|
||||||
-- @field #number Orange Orange smoke (3)
|
-- @field Orange
|
||||||
-- @field #number Blue Blue smoke (4)
|
-- @field Blue
|
||||||
|
|
||||||
SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR
|
SMOKECOLOR = trigger.smokeColor -- #SMOKECOLOR
|
||||||
|
|
||||||
--- Flare colur enum `trigger.flareColor`.
|
---
|
||||||
-- @type FLARECOLOR
|
-- @type FLARECOLOR
|
||||||
-- @field #number Green (0)
|
-- @field Green
|
||||||
-- @field #number Red Red flare (1)
|
-- @field Red
|
||||||
-- @field #number White White flare (2)
|
-- @field White
|
||||||
-- @field #number Yellow Yellow flare (3)
|
-- @field Yellow
|
||||||
|
|
||||||
FLARECOLOR = trigger.flareColor -- #FLARECOLOR
|
FLARECOLOR = trigger.flareColor -- #FLARECOLOR
|
||||||
|
|
||||||
--- Big smoke preset enum.
|
--- Big smoke preset enum.
|
||||||
-- @type BIGSMOKEPRESET
|
-- @type BIGSMOKEPRESET
|
||||||
-- @field #number SmallSmokeAndFire Small moke and fire (1)
|
|
||||||
-- @field #number MediumSmokeAndFire Medium smoke and fire (2)
|
|
||||||
-- @field #number LargeSmokeAndFire Large smoke and fire (3)
|
|
||||||
-- @field #number HugeSmokeAndFire Huge smoke and fire (4)
|
|
||||||
-- @field #number SmallSmoke Small smoke (5)
|
|
||||||
-- @field #number MediumSmoke Medium smoke (6)
|
|
||||||
-- @field #number LargeSmoke Large smoke (7)
|
|
||||||
-- @field #number HugeSmoke Huge smoke (8)
|
|
||||||
BIGSMOKEPRESET = {
|
BIGSMOKEPRESET = {
|
||||||
SmallSmokeAndFire=1,
|
SmallSmokeAndFire=1,
|
||||||
MediumSmokeAndFire=2,
|
MediumSmokeAndFire=2,
|
||||||
@@ -498,7 +490,7 @@ end
|
|||||||
|
|
||||||
--- Counts the number of elements in a table.
|
--- Counts the number of elements in a table.
|
||||||
-- @param #table T Table to count
|
-- @param #table T Table to count
|
||||||
-- @return #number Number of elements in the table
|
-- @return #int Number of elements in the table
|
||||||
function UTILS.TableLength(T)
|
function UTILS.TableLength(T)
|
||||||
local count = 0
|
local count = 0
|
||||||
for _ in pairs(T or {}) do count = count + 1 end
|
for _ in pairs(T or {}) do count = count + 1 end
|
||||||
@@ -805,6 +797,33 @@ UTILS.kg2lbs = function( kg )
|
|||||||
return kg * 2.20462
|
return kg * 2.20462
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Convert latitude or longitude from degrees, minutes, seconds (DMS) to decimal degrees (DD).
|
||||||
|
-- @param #number Degrees Degrees in grad.
|
||||||
|
-- @param #number Minutes Minutes.
|
||||||
|
-- @param #number Seconds Seconds.
|
||||||
|
-- @return #number Latitude or Longitude in decimal degrees.
|
||||||
|
UTILS.LLDMSToDD = function(Degrees, Minutes, Seconds)
|
||||||
|
|
||||||
|
local dd=tonumber(Degrees or 0) + tonumber(Minutes or 0)/60 + tonumber(Seconds or 0)/3600
|
||||||
|
|
||||||
|
return dd
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Convert latitude or longitude from degrees, minutes, seconds (DMS) given in text form to decimal degrees (DD).
|
||||||
|
-- @param #string LatOrLongString Latitude or longitude passed as ttring in format `DD°MM'SS.SS"`.
|
||||||
|
-- @return #number Latitude or Longitude in decimal degrees.
|
||||||
|
UTILS.LLDMSstringToDD = function(LatOrLongString)
|
||||||
|
|
||||||
|
local hem=string.match(LatOrLongString, "(%a)")
|
||||||
|
local Degrees=string.match(LatOrLongString, "(%d+)°")
|
||||||
|
local Minutes=string.match(LatOrLongString, "(%d+)'")
|
||||||
|
local Seconds=string.match(LatOrLongString, "([%d\.]+)\"")
|
||||||
|
|
||||||
|
local dd=UTILS.LLDMSToDD(Degrees, Minutes, Seconds)
|
||||||
|
|
||||||
|
return dd
|
||||||
|
end
|
||||||
|
|
||||||
--[[acc:
|
--[[acc:
|
||||||
in DM: decimal point of minutes.
|
in DM: decimal point of minutes.
|
||||||
In DMS: decimal point of seconds.
|
In DMS: decimal point of seconds.
|
||||||
@@ -1525,6 +1544,22 @@ function UTILS.Vec2Add(a, b)
|
|||||||
return {x=a.x+b.x, y=a.y+b.y}
|
return {x=a.x+b.x, y=a.y+b.y}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Multiply 2D vector by a scalar value.
|
||||||
|
-- @param DCS#Vec2 a Vector in 2D with x, y components.
|
||||||
|
-- @param #number c Scalar value.
|
||||||
|
-- @return DCS#Vec2 Vector
|
||||||
|
function UTILS.Vec2Mult(a, c)
|
||||||
|
return {x=c*a.x, y=c*a.y}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Multiply 3D vector by a scalar value.
|
||||||
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
|
-- @param #number c Scalar value.
|
||||||
|
-- @return DCS#Vec3 Vector
|
||||||
|
function UTILS.VecMult(a, c)
|
||||||
|
return {x=c*a.x, y=c*a.y, z=c*a.z}
|
||||||
|
end
|
||||||
|
|
||||||
--- Calculate the angle between two 3D vectors.
|
--- Calculate the angle between two 3D vectors.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
@@ -1545,6 +1580,24 @@ function UTILS.VecAngle(a, b)
|
|||||||
return math.deg(alpha)
|
return math.deg(alpha)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Calculate the angle between two 3D vectors.
|
||||||
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
|
-- @return #number Angle alpha between and b in degrees.
|
||||||
|
function UTILS.VecAngleSigned(a, b)
|
||||||
|
|
||||||
|
local a=UTILS.VecSubstract(s1.p2.vec3, s1.p1.vec3)
|
||||||
|
|
||||||
|
local b=UTILS.VecSubstract(s2.p2.vec3, s2.p1.vec3)
|
||||||
|
|
||||||
|
local h1=UTILS.VecHdg(a)
|
||||||
|
local h2=UTILS.VecHdg(b)
|
||||||
|
|
||||||
|
local angle=h1-h2 --UTILS.VecAngle(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Calculate "heading" of a 3D vector in the X-Z plane.
|
--- Calculate "heading" of a 3D vector in the X-Z plane.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @return #number Heading in degrees in [0,360).
|
-- @return #number Heading in degrees in [0,360).
|
||||||
@@ -1567,6 +1620,20 @@ function UTILS.Vec2Hdg(a)
|
|||||||
return h
|
return h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Calculate the difference between two "heading", i.e. angles in [0,360) deg.
|
||||||
|
-- @param DCS#Vec3 a Vector a.
|
||||||
|
-- @param DCS#Vec3 a Vector b.
|
||||||
|
-- @return #number Heading difference in degrees.
|
||||||
|
function UTILS.VecHdgDiff(a, b)
|
||||||
|
|
||||||
|
local ha=math.deg(math.atan2(a.z, a.x))
|
||||||
|
local hb=math.deg(math.atan2(b.z, b.x))
|
||||||
|
|
||||||
|
local angle=ha-hb
|
||||||
|
|
||||||
|
return angle
|
||||||
|
end
|
||||||
|
|
||||||
--- Calculate the difference between two "heading", i.e. angles in [0,360) deg.
|
--- Calculate the difference between two "heading", i.e. angles in [0,360) deg.
|
||||||
-- @param #number h1 Heading one.
|
-- @param #number h1 Heading one.
|
||||||
-- @param #number h2 Heading two.
|
-- @param #number h2 Heading two.
|
||||||
@@ -1914,13 +1981,6 @@ function UTILS.GetReportingName(Typename)
|
|||||||
|
|
||||||
local typename = string.lower(Typename)
|
local typename = string.lower(Typename)
|
||||||
|
|
||||||
-- special cases - Shark and Manstay have "A-50" in the name
|
|
||||||
if string.find(typename,"ka-50",1,true) then
|
|
||||||
return "Shark"
|
|
||||||
elseif string.find(typename,"a-50",1,true) then
|
|
||||||
return "Mainstay"
|
|
||||||
end
|
|
||||||
|
|
||||||
for name, value in pairs(ENUMS.ReportingName.NATO) do
|
for name, value in pairs(ENUMS.ReportingName.NATO) do
|
||||||
local svalue = string.lower(value)
|
local svalue = string.lower(value)
|
||||||
if string.find(typename,svalue,1,true) then
|
if string.find(typename,svalue,1,true) then
|
||||||
@@ -2152,9 +2212,9 @@ function UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, Rising, Tlocal)
|
|||||||
local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude))
|
local cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude))
|
||||||
|
|
||||||
if rising and cosH > 1 then
|
if rising and cosH > 1 then
|
||||||
return "N/R" -- The sun never rises on this location on the specified date
|
return "N/S" -- The sun never rises on this location on the specified date
|
||||||
elseif cosH < -1 then
|
elseif cosH < -1 then
|
||||||
return "N/S" -- The sun never sets on this location on the specified date
|
return "N/R" -- The sun never sets on this location on the specified date
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Finish calculating H and convert into hours
|
-- Finish calculating H and convert into hours
|
||||||
@@ -3217,6 +3277,62 @@ function UTILS.BearingToCardinal(Heading)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Adjust given heading so that is is in [0, 360).
|
||||||
|
-- @param #number Heading The heading in degrees.
|
||||||
|
-- @return #number Adjust heading in [0,360).
|
||||||
|
function UTILS.AdjustHeading360(Heading)
|
||||||
|
|
||||||
|
if Heading>=360 then
|
||||||
|
Heading=Heading-360
|
||||||
|
elseif Heading<0 then
|
||||||
|
Heading=Heading+360
|
||||||
|
end
|
||||||
|
|
||||||
|
return Heading
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Transfroms a given 2D vector 3D.
|
||||||
|
-- This takes care of ED's different conventions for 2D and 3D coordinate systems.
|
||||||
|
-- @param DCS#Vec2 Vec Vector to be transformed. Can be any table/object that has at least x and y and optionally a z component.
|
||||||
|
-- @param #boolean OnSurface If `true`, new vector's y-component (alt) is at surface height. Otherwise, it is set to 0.
|
||||||
|
-- @return DCS#Vec3 Vector in 3D with x-, y- and z-components.
|
||||||
|
function UTILS.VecTo3D(Vec, OnSurface)
|
||||||
|
|
||||||
|
local vec={x=0, y=0, z=0} --DCS#Vec3
|
||||||
|
if Vec.z then
|
||||||
|
-- Vector is 3D already ==> Nothing to do.
|
||||||
|
vec.x=Vec.x
|
||||||
|
vec.y=Vec.y
|
||||||
|
vec.z=Vec.z
|
||||||
|
else
|
||||||
|
-- Vector is 2D
|
||||||
|
vec.x=Vec.x
|
||||||
|
vec.y=OnSurface and land.getHeight({x=Vec.x, y=Vec.y}) or 0
|
||||||
|
vec.z=Vec.y
|
||||||
|
end
|
||||||
|
|
||||||
|
return vec
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Transfroms a given 3D (or 2D) vector to 2D.
|
||||||
|
-- This takes care of ED's different conventions for 2D and 3D coordinate systems.
|
||||||
|
-- @param DCS#Vec3 Vec Vector to be transformed. Can be any table/object that has at least x and y and optionally a z component.
|
||||||
|
-- @return DCS#Vec2 Vector in 2D with x- and y-components.
|
||||||
|
function UTILS.VecTo2D(Vec)
|
||||||
|
|
||||||
|
local vec={x=0, y=0} --DCS#Vec2
|
||||||
|
|
||||||
|
if Vec.z then
|
||||||
|
vec.x=Vec.x
|
||||||
|
vec.y=Vec.z
|
||||||
|
else
|
||||||
|
vec.x=Vec.x
|
||||||
|
vec.y=Vec.y
|
||||||
|
end
|
||||||
|
|
||||||
|
return vec
|
||||||
|
end
|
||||||
|
|
||||||
--- Create a BRAA NATO call string BRAA between two GROUP objects
|
--- Create a BRAA NATO call string BRAA between two GROUP objects
|
||||||
-- @param Wrapper.Group#GROUP FromGrp GROUP object
|
-- @param Wrapper.Group#GROUP FromGrp GROUP object
|
||||||
-- @param Wrapper.Group#GROUP ToGrp GROUP object
|
-- @param Wrapper.Group#GROUP ToGrp GROUP object
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
-- @field #AIRBASE.Runway runwayLanding Runway used for landing.
|
-- @field #AIRBASE.Runway runwayLanding Runway used for landing.
|
||||||
-- @field #AIRBASE.Runway runwayTakeoff Runway used for takeoff.
|
-- @field #AIRBASE.Runway runwayTakeoff Runway used for takeoff.
|
||||||
-- @field Wrapper.Storage#STORAGE storage The DCS warehouse storage.
|
-- @field Wrapper.Storage#STORAGE storage The DCS warehouse storage.
|
||||||
|
-- @field #table taxiways Taxiways stored as PATHLINEs.
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
--- Wrapper class to handle the DCS Airbase objects:
|
--- Wrapper class to handle the DCS Airbase objects:
|
||||||
@@ -78,6 +79,7 @@ AIRBASE = {
|
|||||||
[Airbase.Category.SHIP] = "Ship",
|
[Airbase.Category.SHIP] = "Ship",
|
||||||
},
|
},
|
||||||
activerwyno = nil,
|
activerwyno = nil,
|
||||||
|
taxiways = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Enumeration to identify the airbases in the Caucasus region.
|
--- Enumeration to identify the airbases in the Caucasus region.
|
||||||
@@ -449,6 +451,7 @@ AIRBASE.TheChannel = {
|
|||||||
-- * AIRBASE.Syria.Al_Dumayr
|
-- * AIRBASE.Syria.Al_Dumayr
|
||||||
-- * AIRBASE.Syria.Al_Qusayr
|
-- * AIRBASE.Syria.Al_Qusayr
|
||||||
-- * AIRBASE.Syria.Aleppo
|
-- * AIRBASE.Syria.Aleppo
|
||||||
|
-- * AIRBASE.Syria.Amman
|
||||||
-- * AIRBASE.Syria.An_Nasiriyah
|
-- * AIRBASE.Syria.An_Nasiriyah
|
||||||
-- * AIRBASE.Syria.At_Tanf
|
-- * AIRBASE.Syria.At_Tanf
|
||||||
-- * AIRBASE.Syria.Bassel_Al_Assad
|
-- * AIRBASE.Syria.Bassel_Al_Assad
|
||||||
@@ -510,9 +513,8 @@ AIRBASE.TheChannel = {
|
|||||||
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
||||||
-- * AIRBASE.Syria.Ben_Gurion
|
-- * AIRBASE.Syria.Ben_Gurion
|
||||||
-- * AIRBASE.Syria.Hatzor
|
-- * AIRBASE.Syria.Hatzor
|
||||||
-- * AIRBASE.Syria.Palmachim
|
-- * AIRBASE.Syria.Palmashim
|
||||||
-- * AIRBASE.Syria.Tel_Nof
|
-- * AIRBASE.Syria.Tel_Nof
|
||||||
-- * AIRBASE.Syria.Marka
|
|
||||||
--
|
--
|
||||||
--@field Syria
|
--@field Syria
|
||||||
AIRBASE.Syria={
|
AIRBASE.Syria={
|
||||||
@@ -522,6 +524,7 @@ AIRBASE.Syria={
|
|||||||
["Al_Dumayr"] = "Al-Dumayr",
|
["Al_Dumayr"] = "Al-Dumayr",
|
||||||
["Al_Qusayr"] = "Al Qusayr",
|
["Al_Qusayr"] = "Al Qusayr",
|
||||||
["Aleppo"] = "Aleppo",
|
["Aleppo"] = "Aleppo",
|
||||||
|
["Amman"] = "Amman",
|
||||||
["An_Nasiriyah"] = "An Nasiriyah",
|
["An_Nasiriyah"] = "An Nasiriyah",
|
||||||
["At_Tanf"] = "At Tanf",
|
["At_Tanf"] = "At Tanf",
|
||||||
["Bassel_Al_Assad"] = "Bassel Al-Assad",
|
["Bassel_Al_Assad"] = "Bassel Al-Assad",
|
||||||
@@ -553,7 +556,6 @@ AIRBASE.Syria={
|
|||||||
["Kuweires"] = "Kuweires",
|
["Kuweires"] = "Kuweires",
|
||||||
["Lakatamia"] = "Lakatamia",
|
["Lakatamia"] = "Lakatamia",
|
||||||
["Larnaca"] = "Larnaca",
|
["Larnaca"] = "Larnaca",
|
||||||
["Marka"] = "Marka",
|
|
||||||
["Marj_Ruhayyil"] = "Marj Ruhayyil",
|
["Marj_Ruhayyil"] = "Marj Ruhayyil",
|
||||||
["Marj_as_Sultan_North"] = "Marj as Sultan North",
|
["Marj_as_Sultan_North"] = "Marj as Sultan North",
|
||||||
["Marj_as_Sultan_South"] = "Marj as Sultan South",
|
["Marj_as_Sultan_South"] = "Marj as Sultan South",
|
||||||
@@ -584,7 +586,7 @@ AIRBASE.Syria={
|
|||||||
["Wujah_Al_Hajar"] = "Wujah Al Hajar",
|
["Wujah_Al_Hajar"] = "Wujah Al Hajar",
|
||||||
["Ben_Gurion"] = "Ben Gurion",
|
["Ben_Gurion"] = "Ben Gurion",
|
||||||
["Hatzor"] = "Hatzor",
|
["Hatzor"] = "Hatzor",
|
||||||
["Palmachim"] = "Palmachim",
|
["Palmashim"] = "Palmashim",
|
||||||
["Tel_Nof"] = "Tel Nof",
|
["Tel_Nof"] = "Tel Nof",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,7 +691,7 @@ AIRBASE.SouthAtlantic={
|
|||||||
-- * AIRBASE.Sinai.Bilbeis_Air_Base
|
-- * AIRBASE.Sinai.Bilbeis_Air_Base
|
||||||
-- * AIRBASE.Sinai.Bir_Hasanah
|
-- * AIRBASE.Sinai.Bir_Hasanah
|
||||||
-- * AIRBASE.Sinai.Birma_Air_Base
|
-- * AIRBASE.Sinai.Birma_Air_Base
|
||||||
-- * AIRBASE.Sinai.Borg_El_Arab_International_Airport
|
-- * AIRBASE.Sinai.Borj_El_Arab_International_Airport
|
||||||
-- * AIRBASE.Sinai.Cairo_International_Airport
|
-- * AIRBASE.Sinai.Cairo_International_Airport
|
||||||
-- * AIRBASE.Sinai.Cairo_West
|
-- * AIRBASE.Sinai.Cairo_West
|
||||||
-- * AIRBASE.Sinai.Difarsuwar_Airfield
|
-- * AIRBASE.Sinai.Difarsuwar_Airfield
|
||||||
@@ -737,7 +739,7 @@ AIRBASE.Sinai = {
|
|||||||
["Bilbeis_Air_Base"] = "Bilbeis Air Base",
|
["Bilbeis_Air_Base"] = "Bilbeis Air Base",
|
||||||
["Bir_Hasanah"] = "Bir Hasanah",
|
["Bir_Hasanah"] = "Bir Hasanah",
|
||||||
["Birma_Air_Base"] = "Birma Air Base",
|
["Birma_Air_Base"] = "Birma Air Base",
|
||||||
["Borg_El_Arab_International_Airport"] = "Borg El Arab International Airport",
|
["Borj_El_Arab_International_Airport"] = "Borj El Arab International Airport",
|
||||||
["Cairo_International_Airport"] = "Cairo International Airport",
|
["Cairo_International_Airport"] = "Cairo International Airport",
|
||||||
["Cairo_West"] = "Cairo West",
|
["Cairo_West"] = "Cairo West",
|
||||||
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
|
["Difarsuwar_Airfield"] = "Difarsuwar Airfield",
|
||||||
@@ -790,14 +792,9 @@ AIRBASE.Sinai = {
|
|||||||
-- * AIRBASE.Kola.Vidsel
|
-- * AIRBASE.Kola.Vidsel
|
||||||
-- * AIRBASE.Kola.Vuojarvi
|
-- * AIRBASE.Kola.Vuojarvi
|
||||||
-- * AIRBASE.Kola.Andoya
|
-- * AIRBASE.Kola.Andoya
|
||||||
-- * AIRBASE.Kola.Alakurtti
|
-- * AIRBASE.Kola.Alakourtti
|
||||||
-- * AIRBASE.Kola.Kittila
|
-- * AIRBASE.Kola.Kittila
|
||||||
-- * AIRBASE.Kola.Bardufoss
|
-- * AIRBASE.Kola.Bardufoss
|
||||||
-- * AIRBASE.Kola.Alta
|
|
||||||
-- * AIRBASE.Kola.Sodankyla
|
|
||||||
-- * AIRBASE.Kola.Enontekio
|
|
||||||
-- * AIRBASE.Kola.Evenes
|
|
||||||
-- * AIRBASE.Kola.Hosio
|
|
||||||
--
|
--
|
||||||
-- @field Kola
|
-- @field Kola
|
||||||
AIRBASE.Kola = {
|
AIRBASE.Kola = {
|
||||||
@@ -820,20 +817,9 @@ AIRBASE.Kola = {
|
|||||||
["Vidsel"] = "Vidsel",
|
["Vidsel"] = "Vidsel",
|
||||||
["Vuojarvi"] = "Vuojarvi",
|
["Vuojarvi"] = "Vuojarvi",
|
||||||
["Andoya"] = "Andoya",
|
["Andoya"] = "Andoya",
|
||||||
["Alakurtti"] = "Alakurtti",
|
["Alakourtti"] = "Alakourtti",
|
||||||
["Kittila"] = "Kittila",
|
["Kittila"] = "Kittila",
|
||||||
["Bardufoss"] = "Bardufoss",
|
["Bardufoss"] = "Bardufoss",
|
||||||
["Alta"] = "Alta",
|
|
||||||
["Sodankyla"] = "Sodankyla",
|
|
||||||
["Enontekio"] = "Enontekio",
|
|
||||||
["Evenes"] = "Evenes",
|
|
||||||
["Hosio"] = "Hosio",
|
|
||||||
["Kilpyavr"] = "Kilpyavr",
|
|
||||||
["Afrikanda"] = "Afrikanda",
|
|
||||||
["Kalevala"] = "Kalevala",
|
|
||||||
["Koshka_Yavr"] = "Koshka Yavr",
|
|
||||||
["Poduzhemye"] = "Poduzhemye",
|
|
||||||
["Luostari_Pechenga"] = "Luostari Pechenga",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Airbases of the Afghanistan map
|
--- Airbases of the Afghanistan map
|
||||||
@@ -927,10 +913,10 @@ AIRBASE.Iraq = {
|
|||||||
|
|
||||||
--- Airbases of the Germany Cold War map
|
--- Airbases of the Germany Cold War map
|
||||||
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
||||||
-- * AIRBASE.GermanyCW.Airracing_Frankfurt
|
|
||||||
-- * AIRBASE.GermanyCW.Airracing_Koblenz
|
-- * AIRBASE.GermanyCW.Airracing_Koblenz
|
||||||
-- * AIRBASE.GermanyCW.Airracing_Luebeck
|
-- * AIRBASE.GermanyCW.Airracing_Luebeck
|
||||||
-- * AIRBASE.GermanyCW.Allstedt
|
-- * AIRBASE.GermanyCW.Allstedt
|
||||||
|
-- * AIRBASE.GermanyCW.Alt_Daber
|
||||||
-- * AIRBASE.GermanyCW.Altes_Lager
|
-- * AIRBASE.GermanyCW.Altes_Lager
|
||||||
-- * AIRBASE.GermanyCW.Bad_Duerkheim
|
-- * AIRBASE.GermanyCW.Bad_Duerkheim
|
||||||
-- * AIRBASE.GermanyCW.Barth
|
-- * AIRBASE.GermanyCW.Barth
|
||||||
@@ -953,13 +939,14 @@ AIRBASE.Iraq = {
|
|||||||
-- * AIRBASE.GermanyCW.Fritzlar
|
-- * AIRBASE.GermanyCW.Fritzlar
|
||||||
-- * AIRBASE.GermanyCW.Fulda
|
-- * AIRBASE.GermanyCW.Fulda
|
||||||
-- * AIRBASE.GermanyCW.Gardelegen
|
-- * AIRBASE.GermanyCW.Gardelegen
|
||||||
-- * AIRBASE.GermanyCW.Garz
|
|
||||||
-- * AIRBASE.GermanyCW.Gatow
|
-- * AIRBASE.GermanyCW.Gatow
|
||||||
-- * AIRBASE.GermanyCW.Gelnhausen
|
-- * AIRBASE.GermanyCW.Gelnhausen
|
||||||
-- * AIRBASE.GermanyCW.Giebelstadt
|
-- * AIRBASE.GermanyCW.Giebelstadt
|
||||||
-- * AIRBASE.GermanyCW.Glindbruchkippe
|
-- * AIRBASE.GermanyCW.Glindbruchkippe
|
||||||
|
-- * AIRBASE.GermanyCW.Gross_Doelln
|
||||||
-- * AIRBASE.GermanyCW.Gross_Mohrdorf
|
-- * AIRBASE.GermanyCW.Gross_Mohrdorf
|
||||||
-- * AIRBASE.GermanyCW.Grosse_Wiese
|
-- * AIRBASE.GermanyCW.Grosse_Wiese
|
||||||
|
-- * AIRBASE.GermanyCW.Gaerz
|
||||||
-- * AIRBASE.GermanyCW.Guetersloh
|
-- * AIRBASE.GermanyCW.Guetersloh
|
||||||
-- * AIRBASE.GermanyCW.H_FRG_01
|
-- * AIRBASE.GermanyCW.H_FRG_01
|
||||||
-- * AIRBASE.GermanyCW.H_FRG_02
|
-- * AIRBASE.GermanyCW.H_FRG_02
|
||||||
@@ -1031,11 +1018,10 @@ AIRBASE.Iraq = {
|
|||||||
-- * AIRBASE.GermanyCW.H_GDR_31
|
-- * AIRBASE.GermanyCW.H_GDR_31
|
||||||
-- * AIRBASE.GermanyCW.H_GDR_32
|
-- * AIRBASE.GermanyCW.H_GDR_32
|
||||||
-- * AIRBASE.GermanyCW.H_GDR_33
|
-- * AIRBASE.GermanyCW.H_GDR_33
|
||||||
-- * AIRBASE.GermanyCW.H_GDR_34
|
|
||||||
-- * AIRBASE.GermanyCW.H_Med_FRG_01
|
|
||||||
-- * AIRBASE.GermanyCW.H_Med_FRG_02
|
-- * AIRBASE.GermanyCW.H_Med_FRG_02
|
||||||
-- * AIRBASE.GermanyCW.H_Med_FRG_04
|
-- * AIRBASE.GermanyCW.H_Med_FRG_04
|
||||||
-- * AIRBASE.GermanyCW.H_Med_FRG_06
|
-- * AIRBASE.GermanyCW.H_Med_FRG_06
|
||||||
|
-- * AIRBASE.GermanyCW.H_Med_FRG_09
|
||||||
-- * AIRBASE.GermanyCW.H_Med_FRG_11
|
-- * AIRBASE.GermanyCW.H_Med_FRG_11
|
||||||
-- * AIRBASE.GermanyCW.H_Med_FRG_12
|
-- * AIRBASE.GermanyCW.H_Med_FRG_12
|
||||||
-- * AIRBASE.GermanyCW.H_Med_FRG_13
|
-- * AIRBASE.GermanyCW.H_Med_FRG_13
|
||||||
@@ -1083,9 +1069,9 @@ AIRBASE.Iraq = {
|
|||||||
-- * AIRBASE.GermanyCW.Koethen
|
-- * AIRBASE.GermanyCW.Koethen
|
||||||
-- * AIRBASE.GermanyCW.Laage
|
-- * AIRBASE.GermanyCW.Laage
|
||||||
-- * AIRBASE.GermanyCW.Langenselbold
|
-- * AIRBASE.GermanyCW.Langenselbold
|
||||||
-- * AIRBASE.GermanyCW.Laerz
|
|
||||||
-- * AIRBASE.GermanyCW.Leipzig_Halle
|
-- * AIRBASE.GermanyCW.Leipzig_Halle
|
||||||
-- * AIRBASE.GermanyCW.Leipzig_Mockau
|
-- * AIRBASE.GermanyCW.Leipzig_Mockau
|
||||||
|
-- * AIRBASE.GermanyCW.Laerz
|
||||||
-- * AIRBASE.GermanyCW.Luebeck
|
-- * AIRBASE.GermanyCW.Luebeck
|
||||||
-- * AIRBASE.GermanyCW.Lueneburg
|
-- * AIRBASE.GermanyCW.Lueneburg
|
||||||
-- * AIRBASE.GermanyCW.Mahlwinkel
|
-- * AIRBASE.GermanyCW.Mahlwinkel
|
||||||
@@ -1103,15 +1089,14 @@ AIRBASE.Iraq = {
|
|||||||
-- * AIRBASE.GermanyCW.Pottschutthoehe
|
-- * AIRBASE.GermanyCW.Pottschutthoehe
|
||||||
-- * AIRBASE.GermanyCW.Ramstein
|
-- * AIRBASE.GermanyCW.Ramstein
|
||||||
-- * AIRBASE.GermanyCW.Rinteln
|
-- * AIRBASE.GermanyCW.Rinteln
|
||||||
-- * AIRBASE.GermanyCW.Schoenefeld
|
|
||||||
-- * AIRBASE.GermanyCW.Schweinfurt
|
-- * AIRBASE.GermanyCW.Schweinfurt
|
||||||
|
-- * AIRBASE.GermanyCW.Schoenefeld
|
||||||
-- * AIRBASE.GermanyCW.Sembach
|
-- * AIRBASE.GermanyCW.Sembach
|
||||||
-- * AIRBASE.GermanyCW.Spangdahlem
|
-- * AIRBASE.GermanyCW.Spangdahlem
|
||||||
-- * AIRBASE.GermanyCW.Sperenberg
|
-- * AIRBASE.GermanyCW.Sperenberg
|
||||||
-- * AIRBASE.GermanyCW.Stendal
|
-- * AIRBASE.GermanyCW.Stendal
|
||||||
-- * AIRBASE.GermanyCW.Tegel
|
-- * AIRBASE.GermanyCW.Tegel
|
||||||
-- * AIRBASE.GermanyCW.Tempelhof
|
-- * AIRBASE.GermanyCW.Tempelhof
|
||||||
-- * AIRBASE.GermanyCW.Templin
|
|
||||||
-- * AIRBASE.GermanyCW.Tutow
|
-- * AIRBASE.GermanyCW.Tutow
|
||||||
-- * AIRBASE.GermanyCW.Uelzen
|
-- * AIRBASE.GermanyCW.Uelzen
|
||||||
-- * AIRBASE.GermanyCW.Uetersen
|
-- * AIRBASE.GermanyCW.Uetersen
|
||||||
@@ -1123,7 +1108,6 @@ AIRBASE.Iraq = {
|
|||||||
-- * AIRBASE.GermanyCW.Weser_Wuemme
|
-- * AIRBASE.GermanyCW.Weser_Wuemme
|
||||||
-- * AIRBASE.GermanyCW.Wiesbaden
|
-- * AIRBASE.GermanyCW.Wiesbaden
|
||||||
-- * AIRBASE.GermanyCW.Wismar
|
-- * AIRBASE.GermanyCW.Wismar
|
||||||
-- * AIRBASE.GermanyCW.Wittstock
|
|
||||||
-- * AIRBASE.GermanyCW.Worms
|
-- * AIRBASE.GermanyCW.Worms
|
||||||
-- * AIRBASE.GermanyCW.Wunstorf
|
-- * AIRBASE.GermanyCW.Wunstorf
|
||||||
-- * AIRBASE.GermanyCW.Zerbst
|
-- * AIRBASE.GermanyCW.Zerbst
|
||||||
@@ -1135,6 +1119,7 @@ AIRBASE.GermanyCW = {
|
|||||||
["Airracing_Koblenz"] = "Airracing Koblenz",
|
["Airracing_Koblenz"] = "Airracing Koblenz",
|
||||||
["Airracing_Luebeck"] = "Airracing Lubeck",
|
["Airracing_Luebeck"] = "Airracing Lubeck",
|
||||||
["Allstedt"] = "Allstedt",
|
["Allstedt"] = "Allstedt",
|
||||||
|
["Alt_Daber"] = "Alt Daber",
|
||||||
["Altes_Lager"] = "Altes Lager",
|
["Altes_Lager"] = "Altes Lager",
|
||||||
["Bad_Duerkheim"] = "Bad Durkheim",
|
["Bad_Duerkheim"] = "Bad Durkheim",
|
||||||
["Barth"] = "Barth",
|
["Barth"] = "Barth",
|
||||||
@@ -1157,13 +1142,14 @@ AIRBASE.GermanyCW = {
|
|||||||
["Fritzlar"] = "Fritzlar",
|
["Fritzlar"] = "Fritzlar",
|
||||||
["Fulda"] = "Fulda",
|
["Fulda"] = "Fulda",
|
||||||
["Gardelegen"] = "Gardelegen",
|
["Gardelegen"] = "Gardelegen",
|
||||||
["Garz"] = "Garz",
|
|
||||||
["Gatow"] = "Gatow",
|
["Gatow"] = "Gatow",
|
||||||
["Gelnhausen"] = "Gelnhausen",
|
["Gelnhausen"] = "Gelnhausen",
|
||||||
["Giebelstadt"] = "Giebelstadt",
|
["Giebelstadt"] = "Giebelstadt",
|
||||||
["Glindbruchkippe"] = "Glindbruchkippe ",
|
["Glindbruchkippe_"] = "Glindbruchkippe ",
|
||||||
|
["Gross_Doelln"] = "Gross Dolln",
|
||||||
["Gross_Mohrdorf"] = "Gross Mohrdorf",
|
["Gross_Mohrdorf"] = "Gross Mohrdorf",
|
||||||
["Grosse_Wiese"] = "Grosse Wiese",
|
["Grosse_Wiese"] = "Grosse Wiese",
|
||||||
|
["Gaerz"] = "Garz",
|
||||||
["Guetersloh"] = "Gutersloh",
|
["Guetersloh"] = "Gutersloh",
|
||||||
["H_FRG_01"] = "H FRG 01",
|
["H_FRG_01"] = "H FRG 01",
|
||||||
["H_FRG_02"] = "H FRG 02",
|
["H_FRG_02"] = "H FRG 02",
|
||||||
@@ -1235,11 +1221,10 @@ AIRBASE.GermanyCW = {
|
|||||||
["H_GDR_31"] = "H GDR 31",
|
["H_GDR_31"] = "H GDR 31",
|
||||||
["H_GDR_32"] = "H GDR 32",
|
["H_GDR_32"] = "H GDR 32",
|
||||||
["H_GDR_33"] = "H GDR 33",
|
["H_GDR_33"] = "H GDR 33",
|
||||||
["H_GDR_34"] = "H GDR 34",
|
|
||||||
["H_Med_FRG_01"] = "H Med FRG 01",
|
|
||||||
["H_Med_FRG_02"] = "H Med FRG 02",
|
["H_Med_FRG_02"] = "H Med FRG 02",
|
||||||
["H_Med_FRG_04"] = "H Med FRG 04",
|
["H_Med_FRG_04"] = "H Med FRG 04",
|
||||||
["H_Med_FRG_06"] = "H Med FRG 06",
|
["H_Med_FRG_06"] = "H Med FRG 06",
|
||||||
|
["H_Med_FRG_09"] = "H Med FRG 09",
|
||||||
["H_Med_FRG_11"] = "H Med FRG 11",
|
["H_Med_FRG_11"] = "H Med FRG 11",
|
||||||
["H_Med_FRG_12"] = "H Med FRG 12",
|
["H_Med_FRG_12"] = "H Med FRG 12",
|
||||||
["H_Med_FRG_13"] = "H Med FRG 13",
|
["H_Med_FRG_13"] = "H Med FRG 13",
|
||||||
@@ -1287,9 +1272,9 @@ AIRBASE.GermanyCW = {
|
|||||||
["Koethen"] = "Kothen",
|
["Koethen"] = "Kothen",
|
||||||
["Laage"] = "Laage",
|
["Laage"] = "Laage",
|
||||||
["Langenselbold"] = "Langenselbold",
|
["Langenselbold"] = "Langenselbold",
|
||||||
["Laerz"] = "Larz",
|
|
||||||
["Leipzig_Halle"] = "Leipzig Halle",
|
["Leipzig_Halle"] = "Leipzig Halle",
|
||||||
["Leipzig_Mockau"] = "Leipzig Mockau",
|
["Leipzig_Mockau"] = "Leipzig Mockau",
|
||||||
|
["Laerz"] = "Larz",
|
||||||
["Luebeck"] = "Lubeck",
|
["Luebeck"] = "Lubeck",
|
||||||
["Lueneburg"] = "Luneburg",
|
["Lueneburg"] = "Luneburg",
|
||||||
["Mahlwinkel"] = "Mahlwinkel",
|
["Mahlwinkel"] = "Mahlwinkel",
|
||||||
@@ -1307,15 +1292,14 @@ AIRBASE.GermanyCW = {
|
|||||||
["Pottschutthoehe"] = "Pottschutthohe",
|
["Pottschutthoehe"] = "Pottschutthohe",
|
||||||
["Ramstein"] = "Ramstein",
|
["Ramstein"] = "Ramstein",
|
||||||
["Rinteln"] = "Rinteln",
|
["Rinteln"] = "Rinteln",
|
||||||
["Schoenefeld"] = "Schonefeld",
|
|
||||||
["Schweinfurt"] = "Schweinfurt",
|
["Schweinfurt"] = "Schweinfurt",
|
||||||
|
["Schoenefeld"] = "Schonefeld",
|
||||||
["Sembach"] = "Sembach",
|
["Sembach"] = "Sembach",
|
||||||
["Spangdahlem"] = "Spangdahlem",
|
["Spangdahlem"] = "Spangdahlem",
|
||||||
["Sperenberg"] = "Sperenberg",
|
["Sperenberg"] = "Sperenberg",
|
||||||
["Stendal"] = "Stendal",
|
["Stendal"] = "Stendal",
|
||||||
["Tegel"] = "Tegel",
|
["Tegel"] = "Tegel",
|
||||||
["Tempelhof"] = "Tempelhof",
|
["Tempelhof"] = "Tempelhof",
|
||||||
["Templin"] = "Templin",
|
|
||||||
["Tutow"] = "Tutow",
|
["Tutow"] = "Tutow",
|
||||||
["Uelzen"] = "Uelzen",
|
["Uelzen"] = "Uelzen",
|
||||||
["Uetersen"] = "Uetersen",
|
["Uetersen"] = "Uetersen",
|
||||||
@@ -1327,7 +1311,6 @@ AIRBASE.GermanyCW = {
|
|||||||
["Weser_Wuemme"] = "Weser Wumme",
|
["Weser_Wuemme"] = "Weser Wumme",
|
||||||
["Wiesbaden"] = "Wiesbaden",
|
["Wiesbaden"] = "Wiesbaden",
|
||||||
["Wismar"] = "Wismar",
|
["Wismar"] = "Wismar",
|
||||||
["Wittstock"] = "Wittstock",
|
|
||||||
["Worms"] = "Worms",
|
["Worms"] = "Worms",
|
||||||
["Wunstorf"] = "Wunstorf",
|
["Wunstorf"] = "Wunstorf",
|
||||||
["Zerbst"] = "Zerbst",
|
["Zerbst"] = "Zerbst",
|
||||||
@@ -1401,6 +1384,32 @@ AIRBASE.SpotStatus = {
|
|||||||
RESERVED="Reserved",
|
RESERVED="Reserved",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- ICAO Codes.
|
||||||
|
-- @type AIRBASE.ICAO
|
||||||
|
AIRBASE.ICAO = {
|
||||||
|
UGTB=AIRBASE.Caucasus.Tbilisi_Lochini,
|
||||||
|
UGKO=AIRBASE.Caucasus.Kutaisi,
|
||||||
|
UG5X=AIRBASE.Caucasus.Kobuleti,
|
||||||
|
UG24=AIRBASE.Caucasus.Soganlug,
|
||||||
|
UG27=AIRBASE.Caucasus.Vaziani,
|
||||||
|
UGSS=AIRBASE.Caucasus.Sukhumi_Babushara,
|
||||||
|
UG23=AIRBASE.Caucasus.Gudauta,
|
||||||
|
URSS=AIRBASE.Caucasus.Sochi_Adler,
|
||||||
|
URMO=AIRBASE.Caucasus.Beslan,
|
||||||
|
URMN=AIRBASE.Caucasus.Nalchik,
|
||||||
|
XRMF=AIRBASE.Caucasus.Mozdok,
|
||||||
|
URMM=AIRBASE.Caucasus.Mineralnye_Vody,
|
||||||
|
URKH=AIRBASE.Caucasus.Maykop_Khanskaya,
|
||||||
|
URKK=AIRBASE.Caucasus.Krasnodar_Pashkovsky,
|
||||||
|
URKL=AIRBASE.Caucasus.Krasnodar_Center,
|
||||||
|
URKG=AIRBASE.Caucasus.Gelendzhik,
|
||||||
|
URKN=AIRBASE.Caucasus.Novorossiysk,
|
||||||
|
URKW=AIRBASE.Caucasus.Krymsk,
|
||||||
|
URKA=AIRBASE.Caucasus.Anapa_Vityazevo,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Runway data.
|
--- Runway data.
|
||||||
-- @type AIRBASE.Runway
|
-- @type AIRBASE.Runway
|
||||||
-- @field #string name Runway name.
|
-- @field #string name Runway name.
|
||||||
@@ -1578,14 +1587,47 @@ end
|
|||||||
|
|
||||||
--- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase.
|
--- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @param #string AirbaseName The Airbase Name.
|
-- @param #string AirbaseName The name of the airbase. Can also be the ICAO code or the airbase ID.
|
||||||
-- @return #AIRBASE self
|
-- @return #AIRBASE self
|
||||||
function AIRBASE:FindByName( AirbaseName )
|
function AIRBASE:FindByName( AirbaseName )
|
||||||
|
|
||||||
local AirbaseFound = _DATABASE:FindAirbase( AirbaseName )
|
local AirbaseFound = _DATABASE:FindAirbase( AirbaseName )
|
||||||
|
|
||||||
|
if not AirbaseFound then
|
||||||
|
AirbaseFound=self:FindByICAO(AirbaseName)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not AirbaseFound then
|
||||||
|
AirbaseFound=self:FindByID(AirbaseName)
|
||||||
|
end
|
||||||
|
|
||||||
return AirbaseFound
|
return AirbaseFound
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Find an AIRBASE in the _DATABASE using the [International Civil Aviation Organization](https://en.wikipedia.org/wiki/ICAO_airport_code) (ICAO) airport code.
|
||||||
|
-- The code consists of four characters. Typically, the first one or two letters of the ICAO code indicate the country and the remaining letters identify the airport.
|
||||||
|
--
|
||||||
|
-- **NOTE** that the ICAO code cannot be retrieved via the DCS API and has to be hard coded into the MOOSE code. Therefore, it is a rare occasion where
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param #string AirbaseICAO The Airbase ICAO code.
|
||||||
|
-- @return #AIRBASE self
|
||||||
|
function AIRBASE:FindByICAO( AirbaseICAO )
|
||||||
|
|
||||||
|
if AirbaseICAO then
|
||||||
|
|
||||||
|
local name=AIRBASE.ICAO[AirbaseICAO]
|
||||||
|
|
||||||
|
env.info(string.format("FF ICAO=%s, Name=%s", tostring(AirbaseICAO), tostring(name)))
|
||||||
|
|
||||||
|
local Airbase=self:FindByName(name)
|
||||||
|
return Airbase
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Find a AIRBASE in the _DATABASE by its ID.
|
--- Find a AIRBASE in the _DATABASE by its ID.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @param #number id Airbase ID.
|
-- @param #number id Airbase ID.
|
||||||
@@ -1898,6 +1940,129 @@ function AIRBASE:IsShip()
|
|||||||
return self.isShip
|
return self.isShip
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Taxi ways
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Add a taxiway from a given PATHLINE.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param Core.Pathline#PATHLINE TaxiPathline Pathline of the taxi way or name of pathline as #string.
|
||||||
|
-- @param #string Name Name of the taxi way, *e.g.* "Alpha", or "Alpha-Kilo". Default is name of pathline.
|
||||||
|
-- @return #AIRBASE self
|
||||||
|
function AIRBASE:AddTaxiway(TaxiPathline, Name)
|
||||||
|
|
||||||
|
-- If passed as string, get pathline.
|
||||||
|
if type(TaxiPathline)=="string" then
|
||||||
|
TaxiPathline=PATHLINE:FindByName(TaxiPathline)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set name.
|
||||||
|
Name=Name or TaxiPathline:GetName()
|
||||||
|
|
||||||
|
-- Create a deep copy.
|
||||||
|
local taxiway=UTILS.DeepCopy(TaxiPathline) --Core.Pathline#PATHLINE
|
||||||
|
|
||||||
|
-- Set name.
|
||||||
|
taxiway.name=Name
|
||||||
|
|
||||||
|
-- Add to taxiways.
|
||||||
|
self.taxiways[Name]=taxiway
|
||||||
|
|
||||||
|
|
||||||
|
--self:I(self.taxiways)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Find the shortest path using taxiways to get from given coodinates A to B on the airbase.
|
||||||
|
-- Note that the taxi ways have to be manually added with the `AIRBASE:AddTaxiway()` function.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param Core.Point#COORDINATE StartCoord Start coordinate.
|
||||||
|
-- @param Core.Point#COORDINATE EndCoord End coordinate.
|
||||||
|
-- @return Core.Pathline#PATHLINE Shortest path on taxiways from `StartCoord` to `EndCoord`.
|
||||||
|
-- @return #table Table of used taxi way pathlines.
|
||||||
|
function AIRBASE:FindTaxiwaysFromAtoB(StartCoord, EndCoord)
|
||||||
|
|
||||||
|
-- Create A* pathfinding.
|
||||||
|
local astar=ASTAR:New()
|
||||||
|
|
||||||
|
-- Add pathlines of taxiways of airport.
|
||||||
|
for _,_taxiway in pairs(self.taxiways) do
|
||||||
|
local taxiway=_taxiway --Core.Pathline#PATHLINE
|
||||||
|
|
||||||
|
astar:AddNodeFromPathlineName(taxiway)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set cost function.
|
||||||
|
astar:SetCostDist2D()
|
||||||
|
|
||||||
|
-- Set valid neighbours to be on the same pathline or at most 10 meters between nodes to jump from one pathline/taxiway to another.
|
||||||
|
astar:SetValidNeighbourPathline(10)
|
||||||
|
|
||||||
|
-- Set start and end coordinates.
|
||||||
|
astar:SetStartCoordinate(StartCoord)
|
||||||
|
astar:SetEndCoordinate(EndCoord)
|
||||||
|
|
||||||
|
-- Get pathline.
|
||||||
|
local taxipath, nodes=astar:GetPathline()
|
||||||
|
|
||||||
|
local taxiways=astar:GetPathlinesFromNodes(nodes)
|
||||||
|
|
||||||
|
return taxipath, taxiways
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get closest taxiway from a given reference coordinate.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param Core.Point#COORDINATE Coord Reference coordinate.
|
||||||
|
-- @return Core.Pathline#PATHLINE Taxiway.
|
||||||
|
-- @return #number Distance to taxiway in meters.
|
||||||
|
-- @return Core.Point#COORDINATE Coordinate on taxiway closest to reference coordinate.
|
||||||
|
-- @return Core.Pathline#PATHLINE.Segment Segment of the taxiway closest to the reference coordinate.
|
||||||
|
function AIRBASE:GetClosestTaxiway(Coord)
|
||||||
|
|
||||||
|
local taxipath=nil
|
||||||
|
local distmin=math.huge
|
||||||
|
local coordmin=nil
|
||||||
|
local segmin=nil
|
||||||
|
|
||||||
|
for name,_pathline in pairs(self.taxiways) do
|
||||||
|
local pathline=_pathline --Core.Pathline#PATHLINE
|
||||||
|
|
||||||
|
local coord, dist, segment=pathline:GetClosestPoint3D(Coord)
|
||||||
|
|
||||||
|
if dist<distmin then
|
||||||
|
taxipath=pathline
|
||||||
|
coordmin=coord
|
||||||
|
distmin=dist
|
||||||
|
segmin=segment
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return taxipath, distmin, coordmin, segmin
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Find the shortest path using taxiways to get from given parking spot to the starting point of a runway.
|
||||||
|
-- Note that the taxi ways have to be manually added with the `AIRBASE:AddTaxiway()` function.
|
||||||
|
-- @param #AIRBASE self
|
||||||
|
-- @param #AIRBASE.ParkingSpot ParkingSpot Parking spot.
|
||||||
|
-- @param #AIRBASE.Runway Runway The runway. If none is given, we take the active runway for takeoff.
|
||||||
|
-- @return Core.Pathline#PATHLINE Shortest path on taxiways from `StartCoord` to `EndCoord`.
|
||||||
|
-- @return #table Table of used taxi way pathlines.
|
||||||
|
function AIRBASE:FindTaxiwaysParkingToRunway(ParkingSpot, Runway)
|
||||||
|
|
||||||
|
Runway=Runway or self:GetActiveRunwayTakeoff()
|
||||||
|
|
||||||
|
local StartCoord=ParkingSpot.Coordinate
|
||||||
|
local EndCoord=Runway.position
|
||||||
|
|
||||||
|
local taxipath, taxiways=self:FindTaxiwaysFromAtoB(StartCoord,EndCoord)
|
||||||
|
|
||||||
|
return taxipath, taxiways
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Parking
|
-- Parking
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -2600,7 +2765,7 @@ function AIRBASE:_InitRunways(IncludeInverse)
|
|||||||
runway.name=string.format("%02d", tonumber(namefromheading))
|
runway.name=string.format("%02d", tonumber(namefromheading))
|
||||||
else
|
else
|
||||||
runway.name=string.format("%02d", tonumber(name))
|
runway.name=string.format("%02d", tonumber(name))
|
||||||
--self:I("RunwayName: "..runway.name)
|
self:I("RunwayName: "..runway.name)
|
||||||
end
|
end
|
||||||
|
|
||||||
--runway.name=string.format("%02d", tonumber(name))
|
--runway.name=string.format("%02d", tonumber(name))
|
||||||
|
|||||||
@@ -912,18 +912,15 @@ function GROUP:GetVelocityVec3()
|
|||||||
|
|
||||||
if DCSGroup and DCSGroup:isExist() then
|
if DCSGroup and DCSGroup:isExist() then
|
||||||
local GroupUnits = DCSGroup:getUnits()
|
local GroupUnits = DCSGroup:getUnits()
|
||||||
local GroupCount = 0
|
local GroupCount = #GroupUnits
|
||||||
|
|
||||||
local VelocityVec3 = { x = 0, y = 0, z = 0 }
|
local VelocityVec3 = { x = 0, y = 0, z = 0 }
|
||||||
|
|
||||||
for _, DCSUnit in pairs( GroupUnits ) do
|
for _, DCSUnit in pairs( GroupUnits ) do
|
||||||
if DCSUnit:isExist() and DCSUnit:isActive() then
|
|
||||||
local UnitVelocityVec3 = DCSUnit:getVelocity()
|
local UnitVelocityVec3 = DCSUnit:getVelocity()
|
||||||
VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x
|
VelocityVec3.x = VelocityVec3.x + UnitVelocityVec3.x
|
||||||
VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y
|
VelocityVec3.y = VelocityVec3.y + UnitVelocityVec3.y
|
||||||
VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z
|
VelocityVec3.z = VelocityVec3.z + UnitVelocityVec3.z
|
||||||
GroupCount = GroupCount + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
VelocityVec3.x = VelocityVec3.x / GroupCount
|
VelocityVec3.x = VelocityVec3.x / GroupCount
|
||||||
@@ -1757,7 +1754,6 @@ function GROUP:GetMaxVelocity()
|
|||||||
|
|
||||||
for Index, UnitData in pairs( DCSGroup:getUnits() ) do
|
for Index, UnitData in pairs( DCSGroup:getUnits() ) do
|
||||||
|
|
||||||
if UnitData:isExist() and UnitData:isActive() then
|
|
||||||
local UnitVelocityVec3 = UnitData:getVelocity()
|
local UnitVelocityVec3 = UnitData:getVelocity()
|
||||||
local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z )
|
local UnitVelocity = math.abs( UnitVelocityVec3.x ) + math.abs( UnitVelocityVec3.y ) + math.abs( UnitVelocityVec3.z )
|
||||||
|
|
||||||
@@ -1765,7 +1761,6 @@ function GROUP:GetMaxVelocity()
|
|||||||
GroupVelocityMax = UnitVelocity
|
GroupVelocityMax = UnitVelocity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
return GroupVelocityMax
|
return GroupVelocityMax
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -897,7 +897,7 @@ function UNIT:GetAmmunition()
|
|||||||
nAPshells = nAPshells + Nammo
|
nAPshells = nAPshells + Nammo
|
||||||
end
|
end
|
||||||
|
|
||||||
if ammotable[w].desc.typeName and (string.find(ammotable[w].desc.typeName, "_HE", 1, true) or string.find(ammotable[w].desc.typeName, "HESH", 1, true)) then
|
if ammotable[w].desc.typeName and string.find(ammotable[w].desc.typeName, "_HE", 1, true) then
|
||||||
nHEshells = nHEshells + Nammo
|
nHEshells = nHEshells + Nammo
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1107,6 +1107,7 @@ function UNIT:GetUnits()
|
|||||||
|
|
||||||
if DCSUnit then
|
if DCSUnit then
|
||||||
Units[1] = UNIT:Find(DCSUnit)
|
Units[1] = UNIT:Find(DCSUnit)
|
||||||
|
- self:T3(Units)
|
||||||
return Units
|
return Units
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user