mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
256 Commits
FF/OpsDev
...
bd054b26c0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd054b26c0 | ||
|
|
f094716b73 | ||
|
|
b3100d2f5e | ||
|
|
4b1888a34d | ||
|
|
f4cd214823 | ||
|
|
b9be3aa7f8 | ||
|
|
bb6db2b7f8 | ||
|
|
fd2dacaefb | ||
|
|
cc60e85901 | ||
|
|
9520782a04 | ||
|
|
f172f6efeb | ||
|
|
b6b6686873 | ||
|
|
5e724e7a3f | ||
|
|
90f1d1df2a | ||
|
|
a5726c0ed8 | ||
|
|
1860366986 | ||
|
|
9db1d38a15 | ||
|
|
04ceda693b | ||
|
|
23ff128ac8 | ||
|
|
3749142670 | ||
|
|
7d3fc1740a | ||
|
|
b2a084d669 | ||
|
|
30203668e4 | ||
|
|
ebecc70693 | ||
|
|
74712b6e27 | ||
|
|
40253ea8bb | ||
|
|
7279da7f09 | ||
|
|
31c40c96f2 | ||
|
|
7a833365ce | ||
|
|
4e56078d2a | ||
|
|
0ac156f2b5 | ||
|
|
4bbf20ca4e | ||
|
|
a462c5a493 | ||
|
|
179cb5f589 | ||
|
|
367014ebf3 | ||
|
|
9d8d0c2155 | ||
|
|
edfe91274d | ||
|
|
326b20b08d | ||
|
|
11b0ce6275 | ||
|
|
03763e16d6 | ||
|
|
c1e8ee12e0 | ||
|
|
ac8cc408c1 | ||
|
|
dad91cca8c | ||
|
|
2f9c384ac0 | ||
|
|
f23a2267cf | ||
|
|
ada38fa3ea | ||
|
|
2ee0597d48 | ||
|
|
b39a83ad6e | ||
|
|
7ae4cdc8f1 | ||
|
|
7d47227fab | ||
|
|
1f09b8fe0b | ||
|
|
8c92a578ed | ||
|
|
992f09d9ba | ||
|
|
096f2caf9c | ||
|
|
0b37c909b3 | ||
|
|
bdad38e707 | ||
|
|
1b18ae1597 | ||
|
|
8dcc3cbe8f | ||
|
|
aa8f3a824c | ||
|
|
b5a19528a1 | ||
|
|
bd20e8fc81 | ||
|
|
2f806801bc | ||
|
|
be006bd2bf | ||
|
|
18a08288ec | ||
|
|
c9ac6d73e6 | ||
|
|
f602455d1f | ||
|
|
d5c34a37b0 | ||
|
|
8a0e9a3400 | ||
|
|
0e836973fd | ||
|
|
1b57af88a0 | ||
|
|
be40d7be9a | ||
|
|
00de8d911c | ||
|
|
9df3fcfdf7 | ||
|
|
d675e34f37 | ||
|
|
2d96ba0f56 | ||
|
|
21c2bd1103 | ||
|
|
f3b7740041 | ||
|
|
7d7488db6f | ||
|
|
b9197d65d5 | ||
|
|
ec6f190b68 | ||
|
|
5e4f9f035b | ||
|
|
7b6bf7f39b | ||
|
|
2e8875dd2f | ||
|
|
4964cc2f2d | ||
|
|
f0a4c5b008 | ||
|
|
1b6412821b | ||
|
|
926a0733e4 | ||
|
|
124ebd3240 | ||
|
|
7728609165 | ||
|
|
da70f4ce6c | ||
|
|
69b3e9abad | ||
|
|
f9f77bfa7b | ||
|
|
429db73854 | ||
|
|
1e9c45c115 | ||
|
|
727cb3276c | ||
|
|
a68175448d | ||
|
|
33e63a4819 | ||
|
|
d7431478d1 | ||
|
|
3543b2c79a | ||
|
|
4489efff94 | ||
|
|
dcdea379ef | ||
|
|
6a4bddde99 | ||
|
|
2088359756 | ||
|
|
dc2511942c | ||
|
|
f0c257c4a5 | ||
|
|
068d21612f | ||
|
|
773461aad9 | ||
|
|
f9257b2b0d | ||
|
|
9e0f03a3cd | ||
|
|
0ab6a10ec4 | ||
|
|
73f393c542 | ||
|
|
a467fabdc8 | ||
|
|
a2ab84c45a | ||
|
|
7ec7228cb8 | ||
|
|
9fd6729967 | ||
|
|
f1d4f1753a | ||
|
|
1f268b3b5d | ||
|
|
6d9c3fd0aa | ||
|
|
28ae63bd8d | ||
|
|
42e7e3f94f | ||
|
|
4a5204aecb | ||
|
|
6466c5e95e | ||
|
|
829f5af25f | ||
|
|
0d1147bac4 | ||
|
|
24b47b02e0 | ||
|
|
10262fd30b | ||
|
|
3cabc07d58 | ||
|
|
b0546b1e60 | ||
|
|
a988e67490 | ||
|
|
fa951838d2 | ||
|
|
2594c5bbf0 | ||
|
|
db70fa341c | ||
|
|
763e3852ac | ||
|
|
66157d0596 | ||
|
|
8ec86973c6 | ||
|
|
eb2c6ac6f2 | ||
|
|
93a8d8bc2d | ||
|
|
cbcc893ce5 | ||
|
|
c19713949d | ||
|
|
54450935a1 | ||
|
|
d0f5712ca8 | ||
|
|
382b049c5f | ||
|
|
6c2cc37abe | ||
|
|
a53763221c | ||
|
|
83447a3fb4 | ||
|
|
b7bac28113 | ||
|
|
a9edb16554 | ||
|
|
52cbb7202c | ||
|
|
f6a8317c42 | ||
|
|
2a9a7db9b8 | ||
|
|
3aeec78f79 | ||
|
|
0aeb1fc6af | ||
|
|
26565d7549 | ||
|
|
62816f217b | ||
|
|
eeeeda4e5e | ||
|
|
95767c5ef4 | ||
|
|
f5881eda53 | ||
|
|
fca6faa3a8 | ||
|
|
c1997d9f70 | ||
|
|
bb1caa6642 | ||
|
|
638f083729 | ||
|
|
59d41cf98b | ||
|
|
793adafda7 | ||
|
|
dd5ca93f26 | ||
|
|
0d1a7c770b | ||
|
|
1889df4952 | ||
|
|
7ca219748d | ||
|
|
b3f944e82e | ||
|
|
2fc16ba694 | ||
|
|
432fc0ef4b | ||
|
|
20c50c751f | ||
|
|
d3b62d0260 | ||
|
|
d0449265c1 | ||
|
|
a4feafab8e | ||
|
|
309eedd165 | ||
|
|
997baf21a0 | ||
|
|
fa676cc750 | ||
|
|
b126cc00d0 | ||
|
|
1e0c27f599 | ||
|
|
09b7922b84 | ||
|
|
66032d6894 | ||
|
|
7c98a793c7 | ||
|
|
7a5b9a75f3 | ||
|
|
0ea5631955 | ||
|
|
4bab2ee1de | ||
|
|
f5b9713639 | ||
|
|
1bfb4fc4e1 | ||
|
|
d7defe6f7f | ||
|
|
ebb94c07b3 | ||
|
|
f4cdbec376 | ||
|
|
21d5a5dfac | ||
|
|
f8947aab9c | ||
|
|
db869bcb6d | ||
|
|
36a0cfd635 | ||
|
|
ea4a1f9ff9 | ||
|
|
20406e40ca | ||
|
|
acbcb14cba | ||
|
|
3b50fee5a0 | ||
|
|
804004198b | ||
|
|
67ef6c6e7b | ||
|
|
5b8b8a5566 | ||
|
|
0468bacc0b | ||
|
|
eacc43cb5a | ||
|
|
f3dcde075c | ||
|
|
7eba1349ae | ||
|
|
b6074a4795 | ||
|
|
615afb7cc4 | ||
|
|
36c9f551d9 | ||
|
|
89c3f7310b | ||
|
|
6791a0e704 | ||
|
|
a6b622ed31 | ||
|
|
f1af3a50b8 | ||
|
|
f999e45323 | ||
|
|
0c90e90c18 | ||
|
|
4747f3f48f | ||
|
|
f97ef25104 | ||
|
|
e1a670185e | ||
|
|
069c0aa03f | ||
|
|
b145588ed5 | ||
|
|
b678e2cde1 | ||
|
|
db23a0bf2b | ||
|
|
3ad60a95ce | ||
|
|
5c3b7312c0 | ||
|
|
f177d0a257 | ||
|
|
ac4b620f16 | ||
|
|
c49b56eefc | ||
|
|
ccada18a6a | ||
|
|
1547d66327 | ||
|
|
e21236655a | ||
|
|
cdad3bd058 | ||
|
|
0db9c27f7e | ||
|
|
8042e8bfaf | ||
|
|
dd7b87e9cd | ||
|
|
68a539923f | ||
|
|
460d2768ff | ||
|
|
3c74272749 | ||
|
|
3442725525 | ||
|
|
82c409d77a | ||
|
|
195aac4504 | ||
|
|
326e27327d | ||
|
|
08d8f3e25f | ||
|
|
6f72697e26 | ||
|
|
296d4b1e93 | ||
|
|
0f6439cf9f | ||
|
|
9705b49dbe | ||
|
|
9364579a18 | ||
|
|
02a6d8f2c0 | ||
|
|
2c10943cb1 | ||
|
|
a293c59d6d | ||
|
|
544db963ea | ||
|
|
d3fd21e6da | ||
|
|
207698a2dd | ||
|
|
27cd90a0ce | ||
|
|
d1ae2c0f5e | ||
|
|
66e6a603f1 | ||
|
|
0392417189 |
@@ -1953,7 +1953,7 @@ local function refct_from_id(id) -- refct = refct_from_id(CTypeID)
|
||||
unsigned = refct.unsigned,
|
||||
size = bit.band(bit.rshift(ctype.info, 16), 127),
|
||||
}
|
||||
refct.bool, refct.const, refct.volatile, refct.unsigned = nil
|
||||
refct.bool, refct.const, refct.volatile, refct.unsigned = nil, nil, nil, nil
|
||||
end
|
||||
|
||||
if CT[4] then -- Merge sibling attributes onto this type.
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
-- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- There are basically two classes available to model an A2A defense system.
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
--- 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 will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- 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.
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage -- TODO: Documentation. This class does not exist, unable to determine what it extends.
|
||||
|
||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
--- 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 will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
--- The AI_AIR class implements the core functions to operate an AI @{Wrapper.Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 1) AI_AIR constructor
|
||||
--
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
--
|
||||
-- # QUICK START GUIDE
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
|
||||
|
||||
|
||||
-- @type AI_AIR_ENGAGE
|
||||
--- @type AI_AIR_ENGAGE
|
||||
-- @extends AI.AI_AIR#AI_AIR
|
||||
|
||||
|
||||
--- 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 will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
--- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
-- 
|
||||
|
||||
@@ -33,8 +33,9 @@
|
||||
-- @field Wrapper.Group#GROUP Test
|
||||
-- @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.
|
||||
-- In other words, use AI_BALANCER to simulate human behaviour by spawning in replacement AI in multi player missions.
|
||||
--
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
--- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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,6 +38,9 @@
|
||||
-- @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}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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,12 +9,14 @@
|
||||
-- @module AI.AI_Cargo
|
||||
-- @image Cargo.JPG
|
||||
|
||||
-- @type AI_CARGO
|
||||
--- @type AI_CARGO
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
|
||||
--- 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.
|
||||
-- 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.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
-- The AI_CARGO_APC class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
|
||||
--- 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.
|
||||
--
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # The dispatcher concept.
|
||||
--
|
||||
-- Carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
-- The AI_CARGO_DISPATCHER_APC module is derived from the AI_CARGO_DISPATCHER module.
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
--- Brings a dynamic cargo handling capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
--- A dynamic cargo handling capability for AI helicopter groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Helicopters can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
--
|
||||
--
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
--- A dynamic cargo transportation capability for AI groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Naval vessels can be mobilized to semi-intelligently transport cargo within the simulation.
|
||||
--
|
||||
-- The AI_CARGO_DISPATCHER_SHIP module is derived from the AI_CARGO_DISPATCHER module.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
--- 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.
|
||||
--
|
||||
-- The AI_CARGO_HELICOPTER class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
--- Brings a dynamic cargo handling capability for an AI naval group.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- Naval ships can be utilized to transport cargo around the map following naval shipping lanes.
|
||||
-- The AI_CARGO_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||
-- @{Cargo.Cargo} must be declared within the mission or warehouse to make the AI_CARGO_SHIP recognize the cargo.
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
--
|
||||
-- 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).
|
||||
--
|
||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
--- Models the assignment of AI escorts to player flights upon request using the radio menu.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
--
|
||||
-- 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).
|
||||
--
|
||||
-- The radio commands will vary according the category of the group. The richest set of commands are with helicopters and airPlanes.
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
|
||||
|
||||
--- 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.
|
||||
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
|
||||
--- 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
||||
--
|
||||
-- 
|
||||
-- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -8,9 +8,11 @@
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
do -- ACT_ACCOUNT
|
||||
|
||||
|
||||
--- # @{#ACT_ACCOUNT} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## ACT_ACCOUNT state machine:
|
||||
--
|
||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||
@@ -133,7 +135,7 @@ do -- ACT_ACCOUNT
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To, Event )
|
||||
function ACT_ACCOUNT:onafterEvent( ProcessUnit, From, Event, To )
|
||||
|
||||
self:__NoMore( 1 )
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
--- (SP) (MP) (FSM) Accept or reject process for player (task) assignments.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # @{#ACT_ASSIGN} FSM template class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
--- (SP) (MP) (FSM) Route AI or players through waypoints or to zones.
|
||||
--
|
||||
-- 
|
||||
-- ## ACT_ASSIST state machine:
|
||||
--
|
||||
-- This class is a state machine: it manages a process that is triggered by events causing state transitions to occur.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # @{#ACT_ROUTE} FSM class, extends @{Core.Fsm#FSM_PROCESS}
|
||||
--
|
||||
-- ## ACT_ROUTE state machine:
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 1) MOOSE Cargo System.
|
||||
--
|
||||
-- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities.
|
||||
|
||||
@@ -22,6 +22,9 @@ do -- CARGO_CRATE
|
||||
-- @type CARGO_CRATE
|
||||
-- @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.
|
||||
-- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers.
|
||||
--
|
||||
|
||||
@@ -26,6 +26,8 @@ do -- CARGO_GROUP
|
||||
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
||||
|
||||
--- 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 above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo:
|
||||
|
||||
@@ -32,6 +32,8 @@ do -- CARGO_SLINGLOAD
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
|
||||
@@ -30,6 +30,8 @@ do -- CARGO_UNIT
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
|
||||
@@ -157,8 +157,6 @@ ASTAR = {
|
||||
-- @field #number surfacetype Surface type.
|
||||
-- @field #table valid Cached valid/invalid nodes.
|
||||
-- @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.
|
||||
-- @field #number INF
|
||||
@@ -166,7 +164,7 @@ ASTAR.INF=1/0
|
||||
|
||||
--- ASTAR class version.
|
||||
-- @field #string version
|
||||
ASTAR.version="0.5.0"
|
||||
ASTAR.version="0.4.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -174,7 +172,6 @@ ASTAR.version="0.5.0"
|
||||
|
||||
-- TODO: Add more valid neighbour functions.
|
||||
-- TODO: Write docs.
|
||||
-- DONE: Add pathlines for seach/valid neighbours.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -247,10 +244,7 @@ end
|
||||
function ASTAR:AddNode(Node)
|
||||
|
||||
self.nodes[Node.id]=Node
|
||||
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))
|
||||
self.Nnodes=self.Nnodes+1
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -268,47 +262,6 @@ function ASTAR:AddNodeFromCoordinate(Coordinate)
|
||||
return node
|
||||
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.
|
||||
-- @param #ASTAR self
|
||||
-- @param #ASTAR.Node Node The node to be added.
|
||||
@@ -387,18 +340,6 @@ function ASTAR:SetValidNeighbourRoad(MaxDistance)
|
||||
return self
|
||||
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.
|
||||
-- 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.
|
||||
@@ -443,7 +384,7 @@ end
|
||||
-- @return #ASTAR self
|
||||
function ASTAR:SetCostRoad()
|
||||
|
||||
self:SetCostFunction(ASTAR.Road)
|
||||
self:SetCostFunction(ASTAR)
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -603,55 +544,6 @@ function ASTAR.Road(nodeA, nodeB)
|
||||
|
||||
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.
|
||||
-- @param #ASTAR.Node nodeA First node.
|
||||
-- @param #ASTAR.Node nodeB Other node.
|
||||
@@ -675,9 +567,7 @@ end
|
||||
-- @param #ASTAR.Node nodeB Other node.
|
||||
-- @return #number Distance between the two nodes.
|
||||
function ASTAR.Dist2D(nodeA, 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)
|
||||
local dist=nodeA.coordinate:Get2DDistance(nodeB)
|
||||
return dist
|
||||
end
|
||||
|
||||
@@ -704,7 +594,7 @@ function ASTAR.DistRoad(nodeA, nodeB)
|
||||
local dist=0
|
||||
|
||||
for i=2,#path do
|
||||
local b=path[i] --DCS#Vec2
|
||||
local b=path[i] --DCS#Vec2
|
||||
local a=path[i-1] --DCS#Vec2
|
||||
|
||||
dist=dist+UTILS.VecDist2D(a,b)
|
||||
@@ -714,6 +604,7 @@ function ASTAR.DistRoad(nodeA, nodeB)
|
||||
return dist
|
||||
end
|
||||
|
||||
|
||||
return math.huge
|
||||
end
|
||||
|
||||
@@ -723,11 +614,10 @@ end
|
||||
|
||||
--- Find the closest node from a given coordinate.
|
||||
-- @param #ASTAR self
|
||||
-- @param Core.Point#COORDINATE Coordinate Reference coordinate.
|
||||
-- @param #table ExcludeNodes Table of nodes that are excluded.
|
||||
-- @return #ASTAR.Node Closest node to the coordinate.
|
||||
-- @param Core.Point#COORDINATE Coordinate.
|
||||
-- @return #ASTAR.Node Cloest node to the coordinate.
|
||||
-- @return #number Distance to closest node in meters.
|
||||
function ASTAR:FindClosestNode(Coordinate, ExcludeNodes)
|
||||
function ASTAR:FindClosestNode(Coordinate)
|
||||
|
||||
local distMin=math.huge
|
||||
local closeNode=nil
|
||||
@@ -735,15 +625,11 @@ function ASTAR:FindClosestNode(Coordinate, ExcludeNodes)
|
||||
for _,_node in pairs(self.nodes) do
|
||||
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
|
||||
distMin=dist
|
||||
closeNode=node
|
||||
end
|
||||
|
||||
if dist<distMin then
|
||||
distMin=dist
|
||||
closeNode=node
|
||||
end
|
||||
|
||||
end
|
||||
@@ -751,162 +637,38 @@ function ASTAR:FindClosestNode(Coordinate, ExcludeNodes)
|
||||
return closeNode, distMin
|
||||
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.
|
||||
-- @param #ASTAR self
|
||||
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
||||
-- @return #ASTAR self
|
||||
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)
|
||||
|
||||
-- Find the closest node to the given start coordinate.
|
||||
local node, dist2=self:FindClosestNode(self.startCoord)
|
||||
self.startNode=node
|
||||
|
||||
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))
|
||||
if dist>1000 then
|
||||
self:T(self.lid.."Adding start node to node grid!")
|
||||
self:AddNode(node)
|
||||
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
|
||||
end
|
||||
|
||||
--- Find the end node.
|
||||
--- Add a node.
|
||||
-- @param #ASTAR self
|
||||
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
||||
-- @return #ASTAR self
|
||||
function ASTAR:FindEndNode()
|
||||
|
||||
local pathline, dist, vec3, s=self:FindClosestPathline(self.endCoord)
|
||||
|
||||
-- Find the closest node to the given start coordinate.
|
||||
local node, dist2=self:FindClosestNode(self.endCoord)
|
||||
|
||||
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 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))
|
||||
local node, dist=self:FindClosestNode(self.endCoord)
|
||||
|
||||
self.endNode=node
|
||||
|
||||
if dist>1000 then
|
||||
self:T(self.lid.."Adding end node to node grid!")
|
||||
self:AddNode(node)
|
||||
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
|
||||
end
|
||||
@@ -922,21 +684,12 @@ end
|
||||
-- @return #table Table of nodes from start to finish.
|
||||
function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||
|
||||
-- self:FindStartNode()
|
||||
-- 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})
|
||||
self:FindStartNode()
|
||||
self:FindEndNode()
|
||||
|
||||
local nodes=self.nodes
|
||||
local start=self.startNode
|
||||
local goal=self.endNode
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("GetPath Start Node=%d, End Node=%d", start.id, goal.id))
|
||||
|
||||
-- Sets.
|
||||
local openset = {}
|
||||
@@ -993,12 +746,7 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||
text=text..string.format(", OS Time %.6f sec", dT)
|
||||
end
|
||||
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("\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
|
||||
text=text..string.format(", Ncost=%d [%d cached]", self.ncost, self.ncostcache)
|
||||
self:T(self.lid..text)
|
||||
|
||||
return path
|
||||
@@ -1011,16 +759,13 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||
|
||||
-- Get neighbour nodes.
|
||||
local neighbors=self:_NeighbourNodes(current, nodes)
|
||||
|
||||
|
||||
-- Loop over neighbours.
|
||||
for _,neighbor in pairs(neighbors) do
|
||||
|
||||
-- Node is not in closed set.
|
||||
if self:_NotIn(closedset, neighbor.id) then
|
||||
|
||||
-- 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)
|
||||
local tentative_g_score=g_score[current.id]+self:_DistNodes(current, neighbor)
|
||||
|
||||
if self:_NotIn(openset, neighbor.id) or tentative_g_score < g_score[neighbor.id] then
|
||||
|
||||
@@ -1048,73 +793,6 @@ function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||
return nil -- no valid path
|
||||
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
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1133,18 +811,16 @@ function ASTAR:_HeuristicCost(nodeA, nodeB)
|
||||
local cost=nodeA.cost[nodeB.id]
|
||||
if cost~=nil then
|
||||
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
|
||||
end
|
||||
|
||||
local cost=nil
|
||||
if self.CostFunc then
|
||||
cost=self.CostFunc(nodeA, nodeB, unpack(self.CostArg))
|
||||
else
|
||||
cost=self:_DistNodes(nodeA, nodeB)
|
||||
end
|
||||
|
||||
self:T(self.lid..string.format("Cost nodeA=%d --> nodeB=%d = %.1f", nodeA.id, nodeB.id, cost))
|
||||
|
||||
nodeA.cost[nodeB.id]=cost
|
||||
nodeB.cost[nodeA.id]=cost -- Symmetric problem.
|
||||
|
||||
@@ -1158,10 +834,9 @@ end
|
||||
-- @return #boolean If true, transition between nodes is possible.
|
||||
function ASTAR:_IsValidNeighbour(node, neighbor)
|
||||
|
||||
-- Counter of function calls.
|
||||
-- Counter.
|
||||
self.nvalid=self.nvalid+1
|
||||
|
||||
-- Check if neighbour is in cached set.
|
||||
local valid=node.valid[neighbor.id]
|
||||
if valid~=nil then
|
||||
--env.info(string.format("Node %d has valid=%s neighbour %d", node.id, tostring(valid), neighbor.id))
|
||||
@@ -1169,16 +844,13 @@ function ASTAR:_IsValidNeighbour(node, neighbor)
|
||||
return valid
|
||||
end
|
||||
|
||||
-- Check if this is a valid neighbour.
|
||||
local valid=nil
|
||||
if self.ValidNeighbourFunc then
|
||||
valid=self.ValidNeighbourFunc(node, neighbor, unpack(self.ValidNeighbourArg))
|
||||
else
|
||||
-- If no valid neighbour function is defined, we assume all nodes are valid neighbours.
|
||||
valid=true
|
||||
end
|
||||
|
||||
-- Cache valid neighbour.
|
||||
node.valid[neighbor.id]=valid
|
||||
neighbor.valid[node.id]=valid -- Symmetric problem.
|
||||
|
||||
@@ -1212,9 +884,6 @@ function ASTAR:_LowestFscore(set, f_score)
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Lowest Fscore=%.1f, Node=%s", lowest, tostring(bestNode)))
|
||||
|
||||
return self.nodes[bestNode]
|
||||
end
|
||||
|
||||
@@ -1259,46 +928,16 @@ end
|
||||
-- @param #table map Map.
|
||||
-- @param #ASTAR.Node current_node The current node.
|
||||
-- @return #table Unwinded path.
|
||||
function ASTAR:_UnwindPath(flat_path, map, current_node)
|
||||
function ASTAR:_UnwindPath( flat_path, map, current_node )
|
||||
|
||||
local previous_node=map[current_node]
|
||||
|
||||
if previous_node then
|
||||
table.insert(flat_path, 1, previous_node)
|
||||
return self:_UnwindPath(flat_path, map, previous_node)
|
||||
if map [current_node] then
|
||||
table.insert (flat_path, 1, map[current_node])
|
||||
return self:_UnwindPath(flat_path, map, map[current_node])
|
||||
else
|
||||
-- No previous node ==> return path.
|
||||
return flat_path
|
||||
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 #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 #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||
-- @param ... 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.
|
||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||
|
||||
|
||||
@@ -872,6 +872,8 @@ end
|
||||
-- @return Wrapper.Group#GROUP The found GROUP.
|
||||
function DATABASE:FindGroup( GroupName )
|
||||
|
||||
if type(GroupName) ~= "string" or GroupName == "" then return end
|
||||
|
||||
local GroupFound = self.GROUPS[GroupName]
|
||||
|
||||
if GroupFound == nil and GroupName ~= nil and self.Templates.Groups[GroupName] == nil then
|
||||
@@ -1110,7 +1112,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
else
|
||||
self.STNS[stn] = UnitTemplate.name
|
||||
self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
self:T("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for ".. UnitTemplate.name)
|
||||
end
|
||||
end
|
||||
if UnitTemplate.AddPropAircraft.SADL_TN then
|
||||
@@ -1119,7 +1121,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
|
||||
self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
else
|
||||
self.SADL[sadl] = UnitTemplate.name
|
||||
self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
self:T("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for ".. UnitTemplate.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1380,7 +1382,7 @@ function DATABASE:GetCoalitionFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CoalitionID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1392,7 +1394,7 @@ function DATABASE:GetCategoryFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CategoryID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1404,7 +1406,7 @@ function DATABASE:GetCountryFromClientTemplate( ClientName )
|
||||
if self.Templates.ClientsByName[ClientName] then
|
||||
return self.Templates.ClientsByName[ClientName].CountryID
|
||||
end
|
||||
self:E("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
self:T("WARNING: Template does not exist for client "..tostring(ClientName))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1697,7 +1699,7 @@ function DATABASE:_EventOnBirth( Event )
|
||||
if PlayerName then
|
||||
|
||||
-- Debug info.
|
||||
self:I(string.format("Player '%s' joined unit '%s' of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniDCSGroupName)))
|
||||
self:I(string.format("Player '%s' joined unit '%s' (%s) of group '%s'", tostring(PlayerName), tostring(Event.IniDCSUnitName), tostring(Event.IniTypeName), tostring(Event.IniDCSGroupName)))
|
||||
|
||||
-- Add client in case it does not exist already.
|
||||
if client == nil or (client and client:CountPlayers() == 0) then
|
||||
|
||||
@@ -50,7 +50,7 @@ MARKEROPS_BASE = {
|
||||
ClassName = "MARKEROPS",
|
||||
Tag = "mytag",
|
||||
Keywords = {},
|
||||
version = "0.1.3",
|
||||
version = "0.1.4",
|
||||
debug = false,
|
||||
Casesensitive = true,
|
||||
}
|
||||
@@ -154,14 +154,7 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
||||
return true
|
||||
end
|
||||
--position
|
||||
local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}
|
||||
local coord=COORDINATE:NewFromVec3(vec3)
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
|
||||
local coalition = Event.MarkCoalition
|
||||
-- decision
|
||||
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||
@@ -170,8 +163,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||
@@ -180,8 +179,14 @@ function MARKEROPS_BASE:OnEventMark(Event)
|
||||
local Eventtext = tostring(Event.text)
|
||||
if Eventtext~=nil then
|
||||
if self:_MatchTag(Eventtext) then
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
local coord=COORDINATE:NewFromVec3({y=Event.pos.y, x=Event.pos.x, z=Event.pos.z})
|
||||
if self.debug then
|
||||
local coordtext = coord:ToStringLLDDM()
|
||||
local text = tostring(Event.text)
|
||||
local m = MESSAGE:New(string.format("Mark changed at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||
end
|
||||
local matchtable = self:_MatchKeywords(Eventtext)
|
||||
self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition,Event.PlayerName,Event)
|
||||
end
|
||||
end
|
||||
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||
|
||||
@@ -206,7 +206,7 @@ end
|
||||
function MESSAGE:ToGroup( Group, Settings )
|
||||
self:F( Group.GroupName )
|
||||
|
||||
if Group then
|
||||
if Group and Group:IsAlive() then
|
||||
|
||||
if self.MessageType then
|
||||
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 )
|
||||
self:F( Unit.IdentifiableName )
|
||||
|
||||
if Unit then
|
||||
if Unit and Unit:IsAlive() then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
@@ -452,7 +452,7 @@ end
|
||||
_MESSAGESRS = {}
|
||||
|
||||
--- Set up MESSAGE generally to allow Text-To-Speech via SRS and TTS functions. `SetMSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||
-- @param #string PathToSRS (optional) Path to SRS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone" or your configuration file setting.
|
||||
-- @param #string PathToSRS (optional) Path to SRS TTS Folder, defaults to "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio" or your configuration file setting.
|
||||
-- @param #number Port Port (optional) number of SRS, defaults to 5002 or your configuration file setting.
|
||||
-- @param #string PathToCredentials (optional) Path to credentials file for Google.
|
||||
-- @param #number Frequency Frequency in MHz. Can also be given as a #table of frequencies.
|
||||
@@ -468,13 +468,13 @@ _MESSAGESRS = {}
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
function MESSAGE.SetMSRS(PathToSRS,Port,PathToCredentials,Frequency,Modulation,Gender,Culture,Voice,Coalition,Volume,Label,Coordinate,Backend)
|
||||
|
||||
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
_MESSAGESRS.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
|
||||
_MESSAGESRS.frequency = Frequency or MSRS.frequencies or 243
|
||||
_MESSAGESRS.modulation = Modulation or MSRS.modulations or radio.modulation.AM
|
||||
@@ -535,7 +535,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRS()
|
||||
--
|
||||
@@ -567,7 +567,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.BLUE)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSBlue()
|
||||
--
|
||||
@@ -589,7 +589,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.RED)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSRed()
|
||||
--
|
||||
@@ -611,7 +611,7 @@ end
|
||||
-- @usage
|
||||
-- -- Mind the dot here, not using the colon this time around!
|
||||
-- -- Needed once only
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
||||
-- MESSAGE.SetMSRS("D:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",5012,nil,127,radio.modulation.FM,"female","en-US",nil,coalition.side.NEUTRAL)
|
||||
-- -- later on in your code
|
||||
-- MESSAGE:New("Test message!",15,"SPAWN"):ToSRSAll()
|
||||
--
|
||||
|
||||
@@ -5,13 +5,11 @@
|
||||
-- * Path from A to B
|
||||
-- * Arbitrary number of points
|
||||
-- * Automatically from lines drawtool
|
||||
-- * Draw line or mark points on F10 map
|
||||
-- * Find closest points to path
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
-- @module Core.Pathline
|
||||
-- @image CORE_Pathline.png
|
||||
@@ -23,7 +21,6 @@
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #string name Name of the path line.
|
||||
-- @field #table points List of 3D points defining the path.
|
||||
-- @field #number counter Running number counting the point IDs.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *The shortest distance between two points is a straight line.* -- Archimedes
|
||||
@@ -31,30 +28,30 @@
|
||||
-- ===
|
||||
--
|
||||
-- # The PATHLINE Concept
|
||||
--
|
||||
--
|
||||
-- List of points defining a path from A to B. The pathline can consist of multiple points. Each point holds the information of its position, the surface type, the land height
|
||||
-- and the water depth (if over sea).
|
||||
--
|
||||
--
|
||||
-- Line drawings created in the mission editor are automatically registered as pathlines and stored in the MOOSE database.
|
||||
-- They can be accessed with the @{#PATHLINE.FindByName) function.
|
||||
--
|
||||
--
|
||||
-- # Constructor
|
||||
--
|
||||
--
|
||||
-- The @{PATHLINE.New) function creates a new PATHLINE object. This does not hold any points. Points can be added with the @{#PATHLINE.AddPointFromVec2} and @{#PATHLINE.AddPointFromVec3}
|
||||
--
|
||||
--
|
||||
-- For a given table of 2D or 3D positions, a new PATHLINE object can be created with the @{#PATHLINE.NewFromVec2Array} or @{#PATHLINE.NewFromVec3Array}, respectively.
|
||||
--
|
||||
--
|
||||
-- # Line Drawings
|
||||
--
|
||||
--
|
||||
-- The most convenient way to create a pathline is the draw panel feature in the DCS mission editor. You can select "Line" and then "Segments", "Segment" or "Free" to draw your lines.
|
||||
-- These line drawings are then automatically added to the MOOSE database as PATHLINE objects and can be retrieved with the @{#PATHLINE.FindByName) function, where the name is the one
|
||||
-- you specify in the draw panel.
|
||||
--
|
||||
--
|
||||
-- # Mark on F10 map
|
||||
--
|
||||
-- The ponints of the PATHLINE can be marked on the F10 map with the @{#PATHLINE.MarkPoints}(`true`) function. The mark points contain information of the surface type, land height and
|
||||
--
|
||||
-- The ponints of the PATHLINE can be marked on the F10 map with the @{#PATHLINE.MarkPoints}(`true`) function. The mark points contain information of the surface type, land height and
|
||||
-- water depth.
|
||||
--
|
||||
--
|
||||
-- To remove the marks, use @{#PATHLINE.MarkPoints}(`false`).
|
||||
--
|
||||
-- @field #PATHLINE
|
||||
@@ -62,39 +59,27 @@ PATHLINE = {
|
||||
ClassName = "PATHLINE",
|
||||
lid = nil,
|
||||
points = {},
|
||||
counter = 0,
|
||||
}
|
||||
|
||||
--- Point of line.
|
||||
-- @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#Vec2 vec2 2D position.
|
||||
-- @field #number surfaceType Surface type.
|
||||
-- @field #number landHeight Land height in meters.
|
||||
-- @field #number depth Water depth in meters.
|
||||
-- @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.
|
||||
-- @field #string version
|
||||
PATHLINE.version="0.3.0"
|
||||
PATHLINE.version="0.1.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Read/write to JSON file
|
||||
-- TODO: Translate/rotate pathline
|
||||
-- TODO: Add color.
|
||||
-- TODO: A lot...
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
@@ -108,10 +93,10 @@ function PATHLINE:New(Name)
|
||||
|
||||
-- Inherit everything from INTEL class.
|
||||
local self=BASE:Inherit(self, BASE:New()) --#PATHLINE
|
||||
|
||||
|
||||
self.name=Name or "Unknown Path"
|
||||
|
||||
self.lid=string.format("PATHLINE %s | ", self.name)
|
||||
self.lid=string.format("PATHLINE %s | ", Name)
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -166,70 +151,41 @@ end
|
||||
--- Add a point to the path from a given 2D position. The third dimension is determined from the land height.
|
||||
-- @param #PATHLINE self
|
||||
-- @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
|
||||
function PATHLINE:AddPointFromVec2(Vec2, Index, Point)
|
||||
function PATHLINE:AddPointFromVec2(Vec2)
|
||||
|
||||
if Vec2 then
|
||||
|
||||
-- Create a new point.
|
||||
|
||||
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)
|
||||
end
|
||||
end
|
||||
table.insert(self.points, point)
|
||||
|
||||
end
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a point to the path from a given 3D position.
|
||||
-- @param #PATHLINE self
|
||||
-- @param DCS#Vec3 Vec3 The 3D 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.Point Point that was added.
|
||||
function PATHLINE:AddPointFromVec3(Vec3, Index, Point)
|
||||
-- @return #PATHLINE self
|
||||
function PATHLINE:AddPointFromVec3(Vec3)
|
||||
|
||||
if Vec3 then
|
||||
|
||||
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
return point
|
||||
table.insert(self.points, point)
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get name of pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @return #string Name of the pathline.
|
||||
function PATHLINE:GetName()
|
||||
function PATHLINE:GetName()
|
||||
return self.name
|
||||
end
|
||||
|
||||
@@ -243,35 +199,18 @@ 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.
|
||||
-- @param #PATHLINE self
|
||||
-- @return #list <Core.Pathline#PATHLINE.Point> List of points.
|
||||
function PATHLINE:GetPoints()
|
||||
-- @return #list <#PATHLINE.Point> List of points.
|
||||
function PATHLINE:GetPoints()
|
||||
return self.points
|
||||
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.
|
||||
-- @param #PATHLINE self
|
||||
-- @return #list <DCS#Vec3> List of DCS#Vec3 points.
|
||||
-- @return <DCS#Vec3> List of DCS#Vec3 points.
|
||||
function PATHLINE:GetPoints3D()
|
||||
|
||||
local vecs={}
|
||||
|
||||
|
||||
for _,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
table.insert(vecs, point.vec3)
|
||||
@@ -282,11 +221,11 @@ end
|
||||
|
||||
--- Get 2D points of pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @return #list <DCS#Vec2> List of DCS#Vec2 points.
|
||||
-- @return <DCS#Vec2> List of DCS#Vec2 points.
|
||||
function PATHLINE:GetPoints2D()
|
||||
|
||||
local vecs={}
|
||||
|
||||
|
||||
for _,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
table.insert(vecs, point.vec2)
|
||||
@@ -301,11 +240,11 @@ end
|
||||
function PATHLINE:GetCoordinates()
|
||||
|
||||
local vecs={}
|
||||
|
||||
|
||||
for _,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
local coord=COORDINATE:NewFromVec3(point.vec3)
|
||||
table.insert(vecs, coord)
|
||||
table.insert(vecs,coord)
|
||||
end
|
||||
|
||||
return vecs
|
||||
@@ -318,11 +257,11 @@ end
|
||||
function PATHLINE:GetPointFromIndex(n)
|
||||
|
||||
local N=self:GetNumberOfPoints()
|
||||
|
||||
|
||||
n=n or 1
|
||||
|
||||
local point=nil --#PATHLINE.Point
|
||||
|
||||
|
||||
if n>=1 and n<=N then
|
||||
point=self.points[n]
|
||||
else
|
||||
@@ -339,11 +278,11 @@ end
|
||||
function PATHLINE:GetPoint3DFromIndex(n)
|
||||
|
||||
local point=self:GetPointFromIndex(n)
|
||||
|
||||
|
||||
if point then
|
||||
return point.vec3
|
||||
end
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -354,11 +293,11 @@ end
|
||||
function PATHLINE:GetPoint2DFromIndex(n)
|
||||
|
||||
local point=self:GetPointFromIndex(n)
|
||||
|
||||
|
||||
if point then
|
||||
return point.vec2
|
||||
end
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -366,314 +305,33 @@ end
|
||||
--- Mark points on F10 map.
|
||||
-- @param #PATHLINE self
|
||||
-- @param #boolean Switch If `true` or nil, set marks. If `false`, remove marks.
|
||||
-- @return #PATHLINE self
|
||||
-- @return <DCS#Vec3> List of DCS#Vec3 points.
|
||||
function PATHLINE:MarkPoints(Switch)
|
||||
|
||||
for i,_point in pairs(self.points) do
|
||||
local point=_point --#PATHLINE.Point
|
||||
|
||||
if Switch==false then
|
||||
|
||||
|
||||
if point.markerID then
|
||||
UTILS.RemoveMark(point.markerID)
|
||||
UTILS.RemoveMark(point.markerID, Delay)
|
||||
end
|
||||
|
||||
|
||||
else
|
||||
|
||||
|
||||
if point.markerID then
|
||||
UTILS.RemoveMark(point.markerID)
|
||||
end
|
||||
|
||||
|
||||
point.markerID=UTILS.GetMarkID()
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
trigger.action.markToAll(point.markerID, text, point.vec3, "")
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
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
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -681,56 +339,32 @@ end
|
||||
--- Get 3D points of pathline.
|
||||
-- @param #PATHLINE self
|
||||
-- @param DCS#Vec3 Vec Position vector. Can also be a DCS#Vec2 in which case the altitude at landheight is taken.
|
||||
-- @return #PATHLINE.Point Pathline Point.
|
||||
-- @return #PATHLINE.Point
|
||||
function PATHLINE:_CreatePoint(Vec)
|
||||
|
||||
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
|
||||
-- Given vec is 3D
|
||||
point.vec3=UTILS.DeepCopy(Vec)
|
||||
point.vec2={x=Vec.x, y=Vec.z}
|
||||
else
|
||||
-- Given vec is 2D
|
||||
-- Given vec is 2D
|
||||
point.vec2=UTILS.DeepCopy(Vec)
|
||||
point.vec3={x=Vec.x, y=land.getHeight(Vec), z=Vec.y}
|
||||
end
|
||||
|
||||
-- Get surface type.
|
||||
point.surfaceType=land.getSurfaceType(point.vec2)
|
||||
|
||||
|
||||
-- Get land height and depth.
|
||||
point.landHeight, point.depth=land.getSurfaceHeightWithSeabed(point.vec2)
|
||||
|
||||
|
||||
point.markerID=nil
|
||||
|
||||
return point
|
||||
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
|
||||
|
||||
---
|
||||
--- Coordinate class
|
||||
-- @type COORDINATE
|
||||
-- @field #string ClassName Name of the class
|
||||
-- @field #number x Component of the 3D vector.
|
||||
@@ -59,6 +59,10 @@ do -- COORDINATE
|
||||
-- * @{#COORDINATE.SmokeOrange}(): To smoke the point in orange.
|
||||
-- * @{#COORDINATE.SmokeWhite}(): To smoke the point in white.
|
||||
-- * @{#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
|
||||
--
|
||||
@@ -453,23 +457,6 @@ do -- COORDINATE
|
||||
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.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE Coordinate
|
||||
@@ -678,7 +665,7 @@ do -- COORDINATE
|
||||
local _,_,_,_,_,scenerys=self:ScanObjects(radius, false, false, true)
|
||||
|
||||
local set={}
|
||||
|
||||
|
||||
for _,_scenery in pairs(scenerys) do
|
||||
local scenery=_scenery --DCS#Object
|
||||
|
||||
@@ -850,6 +837,26 @@ do -- COORDINATE
|
||||
return land.getHeight( Vec2 )
|
||||
end
|
||||
|
||||
--- Returns a table of DCS#Vec3 points representing the terrain profile between two points.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Destination DCS#Vec3 Ending point of the profile.
|
||||
-- @return #table DCS#Vec3 table of the profile
|
||||
function COORDINATE:GetLandProfileVec3(Destination)
|
||||
return land.profile(self:GetVec3(), Destination)
|
||||
end
|
||||
|
||||
--- Returns a table of #COORDINATE representing the terrain profile between two points.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Destination #COORDINATE Ending coordinate of the profile.
|
||||
-- @return #table #COORDINATE table of the profile
|
||||
function COORDINATE:GetLandProfileCoordinates(Destination)
|
||||
local points = self:GetLandProfileVec3(Destination:GetVec3())
|
||||
local coords = {}
|
||||
for _, point in ipairs(points) do
|
||||
table.insert(coords, COORDINATE:NewFromVec3(point))
|
||||
end
|
||||
return coords
|
||||
end
|
||||
|
||||
--- Set the heading of the coordinate, if applicable.
|
||||
-- @param #COORDINATE self
|
||||
@@ -2135,14 +2142,112 @@ do -- COORDINATE
|
||||
end
|
||||
|
||||
|
||||
--- Smokes the point in a color.
|
||||
--- 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.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Utilities.Utils#SMOKECOLOR SmokeColor
|
||||
-- @param #string name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
||||
function COORDINATE:Smoke( SmokeColor, name )
|
||||
self:F2( { SmokeColor } )
|
||||
self.firename = name or "Smoke-"..math.random(1,100000)
|
||||
trigger.action.smoke( self:GetVec3(), SmokeColor, self.firename )
|
||||
-- @param #number SmokeColor Color of smoke, e.g. `SMOKECOLOR.Green` for green smoke.
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @param #string Name (Optional) Name if you want to stop the smoke early (normal duration: 5mins)
|
||||
-- @param #boolean Offset (Optional) If true, offset the smokle a bit.
|
||||
-- @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 )
|
||||
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.
|
||||
@@ -2154,49 +2259,83 @@ do -- COORDINATE
|
||||
|
||||
--- Smoke the COORDINATE Green.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeGreen()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Green )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeGreen(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Green, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE Red.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeRed()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Red )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeRed(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Red, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE White.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeWhite()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.White )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeWhite(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.White, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE Orange.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeOrange()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Orange )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeOrange(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Orange, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Smoke the COORDINATE Blue.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SmokeBlue()
|
||||
self:F2()
|
||||
self:Smoke( SMOKECOLOR.Blue )
|
||||
-- @param #number Duration (Optional) Duration of the smoke in seconds. DCS stopps the smoke automatically after 5 min.
|
||||
-- @param #number Delay (Optional) Delay before the smoke is started in seconds.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:SmokeBlue(Duration, Delay)
|
||||
self:Smoke( SMOKECOLOR.Blue, Duration, Delay )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Big smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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 #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.
|
||||
function COORDINATE:BigSmokeAndFire( preset, density, name )
|
||||
self:F2( { preset=preset, density=density } )
|
||||
density=density or 0.5
|
||||
self.firename = name or "Fire-"..math.random(1,10000)
|
||||
trigger.action.effectSmokeBig( self:GetVec3(), preset, density, self.firename )
|
||||
-- @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 #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 #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.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFire( Preset, Density, Duration, Delay, Name )
|
||||
self:F2( { preset=Preset, density=Density } )
|
||||
|
||||
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
|
||||
|
||||
--- Stop big smoke and fire at the coordinate.
|
||||
@@ -2209,82 +2348,98 @@ do -- COORDINATE
|
||||
|
||||
--- Small smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number density (Optional) Smoke density. Number between 0 and 1. Default 0.5.
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeAndFireSmall( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, density, name)
|
||||
-- @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.
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireSmall( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Medium smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeAndFireMedium( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireMedium( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Large smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeAndFireLarge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireLarge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Huge smoke and fire at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeAndFireHuge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeAndFireHuge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmokeAndFire, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Small smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeSmall( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeSmall( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.SmallSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Medium smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeMedium( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, density, name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeMedium( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.MediumSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Large smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeLarge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, density,name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeLarge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.LargeSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Huge smoke at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @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.
|
||||
function COORDINATE:BigSmokeHuge( density, name )
|
||||
self:F2( { density=density } )
|
||||
density=density or 0.5
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, density,name)
|
||||
-- @return #COORDINATE self
|
||||
function COORDINATE:BigSmokeHuge( Density, Duration, Delay, Name )
|
||||
self:BigSmokeAndFire(BIGSMOKEPRESET.HugeSmoke, Density, Duration, Delay, Name)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Flares the point in a color.
|
||||
@@ -2938,8 +3093,10 @@ do -- COORDINATE
|
||||
local sunrise=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, true, Tdiff)
|
||||
local sunset=UTILS.GetSunRiseAndSet(DayOfYear, Latitude, Longitude, false, Tdiff)
|
||||
|
||||
if sunrise == "N/R" then return false end
|
||||
if sunrise == "N/S" then return true end
|
||||
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
|
||||
|
||||
local time=UTILS.ClockToSeconds(clock)
|
||||
|
||||
@@ -2957,6 +3114,11 @@ do -- COORDINATE
|
||||
|
||||
-- Todays sun set in sec.
|
||||
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.
|
||||
local time=UTILS.SecondsOfToday()
|
||||
@@ -3655,7 +3817,26 @@ do -- COORDINATE
|
||||
function COORDINATE:GetRandomPointVec3InRadius( OuterRadius, InnerRadius )
|
||||
return COORDINATE:NewFromVec3( self:GetRandomVec3InRadius( OuterRadius, InnerRadius ) )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Search for clear zones in a given area. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #number SearchRadius Radius of the search area.
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of Core.Point#COORDINATE that are clear of map objects within the given PosRadius. nil if no positions are found.
|
||||
function COORDINATE:GetSimpleZones(SearchRadius, PosRadius, NumPositions)
|
||||
local clearPositions = UTILS.GetSimpleZones(self:GetVec3(), SearchRadius, PosRadius, NumPositions)
|
||||
if clearPositions and #clearPositions > 0 then
|
||||
local coords = {}
|
||||
for _, pos in pairs(clearPositions) do
|
||||
local coord = COORDINATE:NewFromVec2(pos)
|
||||
table.insert(coords, coord)
|
||||
end
|
||||
return coords
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
@@ -175,7 +175,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
local Name = Info.name or "?"
|
||||
|
||||
local ErrorHandler = function( errmsg )
|
||||
env.info( "Error in timer function: " .. errmsg )
|
||||
env.info( "Error in timer function: " .. errmsg or "" )
|
||||
if BASE.Debug ~= nil then
|
||||
env.info( BASE.Debug.traceback() )
|
||||
end
|
||||
@@ -326,7 +326,7 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||
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.
|
||||
if Schedule.ScheduleID then
|
||||
if Schedule and Schedule.ScheduleID then
|
||||
|
||||
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
||||
|
||||
|
||||
@@ -958,7 +958,26 @@ do -- SET_BASE
|
||||
|
||||
return ObjectNames
|
||||
end
|
||||
|
||||
--- Get a *new* set table that only contains alive objects.
|
||||
-- @param #SET_BASE self
|
||||
-- @return #table Set table of alive objects.
|
||||
function SET_BASE:GetAliveSet()
|
||||
--self:F2()
|
||||
|
||||
local AliveSet = {}
|
||||
-- Clean the Set before returning with only the alive Objects.
|
||||
for ObjectName, Object in pairs( self.Set ) do
|
||||
if Object then
|
||||
if Object:IsAlive() then
|
||||
AliveSet[#AliveSet+1] = Object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return AliveSet or {}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do
|
||||
@@ -1125,25 +1144,25 @@ do
|
||||
|
||||
end
|
||||
|
||||
--- Get a *new* set that only contains alive groups.
|
||||
--- Get a *new* set table that only contains alive groups.
|
||||
-- @param #SET_GROUP self
|
||||
-- @return #SET_GROUP Set of alive groups.
|
||||
-- @return #table Set of alive groups.
|
||||
function SET_GROUP:GetAliveSet()
|
||||
--self:F2()
|
||||
|
||||
local AliveSet = SET_GROUP:New()
|
||||
|
||||
--local AliveSet = SET_GROUP:New()
|
||||
local AliveSet = {}
|
||||
-- Clean the Set before returning with only the alive Groups.
|
||||
for GroupName, GroupObject in pairs( self.Set ) do
|
||||
local GroupObject = GroupObject -- Wrapper.Group#GROUP
|
||||
if GroupObject then
|
||||
if GroupObject:IsAlive() then
|
||||
AliveSet:Add( GroupName, GroupObject )
|
||||
AliveSet[GroupName] = GroupObject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return AliveSet.Set or {}
|
||||
return AliveSet or {}
|
||||
end
|
||||
|
||||
--- Returns a report of of unit types.
|
||||
@@ -2595,18 +2614,16 @@ do -- SET_UNIT
|
||||
|
||||
--- Gets the alive set.
|
||||
-- @param #SET_UNIT self
|
||||
-- @return #table Table of SET objects
|
||||
-- @return #table Table of alive UNIT objects
|
||||
-- @return #SET_UNIT AliveSet
|
||||
function SET_UNIT:GetAliveSet()
|
||||
|
||||
local AliveSet = SET_UNIT:New()
|
||||
|
||||
-- Clean the Set before returning with only the alive Groups.
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
||||
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
if GroupObject and GroupObject:IsAlive() then
|
||||
AliveSet:Add(GroupName, GroupObject)
|
||||
AliveSet[GroupName] = GroupObject
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4784,18 +4801,16 @@ do -- SET_CLIENT
|
||||
-- @return #table Table of SET objects
|
||||
function SET_CLIENT:GetAliveSet()
|
||||
|
||||
local AliveSet = SET_CLIENT:New()
|
||||
local AliveSet = {}
|
||||
|
||||
-- Clean the Set before returning with only the alive Groups.
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
||||
|
||||
for GroupName, GroupObject in pairs(self.Set) do
|
||||
if GroupObject and GroupObject:IsAlive() then
|
||||
AliveSet:Add(GroupName, GroupObject)
|
||||
AliveSet[GroupName] = GroupObject
|
||||
end
|
||||
end
|
||||
|
||||
return AliveSet.Set or {}
|
||||
return AliveSet or {}
|
||||
end
|
||||
|
||||
--- [User] Add a custom condition function.
|
||||
|
||||
@@ -149,6 +149,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
||||
self.CategoryID = CategoryID
|
||||
self.CoalitionID = CoalitionID
|
||||
self.SpawnIndex = 0
|
||||
self.StaticCopyFrom = SpawnTemplateName
|
||||
else
|
||||
error( "SPAWNSTATIC:New: There is no static declared in the mission editor with SpawnTemplatePrefix = '" .. tostring(SpawnTemplateName) .. "'" )
|
||||
end
|
||||
@@ -302,12 +303,16 @@ end
|
||||
-- @param #number CallsignID Callsign ID. Default 1 (="London").
|
||||
-- @param #number Frequency Frequency in MHz. Default 127.5 MHz.
|
||||
-- @param #number Modulation Modulation 0=AM, 1=FM.
|
||||
-- @param #boolean DynamicSpawns If true, allow Dynamic Spawns
|
||||
-- @param #boolean DynamicHotStarts If true, and DynamicSpawns is true, then allow Dynamic Spawns with hot starts.
|
||||
-- @return #SPAWNSTATIC self
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation)
|
||||
function SPAWNSTATIC:InitFARP(CallsignID, Frequency, Modulation, DynamicSpawns,DynamicHotStarts)
|
||||
self.InitFarp=true
|
||||
self.InitFarpCallsignID=CallsignID or 1
|
||||
self.InitFarpFreq=Frequency or 127.5
|
||||
self.InitFarpModu=Modulation or 0
|
||||
self.InitFarpDynamicSpawns = DynamicSpawns
|
||||
self.InitFarpDynamicHotStarts = (DynamicSpawns == true and DynamicHotStarts == true) and true or nil
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -459,8 +464,9 @@ end
|
||||
function SPAWNSTATIC:SpawnFromZone(Zone, Heading, NewName)
|
||||
|
||||
-- Spawn the new static at the center of the zone.
|
||||
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||
|
||||
--local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
|
||||
local Static = self:SpawnFromCoordinate(Zone:GetCoordinate(), Heading, NewName)
|
||||
|
||||
return Static
|
||||
end
|
||||
|
||||
@@ -549,6 +555,13 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
TemplateGroup.name=Template.name
|
||||
|
||||
if self.InitFarpDynamicSpawns == true then
|
||||
TemplateGroup.units[1].dynamicSpawn = true
|
||||
if self.InitFarpDynamicHotStarts == true then
|
||||
TemplateGroup.units[1].allowHotStart = true
|
||||
end
|
||||
end
|
||||
|
||||
self:T("Spawning FARP")
|
||||
self:T({Template=Template})
|
||||
@@ -556,7 +569,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
|
||||
-- ED's dirty way to spawn FARPS.
|
||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||
|
||||
--Static=coalition.addStaticObject(CountryID, Template)
|
||||
|
||||
-- Currently DCS 2.8 does not trigger birth events if FARPS are spawned!
|
||||
-- We create such an event. The airbase is registered in Core.Event
|
||||
local Event = {
|
||||
@@ -594,6 +608,19 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
||||
-- delay calling this for .3 seconds so that it hopefully comes after the BIRTH event of the group.
|
||||
self:ScheduleOnce(0.3, self.SpawnFunctionHook, mystatic, unpack(self.SpawnFunctionArguments))
|
||||
end
|
||||
|
||||
|
||||
if self.StaticCopyFrom ~= nil then
|
||||
mystatic.StaticCopyFrom = self.StaticCopyFrom
|
||||
if not _DATABASE.Templates.Statics[Template.name] then
|
||||
local TemplateGroup={}
|
||||
TemplateGroup.units={}
|
||||
TemplateGroup.units[1]=Template
|
||||
TemplateGroup.x=Template.x
|
||||
TemplateGroup.y=Template.y
|
||||
TemplateGroup.name=Template.name
|
||||
_DATABASE:_RegisterStaticTemplate( TemplateGroup, self.CoalitionID, self.CategoryID, CountryID )
|
||||
end
|
||||
end
|
||||
|
||||
return mystatic
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -305,20 +305,6 @@ function ZONE_BASE:GetCoordinate( Height ) --R2.1
|
||||
return self.Coordinate
|
||||
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.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param Core.Point#COORDINATE Coordinate Reference coordinate. Can also be a DCS#Vec2 or DCS#Vec3 object.
|
||||
@@ -548,6 +534,19 @@ function ZONE_BASE:GetZoneProbability()
|
||||
return self.ZoneProbability
|
||||
end
|
||||
|
||||
--- Get the coordinate on the radius of the zone nearest to Outsidecoordinate. Useto e.g. find an ingress point.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param Core.Point#COORDINATE Outsidecoordinate The coordinate outside of the zone from where to look.
|
||||
-- @return Core.Point#COORDINATE CoordinateOnRadius
|
||||
function ZONE_BASE:FindNearestCoordinateOnRadius(Outsidecoordinate)
|
||||
local Vec1 = self:GetVec2()
|
||||
local Radius = self:GetRadius()
|
||||
local Vec2 = Outsidecoordinate:GetVec2()
|
||||
local Point = UTILS.FindNearestPointOnCircle(Vec1,Radius,Vec2)
|
||||
local rc = COORDINATE:NewFromVec2(Point)
|
||||
return rc
|
||||
end
|
||||
|
||||
--- Get the zone taking into account the randomization probability of a zone to be selected.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #ZONE_BASE The zone is selected taking into account the randomization probability factor.
|
||||
@@ -1523,6 +1522,26 @@ function ZONE_RADIUS:IsVec3InZone( Vec3 )
|
||||
return InZone
|
||||
end
|
||||
|
||||
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||
function ZONE_RADIUS:GetClearZonePositions(PosRadius, NumPositions)
|
||||
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
|
||||
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||
function ZONE_RADIUS:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
--- Returns a random Vec2 location within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||
@@ -2501,6 +2520,26 @@ function ZONE_POLYGON_BASE:Flush()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Search for clear ground spawn zones within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #number PosRadius Required clear radius around each position.
|
||||
-- @param #number NumPositions Number of positions to find.
|
||||
-- @return #table A table of DCS#Vec2 positions that are clear of map objects within the given PosRadius. nil if no clear positions are found.
|
||||
function ZONE_POLYGON_BASE:GetClearZonePositions(PosRadius, NumPositions)
|
||||
return UTILS.GetClearZonePositions(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
|
||||
--- Search for a random clear ground spawn coordinate within this zone. A powerful and efficient function using Disposition to find clear areas for spawning ground units avoiding trees, water and map scenery.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #number PosRadius (Optional) Required clear radius around each position. (Default is math.min(Radius/10, 200))
|
||||
-- @param #number NumPositions (Optional) Number of positions to find. (Default 50)
|
||||
-- @return Core.Point#COORDINATE A random coordinate for a clear zone. nil if no clear positions are found.
|
||||
-- @return #number Assigned radius for the found zones. nil if no clear positions are found.
|
||||
function ZONE_POLYGON_BASE:GetRandomClearZoneCoordinate(PosRadius, NumPositions)
|
||||
return UTILS.GetRandomClearZoneCoordinate(self, PosRadius, NumPositions)
|
||||
end
|
||||
|
||||
--- Smokes the zone boundaries in a color.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @param #boolean UnBound If true, the tyres will be destroyed.
|
||||
@@ -3218,12 +3257,7 @@ function ZONE_POLYGON:Scan( ObjectCategories, UnitCategories )
|
||||
|
||||
local vectors = self:GetBoundingSquare()
|
||||
|
||||
local minVec3 = {x=vectors.x1, y=0, z=vectors.y1}
|
||||
local maxVec3 = {x=vectors.x2, y=0, z=vectors.y2}
|
||||
|
||||
local minmarkcoord = COORDINATE:NewFromVec3(minVec3)
|
||||
local maxmarkcoord = COORDINATE:NewFromVec3(maxVec3)
|
||||
local ZoneRadius = minmarkcoord:Get2DDistance(maxmarkcoord)/2
|
||||
local ZoneRadius = UTILS.VecDist2D({x=vectors.x1, y=vectors.y1}, {x=vectors.x2, y=vectors.y2})/2
|
||||
-- self:I("Scan Radius:" ..ZoneRadius)
|
||||
local CenterVec3 = self:GetCoordinate():GetVec3()
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ end -- env
|
||||
|
||||
do -- radio
|
||||
|
||||
---@type radio
|
||||
--@type radio
|
||||
-- @field #radio.modulation modulation
|
||||
|
||||
---
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Applevangelist**
|
||||
-- Last Update Sept 2023
|
||||
-- Last Update July 2025
|
||||
--
|
||||
-- ===
|
||||
-- @module Functional.AICSAR
|
||||
@@ -57,6 +57,8 @@
|
||||
-- @field #number Speed Default speed setting for the helicopter FLIGHTGROUP is 100kn.
|
||||
-- @field #boolean UseEventEject In case Event LandingAfterEjection isn't working, use set this to true.
|
||||
-- @field #number Delay In case of UseEventEject wait this long until we spawn a landed pilot.
|
||||
-- @field #boolean UseRescueZone If true, use a rescue zone and not the max distance to FARP/MASH
|
||||
-- @field Core.Zone#ZONE_RADIUS RescueZone Use this zone as operational area for the AICSAR instance.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
@@ -153,10 +155,10 @@
|
||||
-- To set up AICSAR for SRS TTS output, add e.g. the following to your script:
|
||||
--
|
||||
-- -- setup for google TTS, radio 243 AM, SRS server port 5002 with a google standard-quality voice (google cloud account required)
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\google.json")
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Google.Standard.en_US_Standard_D,"en-US","female","C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\google.json")
|
||||
--
|
||||
-- -- alternatively for MS Desktop TTS (voices need to be installed locally first!)
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female")
|
||||
-- my_aicsar:SetSRSTTSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",243,radio.modulation.AM,5002,MSRS.Voices.Microsoft.Hazel,"en-GB","female")
|
||||
--
|
||||
-- -- define a different voice for the downed pilot(s)
|
||||
-- my_aicsar:SetPilotTTSVoice(MSRS.Voices.Google.Standard.en_AU_Standard_D,"en-AU","male")
|
||||
@@ -177,7 +179,7 @@
|
||||
--
|
||||
-- Switch on radio transmissions via **either** SRS **or** "normal" DCS radio e.g. like so:
|
||||
--
|
||||
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone",270,radio.modulation.AM,nil,5002)
|
||||
-- my_aicsar:SetSRSRadio(true,"C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio",270,radio.modulation.AM,nil,5002)
|
||||
--
|
||||
-- or
|
||||
--
|
||||
@@ -191,7 +193,7 @@
|
||||
-- @field #AICSAR
|
||||
AICSAR = {
|
||||
ClassName = "AICSAR",
|
||||
version = "0.1.16",
|
||||
version = "0.1.18",
|
||||
lid = "",
|
||||
coalition = coalition.side.BLUE,
|
||||
template = "",
|
||||
@@ -236,6 +238,8 @@ AICSAR = {
|
||||
Altitude = 1500,
|
||||
UseEventEject = false,
|
||||
Delay = 100,
|
||||
UseRescueZone = false,
|
||||
RescueZone = nil,
|
||||
}
|
||||
|
||||
-- TODO Messages
|
||||
@@ -304,8 +308,9 @@ AICSAR.RadioLength = {
|
||||
-- @param #string Helotemplate Helicopter template name.
|
||||
-- @param Wrapper.Airbase#AIRBASE FARP FARP object or Airbase from where to start.
|
||||
-- @param Core.Zone#ZONE MASHZone Zone where to drop pilots after rescue.
|
||||
-- @param #number Helonumber Max number of alive Ai Helos at the same time. Defaults to three.
|
||||
-- @return #AICSAR self
|
||||
function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
||||
function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone,Helonumber)
|
||||
-- Inherit everything from FSM class.
|
||||
local self=BASE:Inherit(self, FSM:New())
|
||||
|
||||
@@ -373,7 +378,7 @@ function AICSAR:New(Alias,Coalition,Pilottemplate,Helotemplate,FARP,MASHZone)
|
||||
|
||||
-- limit number of available helos at the same time
|
||||
self.limithelos = true
|
||||
self.helonumber = 3
|
||||
self.helonumber = Helonumber or 3
|
||||
|
||||
-- localization
|
||||
self:InitLocalization()
|
||||
@@ -524,10 +529,20 @@ function AICSAR:InitLocalization()
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Use a defined zone as area of operation and not the distance to FARP.
|
||||
-- @param #AICSAR self
|
||||
-- @param Core.Zone#ZONE Zone The operational zone to use. Downed pilots in this area will be rescued. Can be any known #ZONE type.
|
||||
-- @return #AICSAR self
|
||||
function AICSAR:SetUsingRescueZone(Zone)
|
||||
self.UseRescueZone = true
|
||||
self.RescueZone = Zone
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Switch sound output on and use SRS output for sound files.
|
||||
-- @param #AICSAR self
|
||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||
-- @param #string Path Path to your SRS Server Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string Path Path to your SRS Server External Audio Component, e.g. "C:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\\\ExternalAudio"
|
||||
-- @param #number Frequency Defaults to 243 (guard)
|
||||
-- @param #number Modulation Radio modulation. Defaults to radio.modulation.AM
|
||||
-- @param #string SoundPath Where to find the audio files. Defaults to nil, i.e. add messages via "Sound to..." in the Mission Editor.
|
||||
@@ -538,7 +553,7 @@ function AICSAR:SetSRSRadio(OnOff,Path,Frequency,Modulation,SoundPath,Port)
|
||||
self.SRSRadio = OnOff and true
|
||||
self.SRSTTSRadio = false
|
||||
self.SRSFrequency = Frequency or 243
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.SRS:SetLabel("ACSR")
|
||||
self.SRS:SetCoalition(self.coalition)
|
||||
self.SRSModulation = Modulation or radio.modulation.AM
|
||||
@@ -556,7 +571,7 @@ end
|
||||
-- See `AICSAR:SetPilotTTSVoice()` and `AICSAR:SetOperatorTTSVoice()`
|
||||
-- @param #AICSAR self
|
||||
-- @param #boolean OnOff Switch on (true) or off (false).
|
||||
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string Path Path to your SRS Server Component, e.g. "E:\\\\Program Files\\\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #number Frequency (Optional) Defaults to 243 (guard)
|
||||
-- @param #number Modulation (Optional) Radio modulation. Defaults to radio.modulation.AM
|
||||
-- @param #number Port (Optional) Port of the SRS, defaults to 5002.
|
||||
@@ -570,7 +585,7 @@ function AICSAR:SetSRSTTSRadio(OnOff,Path,Frequency,Modulation,Port,Voice,Cultur
|
||||
self.SRSTTSRadio = OnOff and true
|
||||
self.SRSRadio = false
|
||||
self.SRSFrequency = Frequency or 243
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.SRSModulation = Modulation or radio.modulation.AM
|
||||
self.SRSPort = Port or MSRS.port or 5002
|
||||
if OnOff then
|
||||
@@ -693,7 +708,7 @@ function AICSAR:_EjectEventHandler(EventData)
|
||||
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
||||
local _country = _event.initiator:getCountry()
|
||||
local _coalition = coalition.getCountryCoalition( _country )
|
||||
local data = UTILS.DeepCopy(EventData)
|
||||
--local data = UTILS.DeepCopy(EventData)
|
||||
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
||||
self:ScheduleOnce(self.Delay,self._DelayedSpawnPilot,self,_LandingPos,_coalition)
|
||||
end
|
||||
@@ -708,7 +723,14 @@ end
|
||||
-- @return #AICSAR self
|
||||
function AICSAR:_DelayedSpawnPilot(_LandingPos,_coalition)
|
||||
|
||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||
if self.UseRescueZone == true and self.RescueZone ~= nil then
|
||||
if self.RescueZone:IsCoordinateInZone(_LandingPos) then
|
||||
distancetofarp = self.maxdistance - 10
|
||||
else
|
||||
distancetofarp = self.maxdistance + 10
|
||||
end
|
||||
end
|
||||
-- Mayday Message
|
||||
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
||||
local text = ""
|
||||
@@ -795,7 +817,13 @@ function AICSAR:_EventHandler(EventData, FromEject)
|
||||
|
||||
-- DONE: add distance check
|
||||
local distancetofarp = _LandingPos:Get2DDistance(self.farp:GetCoordinate())
|
||||
|
||||
if self.UseRescueZone == true and self.RescueZone ~= nil then
|
||||
if self.RescueZone:IsCoordinateInZone(_LandingPos) then
|
||||
distancetofarp = self.maxdistance - 10
|
||||
else
|
||||
distancetofarp = self.maxdistance + 10
|
||||
end
|
||||
end
|
||||
-- Mayday Message
|
||||
local Text,Soundfile,Soundlength,Subtitle = self.gettext:GetEntry("PILOTDOWN",self.locale)
|
||||
local text = ""
|
||||
@@ -817,7 +845,6 @@ function AICSAR:_EventHandler(EventData, FromEject)
|
||||
if _coalition == self.coalition then
|
||||
if self.verbose then
|
||||
MESSAGE:New(msgtxt,15,"AICSAR"):ToCoalition(self.coalition)
|
||||
-- MESSAGE:New(msgtxt,15,"AICSAR"):ToLog()
|
||||
end
|
||||
if self.SRSRadio then
|
||||
local sound = SOUNDFILE:New(Soundfile,self.SRSSoundPath,Soundlength)
|
||||
@@ -869,6 +896,7 @@ function AICSAR:_GetFlight()
|
||||
:InitUnControlled(true)
|
||||
:OnSpawnGroup(
|
||||
function(Group)
|
||||
Group:OptionPreferVerticalLanding()
|
||||
self:__HeloOnDuty(1,Group)
|
||||
end
|
||||
)
|
||||
@@ -892,7 +920,7 @@ function AICSAR:_InitMission(Pilot,Index)
|
||||
--local pilotset = SET_GROUP:New()
|
||||
--pilotset:AddGroup(Pilot)
|
||||
|
||||
-- Cargo transport assignment.
|
||||
-- Cargo transport assignment.
|
||||
local opstransport=OPSTRANSPORT:New(Pilot, pickupzone, self.farpzone)
|
||||
--opstransport:SetVerbosity(3)
|
||||
|
||||
@@ -934,6 +962,10 @@ function AICSAR:_InitMission(Pilot,Index)
|
||||
helo:__UnloadingDone(5)
|
||||
end
|
||||
|
||||
function helo:OnAfterLandAtAirbase(From,Event,To,airbase)
|
||||
helo:Despawn(2)
|
||||
end
|
||||
|
||||
self.helos[Index] = helo
|
||||
|
||||
return self
|
||||
@@ -984,7 +1016,9 @@ function AICSAR:_CheckHelos()
|
||||
local name = helo:GetName()
|
||||
self:T("Helo group "..name.." in state "..state)
|
||||
if state == "Arrived" then
|
||||
helo:__Stop(5)
|
||||
--helo:__Stop(5)
|
||||
helo.OnAfterDead = nil
|
||||
helo:Despawn(35)
|
||||
self.helos[_index] = nil
|
||||
end
|
||||
else
|
||||
@@ -1025,7 +1059,7 @@ function AICSAR:_CheckQueue(OpsGroup)
|
||||
if self:_CheckInMashZone(_pilot) then
|
||||
self:T("Pilot" .. _pilot.GroupName .. " rescued!")
|
||||
if OpsGroup then
|
||||
OpsGroup:Despawn(10)
|
||||
--OpsGroup:Despawn(10)
|
||||
else
|
||||
_pilot:Destroy(true,10)
|
||||
end
|
||||
|
||||
@@ -105,7 +105,7 @@ AUTOLASE = {
|
||||
debug = false,
|
||||
smokemenu = true,
|
||||
RoundingPrecision = 0,
|
||||
increasegroundawareness = true,
|
||||
increasegroundawareness = false,
|
||||
MonitorFrequency = 30,
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ function AUTOLASE:New(RecceSet, Coalition, Alias, PilotSet)
|
||||
self.smokemenu = true
|
||||
self.threatmenu = true
|
||||
self.RoundingPrecision = 0
|
||||
self.increasegroundawareness = true
|
||||
self.increasegroundawareness = false
|
||||
self.MonitorFrequency = 30
|
||||
|
||||
self:EnableSmokeMenu({Angle=math.random(0,359),Distance=math.random(10,20)})
|
||||
@@ -493,7 +493,7 @@ end
|
||||
--- (User) Function enable sending messages via SRS.
|
||||
-- @param #AUTOLASE self
|
||||
-- @param #boolean OnOff Switch usage on and off
|
||||
-- @param #string Path Path to SRS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone
|
||||
-- @param #string Path Path to SRS TTS directory, e.g. C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio
|
||||
-- @param #number Frequency Frequency to send, e.g. 243
|
||||
-- @param #number Modulation Modulation i.e. radio.modulation.AM or radio.modulation.FM
|
||||
-- @param #string Label (Optional) Short label to be used on the SRS Client Overlay
|
||||
@@ -508,7 +508,7 @@ end
|
||||
function AUTOLASE:SetUsingSRS(OnOff,Path,Frequency,Modulation,Label,Gender,Culture,Port,Voice,Volume,PathToGoogleKey)
|
||||
if OnOff then
|
||||
self.useSRS = true
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.SRSPath = Path or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.SRSFreq = Frequency or 271
|
||||
self.SRSMod = Modulation or radio.modulation.AM
|
||||
self.Gender = Gender or MSRS.gender or "male"
|
||||
@@ -1020,7 +1020,7 @@ function AUTOLASE:_Prescient()
|
||||
self:T(self.lid.."Checking possibly visible STATICs for Recce "..unit:GetName())
|
||||
for _,_static in pairs(Statics) do -- DCS static object here
|
||||
local static = STATIC:Find(_static)
|
||||
if static and static:GetCoalition() ~= self.coalition then
|
||||
if static and static:GetCoalition() ~= self.coalition and static:GetCoordinate() then
|
||||
local IsLOS = position:IsLOS(static:GetCoordinate())
|
||||
if IsLOS then
|
||||
unit:KnowUnit(static,true,true)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
--
|
||||
-- Last Update: Mar 2025
|
||||
-- Last Update: July 2025
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -62,7 +62,9 @@
|
||||
-- @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 #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
|
||||
|
||||
|
||||
@@ -74,10 +76,9 @@
|
||||
--
|
||||
-- * 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.
|
||||
-- * **Automatic mode** (default since 0.8) will set-up your SAM site network automatically for you
|
||||
-- * **Classic mode** behaves like before
|
||||
-- * Leverage evasiveness from SEAD, leverage attack range setting
|
||||
-- * Automatic setup of SHORAD based on groups of the class "short-range"
|
||||
-- * **Automatic mode** (default) will set-up your SAM site network automatically for you.
|
||||
-- * 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
|
||||
--
|
||||
@@ -110,7 +111,7 @@
|
||||
-- * Silkworm (though strictly speaking this is a surface to ship missile)
|
||||
-- * SA-2, SA-3, SA-5, SA-6, SA-7, SA-8, SA-9, SA-10, SA-11, SA-13, SA-15, SA-19
|
||||
-- * From IDF mod: STUNNER IDFA, TAMIR IDFA (Note all caps!)
|
||||
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2
|
||||
-- * From HDS (see note on HDS below): SA-2, SA-3, SA-10B, SA-10C, SA-12, SA-17, SA-20A, SA-20B, SA-23, HQ-2, SAMP/T Block 1, SAMP/T Block 1INT, SAMP/T Block2
|
||||
--
|
||||
-- * From SMA: RBS98M, RBS70, RBS90, RBS90M, RBS103A, RBS103B, RBS103AM, RBS103BM, Lvkv9040M
|
||||
-- **NOTE** If you are using the Swedish Military Assets (SMA), please note that the **group name** for RBS-SAM types also needs to contain the keyword "SMA"
|
||||
@@ -124,19 +125,20 @@
|
||||
-- * SA-2 (with V759 missile, e.g. "Red SAM SA-2 HDS")
|
||||
-- * SA-2 (with HQ-2 launcher, use HQ-2 in the group name, e.g. "Red SAM HQ-2" )
|
||||
-- * SA-3 (with V601P missile, e.g. "Red SAM SA-3 HDS")
|
||||
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS")
|
||||
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS")
|
||||
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS")
|
||||
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS")
|
||||
-- * SA-10B (overlap with other SA-10 types, e.g. "Red SAM SA-10B HDS" with 5P85CE launcher)
|
||||
-- * SA-10C (overlap with other SA-10 types, e.g. "Red SAM SA-10C HDS" with 5P85SE launcher)
|
||||
-- * SA-12 (launcher dependent range, e.g. "Red SAM SA-12 HDS 2" for the 9A82 variant and "Red SAM SA-12 HDS 1" for the 9A83 variant)
|
||||
-- * SA-23 (launcher dependent range, e.g. "Red SAM SA-23 HDS 2" for the 9A82ME variant and "Red SAM SA-23 HDS 1" for the 9A83ME variant)
|
||||
-- * SAMP/T (launcher dependent range, e.g. "Blue SAM SAMPT Block 1 HDS" for Block 1, "Blue SAM SAMPT Block 1INT HDS", "Blue SAM SAMPT Block 2 HDS")
|
||||
--
|
||||
-- The other HDS types work like the rest of the known SAM systems.
|
||||
--
|
||||
-- # 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.
|
||||
-- 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.
|
||||
-- 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.
|
||||
-- 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** group per SAM location. SA-15 TOR systems offer a good missile defense.
|
||||
-- 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.
|
||||
-- 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.
|
||||
--
|
||||
@@ -188,7 +190,7 @@
|
||||
--
|
||||
-- ## 2.1 Auto mode features
|
||||
--
|
||||
-- ### 2.1.1 You can now add Accept-, Reject- and Conflict-Zones to your setup, e.g. to consider borders or de-militarized zones:
|
||||
-- ### 2.1.1 You can 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!
|
||||
-- -- This is effectively a 3-stage filter allowing for zone overlap. A coordinate is accepted first when
|
||||
@@ -205,9 +207,6 @@
|
||||
-- ### 2.1.3 SHORAD/Point defense will automatically be added from SAM sites of type "point" or if the range is less than 5km or if the type is AAA.
|
||||
--
|
||||
-- ### 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.
|
||||
-- -- also see engagerange below.
|
||||
@@ -220,6 +219,12 @@
|
||||
--
|
||||
-- -- 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
|
||||
--
|
||||
-- ### 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]
|
||||
--
|
||||
@@ -242,26 +247,8 @@
|
||||
-- E.g. mymantis:SetAdvancedMode( true, 90 )
|
||||
--
|
||||
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
||||
--
|
||||
-- # 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
|
||||
-- # 5. Integrated SEAD
|
||||
--
|
||||
-- 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
|
||||
@@ -288,6 +275,7 @@
|
||||
MANTIS = {
|
||||
ClassName = "MANTIS",
|
||||
name = "mymantis",
|
||||
version = "0.9.32",
|
||||
SAM_Templates_Prefix = "",
|
||||
SAM_Group = nil,
|
||||
EWR_Templates_Prefix = "",
|
||||
@@ -336,6 +324,8 @@ MANTIS = {
|
||||
SmokeDecoy = false,
|
||||
SmokeDecoyColor = SMOKECOLOR.White,
|
||||
checkcounter = 1,
|
||||
DLinkCacheTime = 120,
|
||||
logsamstatus = false,
|
||||
}
|
||||
|
||||
--- Advanced state enumerator
|
||||
@@ -374,7 +364,7 @@ MANTIS.radiusscale[MANTIS.SamType.POINT] = 3
|
||||
MANTIS.SamData = {
|
||||
["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
|
||||
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot" },
|
||||
["Patriot"] = { Range=99, Blindspot=0, Height=25, Type="Long", Radar="Patriot str" },
|
||||
["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-3"] = { Range=18, Blindspot=6, Height=18, Type="Short", Radar="5p73 s-125 ln" },
|
||||
@@ -382,7 +372,8 @@ MANTIS.SamData = {
|
||||
["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-11"] = { Range=35, Blindspot=0, Height=20, Type="Medium", Radar="SA-11" },
|
||||
["Roland"] = { Range=5, Blindspot=0, Height=5, Type="Point", Radar="Roland" },
|
||||
["Roland"] = { Range=6, Blindspot=0, Height=5, Type="Short", 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" },
|
||||
["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" },
|
||||
@@ -393,9 +384,10 @@ MANTIS.SamData = {
|
||||
["Chaparral"] = { Range=8, Blindspot=0, Height=3, Type="Short", Radar="Chaparral" },
|
||||
["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" },
|
||||
["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
|
||||
["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=50, Type="Medium", Radar="SA-17" },
|
||||
["SA-20A"] = { Range=150, Blindspot=5, Height=27, Type="Long" , Radar="S-300PMU1"},
|
||||
["SA-20B"] = { Range=200, Blindspot=4, Height=27, Type="Long" , Radar="S-300PMU2"},
|
||||
["HQ-2"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||
@@ -416,13 +408,17 @@ MANTIS.SamDataHDS = {
|
||||
-- group name MUST contain HDS to ID launcher type correctly!
|
||||
["SA-2 HDS"] = { Range=56, Blindspot=7, Height=30, Type="Medium", Radar="V759" },
|
||||
["SA-3 HDS"] = { Range=20, Blindspot=6, Height=30, Type="Short", Radar="V-601P" },
|
||||
["SA-10C HDS 2"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85DE ln"}, -- V55RUD
|
||||
["SA-10C HDS 1"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
||||
["SA-12 HDS 2"] = { Range=100, Blindspot=10, Height=25, Type="Long" , Radar="S-300V 9A82 l"},
|
||||
["SA-12 HDS 1"] = { Range=75, Blindspot=1, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
||||
["SA-10B HDS"] = { Range=90, Blindspot=5, Height=25, Type="Long" , Radar="5P85CE ln"}, -- V55RUD
|
||||
["SA-10C HDS"] = { Range=75, Blindspot=5, Height=25, Type="Long" , Radar="5P85SE ln"}, -- V55RUD
|
||||
["SA-17 HDS"] = { Range=50, Blindspot=3, Height=50, Type="Medium", Radar="SA-17 " },
|
||||
["SA-12 HDS 2"] = { Range=100, Blindspot=13, Height=30, Type="Long" , Radar="S-300V 9A82 l"},
|
||||
["SA-12 HDS 1"] = { Range=75, Blindspot=6, Height=25, Type="Long" , Radar="S-300V 9A83 l"},
|
||||
["SA-23 HDS 2"] = { Range=200, Blindspot=5, Height=37, Type="Long", Radar="S-300VM 9A82ME" },
|
||||
["SA-23 HDS 1"] = { Range=100, Blindspot=1, Height=50, Type="Long", Radar="S-300VM 9A83ME" },
|
||||
["HQ-2 HDS"] = { Range=50, Blindspot=6, Height=35, Type="Medium", Radar="HQ_2_Guideline_LN" },
|
||||
["SAMPT Block 1 HDS"] = { Range=120, Blindspot=1, Height=20, Type="long", Radar="SAMPT_MLT_Blk1" }, -- Block 1 Launcher
|
||||
["SAMPT Block 1INT HDS"] = { Range=150, Blindspot=1, Height=25, Type="long", Radar="SAMPT_MLT_Blk1NT" }, -- Block 1-INT Launcher
|
||||
["SAMPT Block 2 HDS"] = { Range=200, Blindspot=10, Height=70, Type="long", Radar="SAMPT_MLT_Blk2" }, -- Block 2 Launcher
|
||||
}
|
||||
|
||||
--- SAM data SMA
|
||||
@@ -625,7 +621,8 @@ do
|
||||
self.advAwacs = false
|
||||
end
|
||||
|
||||
|
||||
self:SetDLinkCacheTime()
|
||||
|
||||
-- Set the string id for output to DCS.log file.
|
||||
self.lid=string.format("MANTIS %s | ", self.name)
|
||||
|
||||
@@ -658,6 +655,8 @@ do
|
||||
table.insert(self.ewr_templates,awacs)
|
||||
end
|
||||
|
||||
self.logsamstatus = false
|
||||
|
||||
self:T({self.ewr_templates})
|
||||
|
||||
self.SAM_Group = SET_GROUP:New():FilterPrefixes(self.SAM_Templates_Prefix):FilterCoalitions(self.Coalition)
|
||||
@@ -687,9 +686,6 @@ do
|
||||
-- counter for SAM table updates
|
||||
self.checkcounter = 1
|
||||
|
||||
-- TODO Version
|
||||
-- @field #string version
|
||||
self.version="0.9.27"
|
||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||
|
||||
--- FSM Functions ---
|
||||
@@ -1039,6 +1035,16 @@ do
|
||||
end
|
||||
return self
|
||||
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
|
||||
-- @param #MANTIS self
|
||||
@@ -1431,7 +1437,9 @@ do
|
||||
--IntelTwo:SetClusterRadius(5000)
|
||||
IntelTwo:Start()
|
||||
|
||||
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,300)
|
||||
local CacheTime = self.DLinkCacheTime or 120
|
||||
local IntelDlink = INTEL_DLINK:New({IntelOne,IntelTwo},self.name.." DLINK",22,CacheTime)
|
||||
|
||||
IntelDlink:__Start(1)
|
||||
|
||||
self:SetUsingDLink(IntelDlink)
|
||||
@@ -1493,7 +1501,7 @@ do
|
||||
elseif chm then
|
||||
SAMData = self.SamDataCH
|
||||
end
|
||||
--self:T("Looking to auto-match for "..grpname)
|
||||
--self:I("Looking to auto-match for "..grpname)
|
||||
for _,_unit in pairs(units) do
|
||||
local unit = _unit -- Wrapper.Unit#UNIT
|
||||
local type = string.lower(unit:GetTypeName())
|
||||
@@ -1694,7 +1702,9 @@ do
|
||||
local grpname = group:GetName()
|
||||
local grpcoord = group:GetCoordinate()
|
||||
local grprange, grpheight,type,blind = self:_GetSAMRange(grpname)
|
||||
local radaralive = group:IsSAM()
|
||||
-- TODO the below might stop working at some point after some hours, needs testing
|
||||
--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( SEAD_Grps, grpname )
|
||||
if type == MANTIS.SamType.LONG and radaralive then
|
||||
@@ -1791,7 +1801,7 @@ do
|
||||
if self.Shorad and self.Shorad.ActiveGroups and self.Shorad.ActiveGroups[name] then
|
||||
activeshorad = true
|
||||
end
|
||||
if IsInZone and not suppressed and not activeshorad then --check any target in zone and not currently managed by SEAD
|
||||
if IsInZone and (not suppressed) and (not activeshorad) then --check any target in zone and not currently managed by SEAD
|
||||
if samgroup:IsAlive() then
|
||||
-- switch on SAM
|
||||
local switch = false
|
||||
@@ -1823,7 +1833,7 @@ do
|
||||
-- link in to SHORAD if available
|
||||
-- DONE: Test integration fully
|
||||
if self.ShoradLink and (Distance < self.ShoradActDistance or Distance < blind ) then -- don't give SHORAD position away too early
|
||||
local Shorad = self.Shorad
|
||||
local Shorad = self.Shorad --Functional.Shorad#SHORAD
|
||||
local radius = self.checkradius
|
||||
local ontime = self.ShoradTime
|
||||
Shorad:WakeUpShorad(name, radius, ontime)
|
||||
@@ -1856,7 +1866,7 @@ do
|
||||
end --end alive
|
||||
end --end check
|
||||
end --for loop
|
||||
if self.debug or self.verbose then
|
||||
if self.debug or self.verbose or self.logsamstatus then
|
||||
for _,_status in pairs(self.SamStateTracker) do
|
||||
if _status == "GREEN" then
|
||||
instatusgreen=instatusgreen+1
|
||||
@@ -1877,8 +1887,9 @@ do
|
||||
-- @param #MANTIS self
|
||||
-- @param Functional.Detection#DETECTION_AREAS detection Detection object
|
||||
-- @param #boolean dlink
|
||||
-- @param #boolean reporttolog
|
||||
-- @return #MANTIS self
|
||||
function MANTIS:_Check(detection,dlink)
|
||||
function MANTIS:_Check(detection,dlink,reporttolog)
|
||||
self:T(self.lid .. "Check")
|
||||
--get detected set
|
||||
local detset = detection:GetDetectedItemCoordinates()
|
||||
@@ -1905,7 +1916,8 @@ do
|
||||
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)
|
||||
end
|
||||
if self.debug or self.verbose then
|
||||
|
||||
local function GetReport()
|
||||
local statusreport = REPORT:New("\nMANTIS Status "..self.name)
|
||||
statusreport:Add("+-----------------------------+")
|
||||
statusreport:Add(string.format("+ SAM in RED State: %2d",instatusred))
|
||||
@@ -1914,7 +1926,15 @@ do
|
||||
statusreport:Add(string.format("+ SHORAD active: %2d",activeshorads))
|
||||
end
|
||||
statusreport:Add("+-----------------------------+")
|
||||
return statusreport
|
||||
end
|
||||
|
||||
if self.debug or self.verbose then
|
||||
local statusreport = GetReport()
|
||||
MESSAGE:New(statusreport:Text(),10):ToAll():ToLog()
|
||||
elseif reporttolog == true then
|
||||
local statusreport = GetReport()
|
||||
MESSAGE:New(statusreport:Text(),10):ToLog()
|
||||
end
|
||||
return self
|
||||
end
|
||||
@@ -2022,7 +2042,7 @@ do
|
||||
self:T({From, Event, To})
|
||||
-- check detection
|
||||
if not self.state2flag then
|
||||
self:_Check(self.Detection,self.DLink)
|
||||
self:_Check(self.Detection,self.DLink,self.logsamstatus)
|
||||
end
|
||||
|
||||
local EWRAlive = self:_CheckAnyEWRAlive()
|
||||
@@ -2093,7 +2113,7 @@ do
|
||||
if self.debug and self.verbose then
|
||||
self:I(self.lid .. "Status Report")
|
||||
for _name,_state in pairs(self.SamStateTracker) do
|
||||
self:I(string.format("Site %s\tStatus %s",_name,_state))
|
||||
self:I(string.format("Site %s | Status %s",_name,_state))
|
||||
end
|
||||
end
|
||||
local interval = self.detectinterval * -1
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
|
||||
@@ -603,7 +603,7 @@ RANGE.MenuF10Root = nil
|
||||
|
||||
--- Range script version.
|
||||
-- @field #string version
|
||||
RANGE.version = "2.8.0"
|
||||
RANGE.version = "2.8.1"
|
||||
|
||||
-- TODO list:
|
||||
-- TODO: Verbosity level for messages.
|
||||
@@ -2032,10 +2032,10 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
|
||||
|
||||
-- Smoke impact point of bomb.
|
||||
if playerData and playerData.smokebombimpact and insidezone then
|
||||
if playerData and playerData.delaysmoke then
|
||||
timer.scheduleFunction( self._DelayedSmoke, { coord = impactcoord, color = playerData.smokecolor }, timer.getTime() + self.TdelaySmoke )
|
||||
if playerData.delaysmoke then
|
||||
impactcoord:Smoke(playerData.smokecolor, 30, self.TdelaySmoke)
|
||||
else
|
||||
impactcoord:Smoke( playerData.smokecolor )
|
||||
impactcoord:Smoke(playerData.smokecolor, 30)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2102,7 +2102,12 @@ function RANGE._OnImpact(weapon, self, playerData, attackHdg, attackAlt, attackV
|
||||
result.attackHdg = attackHdg
|
||||
result.attackVel = attackVel
|
||||
result.attackAlt = attackAlt
|
||||
result.date=os and os.date() or "n/a"
|
||||
if os and os.date then
|
||||
result.date=os.date()
|
||||
else
|
||||
self:E(self.lid.."os or os.date() not available")
|
||||
result.date = "n/a"
|
||||
end
|
||||
|
||||
-- Add to table.
|
||||
table.insert( _results, result )
|
||||
@@ -2635,13 +2640,6 @@ end
|
||||
-- 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.
|
||||
-- @param #RANGE self
|
||||
-- @param #string _unitName Name of the player unit.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3153,7 +3153,7 @@ end
|
||||
-- @param #WAREHOUSE self
|
||||
-- @return Core.Point#COORDINATE The coordinate of the warehouse.
|
||||
function WAREHOUSE:GetCoordinate()
|
||||
return self.warehouse:GetCoordinate()
|
||||
return self.warehouse:GetCoord()
|
||||
end
|
||||
|
||||
--- Get 3D vector of warehouse static.
|
||||
@@ -6893,7 +6893,7 @@ function WAREHOUSE:_CheckConquered()
|
||||
for _,_unit in pairs(units) do
|
||||
local unit=_unit --Wrapper.Unit#UNIT
|
||||
|
||||
local distance=coord:Get2DDistance(unit:GetCoordinate())
|
||||
local distance=coord:Get2DDistance(unit:GetCoord())
|
||||
|
||||
-- Filter only alive groud units. Also check distance again, because the scan routine might give some larger distances.
|
||||
if unit:IsGround() and unit:IsAlive() and distance <= radius then
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
--
|
||||
-- # Developer Note
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
|
||||
@@ -32,7 +32,6 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/MarkerOps_Base.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/TextAndSound.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/Pathline.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/ClientMenu.lua')
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Core/Vector.lua')
|
||||
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Object.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Identifiable.lua' )
|
||||
@@ -187,9 +186,4 @@ __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_Dispatcher.lua' )
|
||||
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Beacons.lua' )
|
||||
__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Point.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' )
|
||||
|
||||
@@ -32,7 +32,6 @@ __Moose.Include( 'Core\\MarkerOps_Base.lua' )
|
||||
__Moose.Include( 'Core\\TextAndSound.lua' )
|
||||
__Moose.Include( 'Core\\Condition.lua' )
|
||||
__Moose.Include( 'Core\\ClientMenu.lua' )
|
||||
__Moose.Include( 'Core\\Vector.lua' )
|
||||
|
||||
__Moose.Include( 'Wrapper\\Object.lua' )
|
||||
__Moose.Include( 'Wrapper\\Identifiable.lua' )
|
||||
@@ -116,7 +115,6 @@ __Moose.Include( 'Ops\\Operation.lua' )
|
||||
__Moose.Include( 'Ops\\FlightControl.lua' )
|
||||
__Moose.Include( 'Ops\\PlayerRecce.lua' )
|
||||
__Moose.Include( 'Ops\\EasyGCICAP.lua' )
|
||||
__Moose.Include( 'Ops\\EasyA2G.lua' )
|
||||
|
||||
__Moose.Include( 'AI\\AI_Balancer.lua' )
|
||||
__Moose.Include( 'AI\\AI_Air.lua' )
|
||||
@@ -179,7 +177,4 @@ __Moose.Include( 'Tasking\\Task_Cargo_Dispatcher.lua' )
|
||||
__Moose.Include( 'Tasking\\Task_Capture_Zone.lua' )
|
||||
__Moose.Include( 'Tasking\\Task_Capture_Dispatcher.lua' )
|
||||
|
||||
__Moose.Include( 'Navigation\\Point.lua' )
|
||||
__Moose.Include( 'Navigation\\Beacons.lua' )
|
||||
|
||||
__Moose.Include( 'Globals.lua' )
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
--- **NAVIGATION** - Beacons of the map/theatre.
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Beacons of the map
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ## Example Missions:
|
||||
--
|
||||
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Beacons).
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
-- @module Navigation.Beacons
|
||||
-- @image NAVIGATION_Beacons.png
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- BEACONS class.
|
||||
-- @type BEACONS
|
||||
--
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity of output.
|
||||
-- @field #table beacons Beacons.
|
||||
--
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The BEACONS Concept
|
||||
--
|
||||
-- The NAVFIX class has a great concept!
|
||||
--
|
||||
-- Bla, bla...
|
||||
--
|
||||
-- # Basic Setup
|
||||
--
|
||||
-- A new `BEACONS` object can be created with the @{#BEACONS.New}() function.
|
||||
--
|
||||
-- local beacons=BEACONS:New("G:\Games\DCS World Testing\Mods\terrains\GermanyColdWar\beacons.lua")
|
||||
--
|
||||
-- This is how it works.
|
||||
--
|
||||
-- @field #BEACONS
|
||||
BEACONS = {
|
||||
ClassName = "BEACONS",
|
||||
verbose = 0,
|
||||
beacons = {},
|
||||
}
|
||||
|
||||
--- BEACONS class version.
|
||||
-- @field #string version
|
||||
BEACONS.version="0.0.0"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor(s)
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new BECAONS class instance from a given file.
|
||||
-- @param #BEACONS self
|
||||
-- @param #string FileName Full path to the file containing the map beacons.
|
||||
-- @return #BEACONS self
|
||||
function BEACONS:NewFromFile(FileName)
|
||||
|
||||
-- Inherit everything from BASE class.
|
||||
self=BASE:Inherit(self, BASE:New()) -- #BEACONS
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Add marker all beacons on the F10 map.
|
||||
-- @param #BEACONS self
|
||||
-- @return #BEACONS self
|
||||
function BEACONS:MarkerShow()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove markers of all beacons from the F10 map.
|
||||
-- @param #BEACONS self
|
||||
-- @return #BEACONS self
|
||||
function BEACONS:MarkerRemove()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Get text displayed in the F10 marker.
|
||||
-- @param #BEACONS self
|
||||
-- @return #string Marker text.
|
||||
function BEACONS:_GetMarkerText(beacon)
|
||||
|
||||
local altmin=self.altMin and tostring(self.altMin) or ""
|
||||
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("NAVFIX %s", self.name)
|
||||
if self.isIAF then
|
||||
text=text..string.format(" (IAF)")
|
||||
end
|
||||
if self.isIF then
|
||||
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
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1,481 +0,0 @@
|
||||
--- **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
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1,587 +0,0 @@
|
||||
--- **NAVIGATION** - Navigation Airspace Points, Fixes and Aids.
|
||||
--
|
||||
-- **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-%20NavFix).
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **funkyfranky**
|
||||
--
|
||||
-- ===
|
||||
-- @module Navigation.Point
|
||||
-- @image NAVIGATION_Point.png
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- NAVFIX class.
|
||||
-- @type NAVFIX
|
||||
--
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity of output.
|
||||
-- @field #string name Name of the point.
|
||||
-- @field #string typePoint Type of the point, *e.g. "Intersection", "VOR", "Airport".
|
||||
-- @field Core.Vector#VECTOR vector Position vector of the fix.
|
||||
-- @field Wrapper.Marker#MARKER marker Marker on F10 map.
|
||||
-- @field #number altMin Minimum altitude in meters.
|
||||
-- @field #number altMax Maximum altitude in meters.
|
||||
-- @field #number speedMin Minimum speed in knots.
|
||||
-- @field #number speedMax Maximum speed in knots.
|
||||
--
|
||||
-- @field #boolean isCompulsory Is this a compulsory fix.
|
||||
-- @field #boolean isFlyover Is this a flyover fix (`true`) or turning point otherwise.
|
||||
-- @field #boolean isFAF Is this a final approach fix.
|
||||
-- @field #boolean isIAF Is this an initial approach fix.
|
||||
-- @field #boolean isIF Is this an initial fix.
|
||||
-- @field #boolean isMAF Is this an initial fix.
|
||||
--
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The NAVFIX Concept
|
||||
--
|
||||
-- The NAVFIX class has a great concept!
|
||||
--
|
||||
-- A NAVFIX describes a geo position and can, *e.g.*, be part of a FLIGHTPLAN. It has a unique name and is of a certain type, *e.g.* "Intersection", "VOR", "Airbase" etc.
|
||||
-- It can also have further properties as min/max altitudes and speeds that aircraft need to obey when they pass the point.
|
||||
--
|
||||
-- # Basic Setup
|
||||
--
|
||||
-- A new `NAVFIX` object can be created with the @{#NAVFIX.New}() function.
|
||||
--
|
||||
-- myNavPoint=NAVFIX:New()
|
||||
-- myTemplate:SetXYZ(X, Y, Z)
|
||||
--
|
||||
-- This is how it works.
|
||||
--
|
||||
-- @field #NAVFIX
|
||||
NAVFIX = {
|
||||
ClassName = "NAVFIX",
|
||||
verbose = 0,
|
||||
}
|
||||
|
||||
--- Type of point.
|
||||
-- @type NAVFIX.Type
|
||||
-- @field #string POINT Waypoint.
|
||||
-- @field #string INTERSECTION Intersection of airway.
|
||||
-- @field #string AIRPORT Airport.
|
||||
-- @field #string VOR Very High Frequency Omnidirectional Range Station.
|
||||
-- @field #string DME Distance Measuring Equipment.
|
||||
-- @field #string NDB Non-Directional Beacon.
|
||||
-- @field #string VORDME Combined VHF omnidirectional range (VOR) with a distance-measuring equipment (DME).
|
||||
-- @field #string LOC Localizer.
|
||||
-- @field #string ILS Instrument Landing System.
|
||||
-- @field #string TACAN TACtical Air Navigation System (TACAN).
|
||||
NAVFIX.Type={
|
||||
POINT="Point",
|
||||
INTERSECTION="Intersection",
|
||||
AIRPORT="Airport",
|
||||
NDB="NDB",
|
||||
VOR="VOR",
|
||||
DME="DME",
|
||||
VORDME="VOR/DME",
|
||||
LOC="Localizer",
|
||||
ILS="ILS",
|
||||
TACAN="TACAN"
|
||||
}
|
||||
|
||||
--- NAVFIX class version.
|
||||
-- @field #string version
|
||||
NAVFIX.version="0.0.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: A lot...
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor(s)
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new NAVFIX class instance from a given VECTOR.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #string Name Name/ident of the point. Should be unique!
|
||||
-- @param #string Type Type of the point. Default `NAVFIX.Type.POINT`.
|
||||
-- @param Core.Vector#VECTOR Vector Position vector of the navpoint.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:NewFromVector(Name, Type, Vector)
|
||||
|
||||
-- Inherit everything from BASE class.
|
||||
self=BASE:Inherit(self, BASE:New()) -- #NAVFIX
|
||||
|
||||
-- Vector of point.
|
||||
self.vector=Vector
|
||||
|
||||
-- Name of point.
|
||||
self.name=Name
|
||||
|
||||
-- Type of the point.
|
||||
self.typePoint=Type or NAVFIX.Type.POINT
|
||||
|
||||
local coord=COORDINATE:NewFromVec3(self.vector)
|
||||
|
||||
-- Marker on F10.
|
||||
self.marker=MARKER:New(coord, self:_GetMarkerText())
|
||||
|
||||
-- Log ID string.
|
||||
self.lid=string.format("NAVFIX %s [%s] | ", tostring(self.name), tostring(self.typePoint))
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("Created NAVFIX"))
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Create a new NAVFIX class instance from a given COORDINATE.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #string Name Name of the fix. Should be unique!
|
||||
-- @param #string Type Type of the point. Default `NAVFIX.Type.POINT`.
|
||||
-- @param Core.Point#COORDINATE Coordinate Coordinate of the point.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:NewFromCoordinate(Name, Type, Coordinate)
|
||||
|
||||
-- Create a VECTOR from the coordinate.
|
||||
local Vector=VECTOR:NewFromVec(Coordinate)
|
||||
|
||||
-- Create NAVFIX.
|
||||
self=NAVFIX:NewFromVector(Name, Type, Vector)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Create a new NAVFIX instance from given latitude and longitude in degrees, minutes and seconds (DMS).
|
||||
-- @param #NAVFIX self
|
||||
-- @param #string Name Name of the fix. Should be unique!
|
||||
-- @param #string Type Type of the point. Default `NAVFIX.Type.POINT`.
|
||||
-- @param #string Latitude Latitude in DMS as string.
|
||||
-- @param #string Longitude Longitude in DMS as string.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:NewFromLLDMS(Name, Type, Latitude, Longitude)
|
||||
|
||||
-- Create a VECTOR from the coordinate.
|
||||
local Vector=VECTOR:NewFromLLDMS(Latitude, Longitude)
|
||||
|
||||
-- Create NAVFIX.
|
||||
self=NAVFIX:NewFromVector(Name, Type, Vector)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Create a new NAVFIX instance from given latitude and longitude in decimal degrees (DD).
|
||||
-- @param #NAVFIX self
|
||||
-- @param #string Name Name of the fix. Should be unique!
|
||||
-- @param #string Type Type of the point. Default `NAVFIX.Type.POINT`.
|
||||
-- @param #number Latitude Latitude in DD.
|
||||
-- @param #number Longitude Longitude in DD.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:NewFromLLDD(Name, Type, Latitude, Longitude)
|
||||
|
||||
-- Create a VECTOR from the coordinate.
|
||||
local Vector=VECTOR:NewFromLLDD(Latitude, Longitude)
|
||||
|
||||
-- Create NAVFIX.
|
||||
self=NAVFIX:NewFromVector(Name, Type, Vector)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Create a new NAVFIX class instance relative to a given other NAVFIX.
|
||||
-- You have to specify the distance and bearing from the new point to the given point. *E.g.*, for a distance of 5 NM and a bearing of 090° (West), the
|
||||
-- new nav point is created 5 NM East of the given nav point. The reason is that this corresponts to convention used in most maps.
|
||||
-- You can, however, use the `Reciprocal` switch to create the new point in the direction you specify.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #string Name Name of the fix. Should be unique!
|
||||
-- @param #string Type Type of navfix.
|
||||
-- @param #NAVFIX NavFix The given/existing navigation fix relative to which the new fix is created.
|
||||
-- @param #number Distance Distance from the given to the new point in nautical miles.
|
||||
-- @param #number Bearing Bearing [Deg] from the new point to the given one.
|
||||
-- @param #boolean Reciprocal If `true` the reciprocal `Bearing` is taken so it specifies the direction from the given point to the new one.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:NewFromNavFix(Name, Type, NavFix, Distance, Bearing, Reciprocal)
|
||||
|
||||
-- Convert magnetic to true bearing by adding magnetic declination, e.g. mag. bearing 10°M ==> true bearing 16°M (for 6° variation on Caucasus map)
|
||||
Bearing=Bearing+UTILS.GetMagneticDeclination()
|
||||
|
||||
if Reciprocal then
|
||||
Bearing=Bearing-180
|
||||
end
|
||||
|
||||
-- Translate.
|
||||
local Vector=NavFix.vector:Translate(UTILS.NMToMeters(Distance), Bearing, true)
|
||||
|
||||
self=NAVFIX:NewFromVector(Name, Type, Vector)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Set whether this is the intermediate fix (IF).
|
||||
-- @param #NAVFIX self
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetIntermediateFix(IntermediateFix)
|
||||
self.isIF=IntermediateFix
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set whether this is an initial approach fix (IAF).
|
||||
-- The IAF is the point where the initial approach segment of an instrument approach begins.
|
||||
-- It is usually a designated intersection, VHF omidirectional range (VOR) non-directional beacon (NDB)
|
||||
-- or distance measuring equipment (DME) fix.
|
||||
-- The IAF may be collocated with the intermediate fix (IF) of the instrument apprach an in such case they designate the
|
||||
-- beginning of the intermediate segment of the approach. When the IAF and the IF are combined, there is no inital approach segment.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #boolean IntermediateFix If `true`, this is an intermediate fix.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetInitialApproachFix(IntermediateFix)
|
||||
self.isIAF=IntermediateFix
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set whether this is the final approach fix (FAF).
|
||||
-- @param #NAVFIX self
|
||||
-- @param #boolean FinalApproachFix If `true`, this is a final approach fix.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetFinalApproachFix(FinalApproachFix)
|
||||
self.isFAF=FinalApproachFix
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set whether this is the final approach fix (FAF).
|
||||
-- @param #NAVFIX self
|
||||
-- @param #boolean FinalApproachFix If `true`, this is a final approach fix.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetMissedApproachFix(MissedApproachFix)
|
||||
self.isMAF=MissedApproachFix
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set minimum altitude.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #number Altitude Min altitude in feet.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetAltMin(Altitude)
|
||||
|
||||
self.altMin=Altitude
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set maximum altitude.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #number Altitude Max altitude in feet.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetAltMax(Altitude)
|
||||
|
||||
self.altMax=Altitude
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set mandatory altitude (min alt = max alt).
|
||||
-- @param #NAVFIX self
|
||||
-- @param #number Altitude Altitude in feet.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetAltMandatory(Altitude)
|
||||
|
||||
self.altMin=Altitude
|
||||
self.altMax=Altitude
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set minimum allowed speed at this fix.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #number Speed Min speed in knots.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetSpeedMin(Speed)
|
||||
|
||||
self.speedMin=Speed
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set maximum allowed speed at this fix.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #number Speed Max speed in knots.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetSpeedMax(Speed)
|
||||
|
||||
self.speedMax=Speed
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set mandatory speed (min speed = max speed) at this fix.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #number Speed Mandatory speed in knots.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetSpeedMandatory(Speed)
|
||||
|
||||
self.speedMin=Speed
|
||||
self.speedMax=Speed
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set whether this fix is compulsory.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #boolean Compulsory If `true`, this is a compusory fix. If `false` or nil, it is non-compulsory.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetCompulsory(Compulsory)
|
||||
self.isCompulsory=Compulsory
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set whether this is a fly-over fix fix.
|
||||
-- @param #NAVFIX self
|
||||
-- @param #boolean FlyOver If `true`, this is a fly over fix. If `false` or nil, it is not.
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:SetFlyOver(FlyOver)
|
||||
self.isFlyover=FlyOver
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the altitude in feet MSL. If min and max altitudes are set, it will return a random altitude between min and max.
|
||||
-- @param #NAVFIX self
|
||||
-- @return #number Altitude in feet MSL. Can be `nil`, if neither min nor max altitudes have beeen set.
|
||||
function NAVFIX:GetAltitude()
|
||||
|
||||
local alt=nil
|
||||
if self.altMin and self.altMax and self.altMin~=self.altMax then
|
||||
alt=math.random(self.altMin, self.altMax)
|
||||
elseif self.altMin then
|
||||
alt=self.altMin
|
||||
elseif self.altMax then
|
||||
alt=self.altMax
|
||||
end
|
||||
|
||||
return alt
|
||||
end
|
||||
|
||||
|
||||
--- Get the speed. If min and max speeds are set, it will return a random speed between min and max.
|
||||
-- @param #NAVFIX self
|
||||
-- @return #number Speed in knots. Can be `nil`, if neither min nor max speeds have beeen set.
|
||||
function NAVFIX:GetSpeed()
|
||||
|
||||
local speed=nil
|
||||
if self.speedMin and self.speedMax and self.speedMin~=self.speedMax then
|
||||
speed=math.random(self.speedMin, self.speedMax)
|
||||
elseif self.speedMin then
|
||||
speed=self.speedMin
|
||||
elseif self.speedMax then
|
||||
speed=self.speedMax
|
||||
end
|
||||
|
||||
return speed
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Add marker the NAVFIX on the F10 map.
|
||||
-- @param #NAVFIX self
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:MarkerShow()
|
||||
|
||||
self.marker:ToAll()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove marker of the NAVFIX from the F10 map.
|
||||
-- @param #NAVFIX self
|
||||
-- @return #NAVFIX self
|
||||
function NAVFIX:MarkerRemove()
|
||||
|
||||
self.marker:Remove()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Get text displayed in the F10 marker.
|
||||
-- @param #NAVFIX self
|
||||
-- @return #string Marker text.
|
||||
function NAVFIX:_GetMarkerText()
|
||||
|
||||
local altmin=self.altMin and tostring(self.altMin) or ""
|
||||
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("NAVFIX %s", self.name)
|
||||
if self.isIAF then
|
||||
text=text..string.format(" (IAF)")
|
||||
end
|
||||
if self.isIF then
|
||||
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
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- NAVAID class.
|
||||
-- @type NAVAID
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number verbose Verbosity of output.
|
||||
-- @extends Navigation.Point#NAVFIX
|
||||
|
||||
--- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # The NAVAID Concept
|
||||
--
|
||||
-- A NAVAID consists of one or multiple FLOTILLAs. These flotillas "live" in a WAREHOUSE that has a phyiscal struction (STATIC or UNIT) and can be captured or destroyed.
|
||||
--
|
||||
-- # Basic Setup
|
||||
--
|
||||
-- A new `NAVAID` object can be created with the @{#NAVAID.New}(`WarehouseName`, `FleetName`) function, where `WarehouseName` is the name of the static or unit object hosting the fleet
|
||||
-- and `FleetName` is the name you want to give the fleet. This must be *unique*!
|
||||
--
|
||||
-- myFleet=NAVAID:New("myWarehouseName", "1st Fleet")
|
||||
-- myFleet:SetPortZone(ZonePort1stFleet)
|
||||
-- myFleet:Start()
|
||||
--
|
||||
-- A fleet needs a *port zone*, which is set via the @{#NAVAID.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 @{#NAVAID.Start}() function. If the fleet is not started, it will not process any requests.
|
||||
--
|
||||
-- @field #NAVAID
|
||||
NAVAID = {
|
||||
ClassName = "NAVAID",
|
||||
verbose = 0,
|
||||
}
|
||||
|
||||
--- NAVAID class version.
|
||||
-- @field #string version
|
||||
NAVAID.version="0.0.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- TODO: Add frequencies. Which unit MHz, kHz, Hz?
|
||||
-- TODO: Add radial function
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Constructor
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Create a new NAVAID class instance.
|
||||
-- @param #NAVAID self
|
||||
-- @param #string Name Name/ident of this navaid.
|
||||
-- @param #string Type Type of the point. Default `NAVFIX.Type.POINT`.
|
||||
-- @param #string ZoneName Name of the zone to scan the scenery.
|
||||
-- @param #string SceneryName Name of the scenery object.
|
||||
-- @return #NAVAID self
|
||||
function NAVAID:NewFromScenery(Name, Type, ZoneName, SceneryName)
|
||||
|
||||
-- Get the zone.
|
||||
local zone=ZONE:FindByName(ZoneName)
|
||||
|
||||
-- Get coordinate.
|
||||
local Coordinate=zone:GetCoordinate()
|
||||
|
||||
-- Inherit everything from NAVFIX class.
|
||||
self=BASE:Inherit(self, NAVFIX:NewFromCoordinate(Name, Type, Coordinate)) -- #NAVAID
|
||||
|
||||
-- Set zone.
|
||||
self.zone=ZONE:FindByName(ZoneName)
|
||||
|
||||
-- Try to get the scenery object. Note not all can be found unfortunately.
|
||||
if SceneryName then
|
||||
self.scenery=SCENERY:FindByNameInZone(SceneryName, ZoneName)
|
||||
if not self.scenery then
|
||||
self:E(string.format("ERROR: Could not find scenery object %s in zone %s", SceneryName, ZoneName))
|
||||
end
|
||||
end
|
||||
|
||||
-- Alias.
|
||||
self.alias=string.format("%s %s %s", tostring(ZoneName), tostring(SceneryName), tostring(Type))
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("NAVAID %s | ", self.alias)
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("Created NAVAID!"))
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- User Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--- Set frequency the beacon transmits on.
|
||||
-- @param #NAVAID self
|
||||
-- @param #number Frequency Frequency in Hz.
|
||||
-- @return #NAVAID self
|
||||
function NAVAID:SetFrequency(Frequency)
|
||||
|
||||
self.frequency=Frequency
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set channel of, *e.g.*, TACAN beacons.
|
||||
-- @param #NAVAID self
|
||||
-- @param #number Channel The channel.
|
||||
-- @param #string Band The band either `"X"` (default) or `"Y"`.
|
||||
-- @return #NAVAID self
|
||||
function NAVAID:SetChannel(Channel, Band)
|
||||
|
||||
self.channel=Channel
|
||||
self.band=Band or "X"
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Private Functions
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Add private CLASS functions here.
|
||||
-- No private NAVAID functions yet.
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1,333 +0,0 @@
|
||||
--- **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,108 +0,0 @@
|
||||
--- **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
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -2798,7 +2798,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
||||
|
||||
end
|
||||
_RUNACT = subtitle
|
||||
alltext = alltext .. ";\n" .. subtitle
|
||||
--alltext = alltext .. ";\n" .. subtitle
|
||||
|
||||
-- Runway length.
|
||||
if self.rwylength then
|
||||
|
||||
@@ -974,6 +974,46 @@ function AIRWING:SetTakeoffAir()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to land straight in.
|
||||
-- @param #AIRWING self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function AIRWING:SetLandingStraightIn()
|
||||
self.OptionLandingStraightIn = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to land in pairs for groups > 1 aircraft.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetLandingForcePair()
|
||||
self.OptionLandingForcePair = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to NOT land in pairs.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetLandingRestrictPair()
|
||||
self.OptionLandingRestrictPair = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft of the AirWing to land after overhead break.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetLandingOverheadBreak()
|
||||
self.OptionLandingOverheadBreak = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Helicopter] Set the aircraft of the AirWing to prefer vertical takeoff and landing.
|
||||
-- @param #AIRWING self
|
||||
-- @return #AIRWING self
|
||||
function AIRWING:SetOptionPreferVerticalLanding()
|
||||
self.OptionPreferVerticalLanding = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set despawn after landing. Aircraft will be despawned after the landing event.
|
||||
-- Can help to avoid DCS AI taxiing issues.
|
||||
-- @param #AIRWING self
|
||||
@@ -1464,7 +1504,21 @@ function AIRWING:onafterFlightOnMission(From, Event, To, FlightGroup, Mission)
|
||||
self:T(self.lid..string.format("Group %s on %s mission %s", FlightGroup:GetName(), Mission:GetType(), Mission:GetName()))
|
||||
if self.UseConnectedOpsAwacs and self.ConnectedOpsAwacs then
|
||||
self.ConnectedOpsAwacs:__FlightOnMission(2,FlightGroup,Mission)
|
||||
end
|
||||
end
|
||||
-- Landing Options
|
||||
if self.OptionLandingForcePair then
|
||||
FlightGroup:SetOptionLandingForcePair()
|
||||
elseif self.OptionLandingOverheadBreak then
|
||||
FlightGroup:SetOptionLandingOverheadBreak()
|
||||
elseif self.OptionLandingRestrictPair then
|
||||
FlightGroup:SetOptionLandingRestrictPair()
|
||||
elseif self.OptionLandingStraightIn then
|
||||
FlightGroup:SetOptionLandingStraightIn()
|
||||
end
|
||||
-- Landing Options Helo
|
||||
if self.OptionPreferVerticalLanding then
|
||||
FlightGroup:SetOptionPreferVertical()
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -397,6 +397,7 @@ AUFTRAG = {
|
||||
conditionPush = {},
|
||||
conditionSuccessSet = false,
|
||||
conditionFailureSet = false,
|
||||
repeatDelay = 1,
|
||||
}
|
||||
|
||||
--- Global mission counter.
|
||||
@@ -1428,7 +1429,7 @@ function AUFTRAG:NewCAP(ZoneCAP, Altitude, Speed, Coordinate, Heading, Leg, Targ
|
||||
mission:_SetLogID()
|
||||
|
||||
-- DCS task parameters:
|
||||
mission.engageZone=ZoneCAP
|
||||
mission.engageZone=ZoneCAP or Coordinate
|
||||
mission.engageTargetTypes=TargetTypes or {"Air"}
|
||||
|
||||
-- Mission options:
|
||||
@@ -1715,9 +1716,45 @@ function AUFTRAG:NewSEAD(Target, Altitude)
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIR]** Create a SEAD in Zone mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Zone#ZONE TargetZone The target zone to attack.
|
||||
-- @param #number Altitude Engage altitude in feet. Default 25000 ft.
|
||||
-- @param #table TargetTypes Table of string of DCS known target types, defaults to {"Air Defence"}. See [DCS Target Attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes)
|
||||
-- @param #number Duration Engage this much time when the AUFTRAG starts executing.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewSEADInZone(TargetZone, Altitude, TargetTypes, Duration)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.SEAD)
|
||||
|
||||
mission:_TargetFromObject(TargetZone)
|
||||
|
||||
-- DCS Task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||
mission.engageZone = TargetZone
|
||||
mission.engageTargetTypes = TargetTypes or {"Air Defence"}
|
||||
|
||||
-- Mission options:
|
||||
mission.missionTask=ENUMS.MissionTask.SEAD
|
||||
mission.missionAltitude=mission.engageAltitude
|
||||
mission.missionFraction=0.2
|
||||
mission.optionROE=ENUMS.ROE.OpenFire
|
||||
mission.optionROT=ENUMS.ROT.EvadeFire
|
||||
|
||||
mission.categories={AUFTRAG.Category.AIRCRAFT}
|
||||
|
||||
mission.DCStask=mission:GetDCSMissionTask()
|
||||
|
||||
mission:SetDuration(Duration or 1800)
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
--- **[AIR]** Create a STRIKE mission. Flight will attack the closest map object to the specified coordinate.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE Target The target coordinate. Can also be given as a GROUP, UNIT, STATIC or TARGET object.
|
||||
-- @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 #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.
|
||||
-- @return #AUFTRAG self
|
||||
@@ -1749,11 +1786,12 @@ end
|
||||
--- **[AIR]** Create a BOMBING mission. Flight will drop bombs a specified coordinate.
|
||||
-- See [DCS task bombing](https://wiki.hoggitworld.com/view/DCS_task_bombing).
|
||||
-- @param #AUFTRAG self
|
||||
-- @param Core.Point#COORDINATE Target Target coordinate. Can also be specified as a GROUP, UNIT, STATIC or TARGET object.
|
||||
-- @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 #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 #boolean Divebomb If true, use a dive bombing attack approach.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType)
|
||||
function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType, Divebomb)
|
||||
|
||||
local mission=AUFTRAG:New(AUFTRAG.Type.BOMBING)
|
||||
|
||||
@@ -1770,6 +1808,7 @@ function AUFTRAG:NewBOMBING(Target, Altitude, EngageWeaponType)
|
||||
mission.missionFraction=0.5
|
||||
mission.optionROE=ENUMS.ROE.OpenFire
|
||||
mission.optionROT=ENUMS.ROT.NoReaction -- No reaction is better.
|
||||
mission.optionDivebomb = Divebomb or nil
|
||||
|
||||
-- Evaluate result after 5 min. We might need time until the bombs have dropped and targets have been detroyed.
|
||||
mission.dTevaluate=5*60
|
||||
@@ -2966,6 +3005,16 @@ function AUFTRAG:SetRepeat(Nrepeat)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- **[LEGION, COMMANDER, CHIEF]** Set the repeat delay in seconds after a mission is successful/failed. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number Nrepeat Repeat delay in seconds. Default 1.
|
||||
-- @return #AUFTRAG self
|
||||
function AUFTRAG:SetRepeatDelay(RepeatDelay)
|
||||
self.repeatDelay = RepeatDelay
|
||||
return self
|
||||
end
|
||||
|
||||
--- **[LEGION, COMMANDER, CHIEF]** Set how many times the mission is repeated if it fails. Only valid if the mission is handled by a LEGION (AIRWING, BRIGADE, FLEET) or higher level.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number Nrepeat Number of repeats. Default 0.
|
||||
@@ -4765,6 +4814,8 @@ end
|
||||
-- @return #boolean If `true`, all groups are done with the mission.
|
||||
function AUFTRAG:CheckGroupsDone()
|
||||
|
||||
local fsmState = self:GetState()
|
||||
|
||||
-- Check status of all OPS groups.
|
||||
for groupname,data in pairs(self.groupdata) do
|
||||
local groupdata=data --#AUFTRAG.GroupData
|
||||
@@ -4822,6 +4873,11 @@ function AUFTRAG:CheckGroupsDone()
|
||||
self:T(self.lid..string.format("CheckGroupsDone: Mission is STARTED state %s [FSM=%s] but count of alive OPSGROUP is zero. Mission DONE!", self.status, self:GetState()))
|
||||
return true
|
||||
end
|
||||
|
||||
if (self:IsStarted() or self:IsExecuting()) and (fsmState == AUFTRAG.Status.STARTED or fsmState == AUFTRAG.Status.EXECUTING) 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 false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
@@ -5160,7 +5216,7 @@ function AUFTRAG:onafterSuccess(From, Event, To)
|
||||
|
||||
-- Repeat mission.
|
||||
self:T(self.lid..string.format("Mission SUCCESS! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
||||
self:Repeat()
|
||||
self:__Repeat(self.repeatDelay)
|
||||
|
||||
else
|
||||
|
||||
@@ -5202,7 +5258,7 @@ function AUFTRAG:onafterFailed(From, Event, To)
|
||||
|
||||
-- Repeat mission.
|
||||
self:T(self.lid..string.format("Mission FAILED! Repeating mission for the %d time (max %d times) ==> Repeat mission!", self.repeated+1, N))
|
||||
self:Repeat()
|
||||
self:__Repeat(self.repeatDelay)
|
||||
|
||||
else
|
||||
|
||||
@@ -6108,10 +6164,13 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
-- BOMBING Mission --
|
||||
---------------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskBombing(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType, Divebomb)
|
||||
local coords = self.engageTarget:GetCoordinates()
|
||||
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, self.optionDivebomb)
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
end
|
||||
|
||||
table.insert(DCStasks, DCStask)
|
||||
|
||||
elseif self.type==AUFTRAG.Type.STRAFING then
|
||||
|
||||
----------------------
|
||||
@@ -6147,8 +6206,16 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
-----------------
|
||||
-- CAP Mission --
|
||||
-----------------
|
||||
|
||||
local DCStask=CONTROLLABLE.EnRouteTaskEngageTargetsInZone(nil, self.engageZone:GetVec2(), self.engageZone:GetRadius(), self.engageTargetTypes, Priority)
|
||||
|
||||
local Vec2 = self.engageZone:GetVec2()
|
||||
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)
|
||||
|
||||
@@ -6302,18 +6369,47 @@ function AUFTRAG:GetDCSMissionTask()
|
||||
-- Add enroute task SEAD. Disabled that here because the group enganges everything on its route.
|
||||
--local DCStask=CONTROLLABLE.EnRouteTaskSEAD(nil, self.TargetType)
|
||||
--table.insert(self.enrouteTasks, DCStask)
|
||||
|
||||
self:_GetDCSAttackTask(self.engageTarget, DCStasks)
|
||||
|
||||
|
||||
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,2956984318)
|
||||
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)
|
||||
|
||||
end
|
||||
|
||||
elseif self.type==AUFTRAG.Type.STRIKE then
|
||||
|
||||
--------------------
|
||||
-- STRIKE Mission --
|
||||
--------------------
|
||||
|
||||
local DCStask=CONTROLLABLE.TaskAttackMapObject(nil, self:GetTargetVec2(), self.engageAsGroup, self.engageWeaponExpend, self.engageQuantity, self.engageDirection, self.engageAltitude, self.engageWeaponType)
|
||||
local coords = self.engageTarget:GetCoordinates()
|
||||
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
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **applevangelist**
|
||||
-- @date Last Update Jan 2025
|
||||
-- @date Last Update July 2025
|
||||
-- @module Ops.AWACS
|
||||
-- @image OPS_AWACS.jpg
|
||||
|
||||
@@ -237,7 +237,7 @@ do
|
||||
-- -- Callsign will be "Focus". We'll be a Angels 30, doing 300 knots, orbit leg to 88deg with a length of 25nm.
|
||||
-- testawacs:SetAwacsDetails(CALLSIGN.AWACS.Focus,1,30,300,88,25)
|
||||
-- -- Set up SRS on port 5010 - change the below to your path and port
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010)
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010)
|
||||
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
||||
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
||||
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
||||
@@ -255,7 +255,7 @@ do
|
||||
-- -- The CAP station zone is called "Fremont". We will be on 255 AM. Note the Orbit Zone is given as *nil* in the `New()`-Statement
|
||||
-- local testawacs = AWACS:New("GCI Senaki",AwacsAW,"blue",AIRBASE.Caucasus.Senaki_Kolkhi,nil,ZONE:FindByName("Rock"),"Fremont",255,radio.modulation.AM )
|
||||
-- -- Set up SRS on port 5010 - change the below to your path and port
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone","female","en-GB",5010)
|
||||
-- testawacs:SetSRS("C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio","female","en-GB",5010)
|
||||
-- -- Add a "red" border we don't want to cross, set up in the mission editor with a late activated helo named "Red Border#ZONE_POLYGON"
|
||||
-- testawacs:SetRejectionZone(ZONE:FindByName("Red Border"))
|
||||
-- -- Our CAP flight will have the callsign "Ford", we want 4 AI planes, Time-On-Station is four hours, doing 300 kn IAS.
|
||||
@@ -509,7 +509,7 @@ do
|
||||
-- @field #AWACS
|
||||
AWACS = {
|
||||
ClassName = "AWACS", -- #string
|
||||
version = "0.2.71", -- #string
|
||||
version = "0.2.72", -- #string
|
||||
lid = "", -- #string
|
||||
coalition = coalition.side.BLUE, -- #number
|
||||
coalitiontxt = "blue", -- #string
|
||||
@@ -1123,7 +1123,7 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
||||
self.EscortMissionReplacement = {}
|
||||
|
||||
-- SRS
|
||||
self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.PathToSRS = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.Gender = "female"
|
||||
self.Culture = "en-GB"
|
||||
self.Voice = nil
|
||||
@@ -1242,6 +1242,8 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
||||
self:AddTransition("*", "Intercept", "*")
|
||||
self:AddTransition("*", "InterceptSuccess", "*")
|
||||
self:AddTransition("*", "InterceptFailure", "*")
|
||||
self:AddTransition("*", "VIDSuccess", "*")
|
||||
self:AddTransition("*", "VIDFailure", "*")
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||
|
||||
|
||||
@@ -1365,18 +1367,38 @@ function AWACS:New(Name,AirWing,Coalition,AirbaseName,AwacsOrbit,OpsZone,Station
|
||||
-- @param #string To To state.
|
||||
|
||||
--- On After "InterceptSuccess" event. Intercept successful.
|
||||
-- @function [parent=#AWACS] OnAfterIntercept
|
||||
-- @function [parent=#AWACS] OnAfterInterceptSuccess
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
--- On After "InterceptFailure" event. Intercept failure.
|
||||
-- @function [parent=#AWACS] OnAfterIntercept
|
||||
-- @function [parent=#AWACS] OnAfterInterceptFailure
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
|
||||
--- On After "VIDSuccess" event. Intercept successful.
|
||||
-- @function [parent=#AWACS] OnAfterVIDSuccess
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #number GID Managed group ID (Player)
|
||||
-- @param Wrapper.Group#GROUP Group (Player) Group done the VID
|
||||
-- @param #AWACS.ManagedContact Contact The contact that was VID'd
|
||||
|
||||
--- On After "VIDFailure" event. Intercept failure.
|
||||
-- @function [parent=#AWACS] OnAfterVIDFailure
|
||||
-- @param #AWACS self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #number GID Managed group ID (Player)
|
||||
-- @param Wrapper.Group#GROUP Group (Player) Group done the VID
|
||||
-- @param #AWACS.ManagedContact Contact The contact that was VID'd
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -2091,7 +2113,7 @@ end
|
||||
|
||||
--- [User] Set AWACS SRS TTS details - see @{Sound.SRS} for details. `SetSRS()` will try to use as many attributes configured with @{Sound.SRS#MSRS.LoadConfigFile}() as possible.
|
||||
-- @param #AWACS self
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #string Gender Defaults to "male"
|
||||
-- @param #string Culture Defaults to "en-US"
|
||||
-- @param #number Port Defaults to 5002
|
||||
@@ -2104,7 +2126,7 @@ end
|
||||
-- @return #AWACS self
|
||||
function AWACS:SetSRS(PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Backend)
|
||||
self:T(self.lid.."SetSRS")
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
self.Gender = Gender or MSRS.gender or "male"
|
||||
self.Culture = Culture or MSRS.culture or "en-US"
|
||||
self.Port = Port or MSRS.port or 5002
|
||||
@@ -3263,12 +3285,14 @@ function AWACS:_VID(Group,Declaration)
|
||||
local vidpos = self.gettext:GetEntry("VIDPOS",self.locale)
|
||||
text = string.format(vidpos,Callsign,self.callsigntxt, Declaration)
|
||||
self:T(text)
|
||||
self:__VIDSuccess(3,GID,group,cluster)
|
||||
else
|
||||
-- too far away
|
||||
self:T("Contact VID not close enough")
|
||||
local vidneg = self.gettext:GetEntry("VIDNEG",self.locale)
|
||||
text = string.format(vidneg,Callsign,self.callsigntxt)
|
||||
self:T(text)
|
||||
self:__VIDFailure(3,GID,group,cluster)
|
||||
end
|
||||
self:_NewRadioEntry(text,text,GID,Outcome,true,true,false,true)
|
||||
end
|
||||
|
||||
@@ -599,80 +599,7 @@ function BRIGADE:onafterStatus(From, Event, To)
|
||||
text=text..string.format("\n* %s: spawned=%s", asset.spawngroupname, tostring(asset.spawned))
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
if self.verbose>=3 then
|
||||
|
||||
-- Count numbers
|
||||
local Ntotal=0
|
||||
local Nspawned=0
|
||||
local Nrequested=0
|
||||
local Nreserved=0
|
||||
local Nstock=0
|
||||
|
||||
local text="\n===========================================\n"
|
||||
text=text.."Assets:"
|
||||
local legion=self --Ops.Legion#LEGION
|
||||
|
||||
for _,_cohort in pairs(legion.cohorts) do
|
||||
local cohort=_cohort --Ops.Cohort#COHORT
|
||||
|
||||
for _,_asset in pairs(cohort.assets) do
|
||||
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
||||
|
||||
local state="In Stock"
|
||||
if asset.flightgroup then
|
||||
state=asset.flightgroup:GetState()
|
||||
local mission=legion:GetAssetCurrentMission(asset)
|
||||
if mission then
|
||||
state=state..string.format(", Mission \"%s\" [%s]", mission:GetName(), mission:GetType())
|
||||
end
|
||||
else
|
||||
if asset.spawned then
|
||||
env.info("FF ERROR: asset has opsgroup but is NOT spawned!")
|
||||
end
|
||||
if asset.requested and asset.isReserved then
|
||||
env.info("FF ERROR: asset is requested and reserved. Should not be both!")
|
||||
state="Reserved+Requested!"
|
||||
elseif asset.isReserved then
|
||||
state="Reserved"
|
||||
elseif asset.requested then
|
||||
state="Requested"
|
||||
end
|
||||
end
|
||||
|
||||
-- Text.
|
||||
text=text..string.format("\n[UID=%03d] %s Legion=%s [%s]: State=%s [RID=%s]",
|
||||
asset.uid, asset.spawngroupname, legion.alias, cohort.name, state, tostring(asset.rid))
|
||||
|
||||
|
||||
if asset.spawned then
|
||||
Nspawned=Nspawned+1
|
||||
end
|
||||
if asset.requested then
|
||||
Nrequested=Nrequested+1
|
||||
end
|
||||
if asset.isReserved then
|
||||
Nreserved=Nreserved+1
|
||||
end
|
||||
if not (asset.spawned or asset.requested or asset.isReserved) then
|
||||
Nstock=Nstock+1
|
||||
end
|
||||
|
||||
Ntotal=Ntotal+1
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
text=text.."\n-------------------------------------------"
|
||||
text=text..string.format("\nNstock = %d", Nstock)
|
||||
text=text..string.format("\nNreserved = %d", Nreserved)
|
||||
text=text..string.format("\nNrequested = %d", Nrequested)
|
||||
text=text..string.format("\nNspawned = %d", Nspawned)
|
||||
text=text..string.format("\nNtotal = %d (=%d)", Ntotal, Nstock+Nspawned+Nrequested+Nreserved)
|
||||
text=text.."\n==========================================="
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -136,6 +136,7 @@ COMMANDER = {
|
||||
awacsZones = {},
|
||||
tankerZones = {},
|
||||
limitMission = {},
|
||||
maxMissionsAssignPerCycle = 1,
|
||||
}
|
||||
|
||||
--- COMMANDER class version.
|
||||
@@ -1535,6 +1536,8 @@ function COMMANDER:CheckMissionQueue()
|
||||
end
|
||||
end
|
||||
|
||||
local missionsAssigned = 0
|
||||
|
||||
-- Loop over missions in queue.
|
||||
for _,_mission in pairs(self.missionqueue) do
|
||||
local mission=_mission --Ops.Auftrag#AUFTRAG
|
||||
@@ -1594,9 +1597,12 @@ function COMMANDER:CheckMissionQueue()
|
||||
-- Recruited assets but no requested escort available. Unrecruit assets!
|
||||
LEGION.UnRecruitAssets(assets, mission)
|
||||
end
|
||||
|
||||
-- Only ONE mission is assigned.
|
||||
return
|
||||
|
||||
missionsAssigned = missionsAssigned + 1
|
||||
if missionsAssigned >= (self.maxMissionsAssignPerCycle or 1) then
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
@@ -1611,6 +1617,16 @@ function COMMANDER:CheckMissionQueue()
|
||||
|
||||
end
|
||||
|
||||
--- Set how many missions can be assigned in a single status iteration. (eg. This is useful for persistent missions where you need to load all AUFTRAGs on mission start and then change it back to default)
|
||||
--- Warning: Increasing this value will increase the number of missions started per iteration and thus may lead to performance issues if too many missions are started at once.
|
||||
-- @param #COMMANDER self
|
||||
-- @param #number Number of missions assigned per status iteration. Default is 1.
|
||||
-- @return #COMMANDER self.
|
||||
function COMMANDER:SetMaxMissionsAssignPerCycle(MaxMissionsAssignPerCycle)
|
||||
self.maxMissionsAssignPerCycle = MaxMissionsAssignPerCycle or 1
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get cohorts.
|
||||
-- @param #COMMANDER self
|
||||
-- @param #table Legions Special legions.
|
||||
@@ -1670,9 +1686,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation)
|
||||
for _,_legion in pairs(Legions or {}) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=true
|
||||
if legion:IsAirwing() then
|
||||
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||
end
|
||||
|
||||
-- Legion has to be running.
|
||||
if legion:IsRunning() and Runway then
|
||||
|
||||
@@ -1703,9 +1722,12 @@ function COMMANDER:_GetCohorts(Legions, Cohorts, Operation)
|
||||
for _,_legion in pairs(self.legions) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=true
|
||||
if legion:IsAirwing() then
|
||||
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||
end
|
||||
|
||||
-- Legion has to be running.
|
||||
if legion:IsRunning() and Runway then
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
-- @field #boolean DespawnAfterLanding
|
||||
-- @field #boolean DespawnAfterHolding
|
||||
-- @field #list<Ops.Auftrag#AUFTRAG> ListOfAuftrag
|
||||
-- @field #string defaulttakeofftype Take off type
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- *“Airspeed, altitude, and brains. Two are always needed to successfully complete the flight.”* -- Unknown.
|
||||
@@ -223,7 +224,8 @@ EASYGCICAP = {
|
||||
ReadyFlightGroups = {},
|
||||
DespawnAfterLanding = false,
|
||||
DespawnAfterHolding = true,
|
||||
ListOfAuftrag = {}
|
||||
ListOfAuftrag = {},
|
||||
defaulttakeofftype = "hot",
|
||||
}
|
||||
|
||||
--- Internal Squadron data type
|
||||
@@ -259,7 +261,7 @@ EASYGCICAP = {
|
||||
|
||||
--- EASYGCICAP class version.
|
||||
-- @field #string version
|
||||
EASYGCICAP.version="0.1.18"
|
||||
EASYGCICAP.version="0.1.23"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@@ -312,6 +314,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
||||
self.DespawnAfterLanding = false
|
||||
self.DespawnAfterHolding = true
|
||||
self.ListOfAuftrag = {}
|
||||
self.defaulttakeofftype = "hot"
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("EASYGCICAP %s | ", self.alias)
|
||||
@@ -400,6 +403,16 @@ function EASYGCICAP:SetDefaultRepeatOnFailure(Retries)
|
||||
return self
|
||||
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
|
||||
-- @param #EASYGCICAP self
|
||||
-- @param #number Speed Speed defaults to 300
|
||||
@@ -569,6 +582,13 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
||||
local DespawnAfterLanding = self.DespawnAfterLanding
|
||||
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
|
||||
local CAP_Wing = AIRWING:New(Airbasename,Alias)
|
||||
CAP_Wing:SetVerbosityLevel(0)
|
||||
@@ -596,9 +616,8 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
||||
if #self.ManagedREC > 0 then
|
||||
CAP_Wing:SetNumberRecon(1)
|
||||
end
|
||||
--local PatrolCoordinateKutaisi = ZONE:New(CapZoneName):GetCoordinate()
|
||||
--CAP_Wing:AddPatrolPointCAP(PatrolCoordinateKutaisi,self.capalt,UTILS.KnotsToAltKIAS(self.capspeed,self.capalt),self.capdir,self.capleg)
|
||||
CAP_Wing:SetTakeoffHot()
|
||||
|
||||
CAP_Wing:SetTakeoffType(self.defaulttakeofftype)
|
||||
CAP_Wing:SetLowFuelThreshold(0.3)
|
||||
CAP_Wing.RandomAssetScore = math.random(50,100)
|
||||
CAP_Wing:Start()
|
||||
@@ -606,6 +625,9 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
||||
local Intel = self.Intel
|
||||
|
||||
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)
|
||||
local flightgroup = Flightgroup -- Ops.FlightGroup#FLIGHTGROUP
|
||||
@@ -619,7 +641,7 @@ function EASYGCICAP:_AddAirwing(Airbasename, Alias)
|
||||
flightgroup:GetGroup():SetOptionRadarUsingForContinousSearch()
|
||||
if Mission.type ~= AUFTRAG.Type.TANKER and Mission.type ~= AUFTRAG.Type.AWACS and Mission.type ~= AUFTRAG.Type.RECON then
|
||||
flightgroup:SetDetection(true)
|
||||
flightgroup:SetEngageDetectedOn(self.engagerange,{"Air"},self.GoZoneSet,self.NoGoZoneSet)
|
||||
flightgroup:SetEngageDetectedOn(engagerange,{"Air"},GoZoneSet,NoGoZoneSet)
|
||||
flightgroup:SetOutOfAAMRTB()
|
||||
if CapFormation then
|
||||
flightgroup:GetGroup():SetOption(AI.Option.Air.id.FORMATION,CapFormation)
|
||||
@@ -763,6 +785,11 @@ function EASYGCICAP:_SetTankerPatrolPoints()
|
||||
self:T(self.lid.."_SetTankerPatrolPoints")
|
||||
for _,_data in pairs(self.ManagedTK) do
|
||||
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 Coordinate = data.Coordinate
|
||||
local Altitude = data.Altitude
|
||||
@@ -782,6 +809,11 @@ function EASYGCICAP:_SetAwacsPatrolPoints()
|
||||
self:T(self.lid.."_SetAwacsPatrolPoints")
|
||||
for _,_data in pairs(self.ManagedEWR) do
|
||||
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 Coordinate = data.Coordinate
|
||||
local Altitude = data.Altitude
|
||||
@@ -801,6 +833,11 @@ function EASYGCICAP:_SetCAPPatrolPoints()
|
||||
self:T(self.lid.."_SetCAPPatrolPoints")
|
||||
for _,_data in pairs(self.ManagedCP) do
|
||||
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 Coordinate = data.Coordinate
|
||||
local Altitude = data.Altitude
|
||||
@@ -820,6 +857,11 @@ function EASYGCICAP:_SetReconPatrolPoints()
|
||||
self:T(self.lid.."_SetReconPatrolPoints")
|
||||
for _,_data in pairs(self.ManagedREC) do
|
||||
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 Coordinate = data.Coordinate
|
||||
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
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("FLIGHTGROUP %s | ", self.groupname)
|
||||
self.lid=string.format("FLIGHTGROUP %s | ", self.groupname or "N/A")
|
||||
|
||||
-- Defaults
|
||||
self:SetDefaultROE()
|
||||
@@ -779,6 +779,61 @@ function FLIGHTGROUP:SetJettisonWeapons(Switch)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to land straight in.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingStraightIn()
|
||||
self.OptionLandingStraightIn = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingStraightIn()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to land in pairs.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingForcePair()
|
||||
self.OptionLandingForcePair = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingForcePair()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to NOT land in pairs.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingRestrictPair()
|
||||
self.OptionLandingRestrictPair = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingRestrictPair()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the aircraft to land after overhead break.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionLandingOverheadBreak()
|
||||
self.OptionLandingOverheadBreak = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():SetOptionLandingOverheadBreak()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- [HELICOPTER] Set the aircraft to prefer takeoff and landing vertically.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetOptionPreferVertical()
|
||||
self.OptionPreferVertical = true
|
||||
if self:GetGroup():IsAlive() then
|
||||
self:GetGroup():OptionPreferVerticalLanding()
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set if group is ready for taxi/takeoff if controlled by a `FLIGHTCONTROL`.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @param #boolean ReadyTO If `true`, flight is ready for takeoff.
|
||||
@@ -2002,6 +2057,9 @@ function FLIGHTGROUP:onafterElementAirborne(From, Event, To, Element)
|
||||
|
||||
-- Debug info.
|
||||
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.
|
||||
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.AIRBORNE)
|
||||
@@ -3076,7 +3134,7 @@ function FLIGHTGROUP:onbeforeLandAtAirbase(From, Event, To, airbase)
|
||||
local Tsuspend=nil
|
||||
|
||||
if airbase==nil then
|
||||
self:T(self.lid.."ERROR: Airbase is nil in LandAtAirase() call!")
|
||||
self:T(self.lid.."ERROR: Airbase is nil in LandAtAirbase() call!")
|
||||
allowed=false
|
||||
end
|
||||
|
||||
@@ -4494,6 +4552,11 @@ function FLIGHTGROUP:GetParkingSpot(element, maxdist, airbase)
|
||||
-- Airbase.
|
||||
airbase=airbase or self:GetClosestAirbase()
|
||||
|
||||
if airbase == nil then
|
||||
self:T(self.lid.."No airbase found for element "..element.name)
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Parking table of airbase.
|
||||
local parking=airbase.parking --:GetParkingSpotsTable()
|
||||
|
||||
|
||||
@@ -2324,7 +2324,7 @@ INTEL_DLINK = {
|
||||
verbose = 0,
|
||||
lid = nil,
|
||||
alias = nil,
|
||||
cachetime = 300,
|
||||
cachetime = 120,
|
||||
interval = 20,
|
||||
contacts = {},
|
||||
clusters = {},
|
||||
@@ -2333,7 +2333,7 @@ INTEL_DLINK = {
|
||||
|
||||
--- Version string
|
||||
-- @field #string version
|
||||
INTEL_DLINK.version = "0.0.1"
|
||||
INTEL_DLINK.version = "0.0.2"
|
||||
|
||||
--- Function to instantiate a new object
|
||||
-- @param #INTEL_DLINK self
|
||||
@@ -2384,15 +2384,15 @@ function INTEL_DLINK:New(Intels, Alias, Interval, Cachetime)
|
||||
self.alias="SPECTRE"
|
||||
end
|
||||
|
||||
-- Cache time
|
||||
self.cachetime = Cachetime or 300
|
||||
|
||||
-- Interval
|
||||
self.interval = Interval or 20
|
||||
|
||||
-- Set some string id for output to DCS.log file.
|
||||
self.lid=string.format("INTEL_DLINK %s | ", self.alias)
|
||||
|
||||
-- Cache time
|
||||
self:SetDLinkCacheTime(Cachetime or 120)
|
||||
|
||||
-- Start State.
|
||||
self:SetStartState("Stopped")
|
||||
|
||||
@@ -2477,6 +2477,16 @@ function INTEL_DLINK:onafterStart(From, Event, To)
|
||||
return self
|
||||
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
|
||||
-- @param #INTEL_DLINK self
|
||||
-- @param #string From The From state
|
||||
|
||||
@@ -2513,9 +2513,12 @@ function LEGION._GetCohorts(Legions, Cohorts, Operation, OpsQueue)
|
||||
for _,_legion in pairs(Legions or {}) do
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=legion:IsAirwing() and legion:IsRunwayOperational() or true
|
||||
|
||||
-- Check that runway is operational.
|
||||
local Runway=true
|
||||
if legion:IsAirwing() then
|
||||
Runway=legion:IsRunwayOperational() and legion.airbase and legion.airbase:GetCoalition() == legion:GetCoalition()
|
||||
end
|
||||
|
||||
-- Legion has to be running.
|
||||
if legion:IsRunning() and Runway then
|
||||
|
||||
|
||||
@@ -445,7 +445,6 @@ OPSGROUP.TaskType={
|
||||
-- @field Wrapper.Marker#MARKER marker Marker on the F10 map.
|
||||
-- @field #string formation Ground formation. Similar to action but on/off road.
|
||||
-- @field #number missionUID Mission UID (Auftragsnr) this waypoint belongs to.
|
||||
-- @field Navigation.FlightPlan#FLIGHTPLAN flightplan Flightplan this waypoint belongs to.
|
||||
|
||||
--- Cargo Carrier status.
|
||||
-- @type OPSGROUP.CarrierStatus
|
||||
@@ -574,11 +573,6 @@ function OPSGROUP:New(group)
|
||||
|
||||
-- Set DCS group and controller.
|
||||
self.dcsgroup=self:GetDCSGroup()
|
||||
|
||||
if not self.dcsgroup then
|
||||
return
|
||||
end
|
||||
|
||||
self.controller=self.dcsgroup:getController()
|
||||
|
||||
-- Category.
|
||||
@@ -5595,10 +5589,13 @@ function OPSGROUP:onafterUnpauseMission(From, Event, To)
|
||||
-- Debug info.
|
||||
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.
|
||||
self:MissionStart(mission)
|
||||
|
||||
-- Remove mission from
|
||||
-- Remove mission from pausedmissions queue
|
||||
for i,mid in pairs(self.pausedmissions) do
|
||||
--self:T(self.lid..string.format("Checking paused mission", mid))
|
||||
if mid==mission.auftragsnummer then
|
||||
@@ -6238,7 +6235,7 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
end
|
||||
|
||||
-- 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 then
|
||||
if (self.speedMax<=3.6 or mission.teleport) and not mission.unpaused then
|
||||
|
||||
-- Teleport to waypoint coordinate. Mission will not be paused.
|
||||
self:Teleport(waypointcoord, nil, true)
|
||||
@@ -11355,9 +11352,9 @@ function OPSGROUP:_SimpleTaskFunction(Function, uid)
|
||||
return DCSTask
|
||||
end
|
||||
|
||||
--- Enhanced waypoint table.
|
||||
--- Enhance waypoint table.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #OPSGROUP.Waypoint waypoint Waypoint data.
|
||||
-- @param #OPSGROUP.Waypoint Waypoint data.
|
||||
-- @return #OPSGROUP.Waypoint Modified waypoint data.
|
||||
function OPSGROUP:_CreateWaypoint(waypoint)
|
||||
|
||||
@@ -12785,7 +12782,7 @@ function OPSGROUP:_UpdatePosition()
|
||||
self.positionLast=self.position or self:GetVec3()
|
||||
self.headingLast=self.heading or self:GetHeading()
|
||||
self.orientXLast=self.orientX or self:GetOrientationX()
|
||||
self.velocityLast=self.velocity or self.group:GetVelocityMPS()
|
||||
self.velocityLast=self.velocity or self.group:GetVelocityMPS()
|
||||
|
||||
-- Current state.
|
||||
self.position=self:GetVec3()
|
||||
@@ -13613,24 +13610,20 @@ end
|
||||
-- @return Core.Point#COORDINATE The coordinate of the object.
|
||||
function OPSGROUP:_CoordinateFromObject(Object)
|
||||
|
||||
env.info("FF coordfrom object")
|
||||
if Object then
|
||||
if VECTOR._IsVector(Object) then
|
||||
env.info("FF VECTOR")
|
||||
return Object:GetCoordinate()
|
||||
elseif Object:IsInstanceOf("COORDINATE") then
|
||||
if Object:IsInstanceOf("COORDINATE") then
|
||||
return Object
|
||||
else
|
||||
if Object:IsInstanceOf("POSITIONABLE") or Object:IsInstanceOf("ZONE_BASE") then
|
||||
self:E(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate")
|
||||
self:T(self.lid.."WARNING: Coordinate is not a COORDINATE but a POSITIONABLE or ZONE. Trying to get coordinate")
|
||||
local coord=Object:GetCoordinate()
|
||||
return coord
|
||||
else
|
||||
self:E(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!")
|
||||
self:T(self.lid.."ERROR: Coordinate is neither a COORDINATE nor any POSITIONABLE or ZONE!")
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E(self.lid.."ERROR: Object passed is nil!")
|
||||
self:T(self.lid.."ERROR: Object passed is nil!")
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
@@ -53,7 +53,8 @@
|
||||
-- @field #number threatlevelCapture Threat level necessary to capture a zone.
|
||||
-- @field Core.Set#SET_UNIT ScanUnitSet Set of scanned units.
|
||||
-- @field Core.Set#SET_GROUP ScanGroupSet Set of scanned groups.
|
||||
-- @extends Core.Fsm#FSM
|
||||
-- @field #number UpdateSeconds Run status every this many seconds.
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- *Gentlemen, when the enemy is committed to a mistake we must not interrupt him too soon.* --- Horation Nelson
|
||||
--
|
||||
@@ -77,6 +78,7 @@ OPSZONE = {
|
||||
Tnut = 0,
|
||||
chiefs = {},
|
||||
Missions = {},
|
||||
UpdateSeconds = 120,
|
||||
}
|
||||
|
||||
--- OPSZONE.MISSION
|
||||
@@ -97,7 +99,7 @@ OPSZONE.ZoneType={
|
||||
|
||||
--- OPSZONE class version.
|
||||
-- @field #string version
|
||||
OPSZONE.version="0.6.1"
|
||||
OPSZONE.version="0.6.2"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ToDo list
|
||||
@@ -733,7 +735,8 @@ function OPSZONE:onafterStart(From, Event, To)
|
||||
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self)
|
||||
|
||||
-- Status update.
|
||||
self.timerStatus:Start(1, 120)
|
||||
local EveryUpdateIn = self.UpdateSeconds or 120
|
||||
self.timerStatus:Start(1, EveryUpdateIn)
|
||||
|
||||
-- Handle base captured event.
|
||||
if self.airbase then
|
||||
|
||||
@@ -1544,7 +1544,7 @@ end
|
||||
-- @param #PLAYERRECCE self
|
||||
-- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations!
|
||||
-- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies!
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #string Gender (Optional) Defaults to "male"
|
||||
-- @param #string Culture (Optional) Defaults to "en-US"
|
||||
-- @param #number Port (Optional) Defaults to 5002
|
||||
@@ -1556,7 +1556,7 @@ end
|
||||
-- @return #PLAYERRECCE self
|
||||
function PLAYERRECCE:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,Backend)
|
||||
self:T(self.lid.."SetSRS")
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" --
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" --
|
||||
self.Gender = Gender or MSRS.gender or "male" --
|
||||
self.Culture = Culture or MSRS.culture or "en-US" --
|
||||
self.Port = Port or MSRS.port or 5002 --
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-- ===
|
||||
-- @module Ops.PlayerTask
|
||||
-- @image OPS_PlayerTask.jpg
|
||||
-- @date Last Update Jan 2025
|
||||
-- @date Last Update May 2025
|
||||
|
||||
|
||||
do
|
||||
@@ -98,7 +98,7 @@ PLAYERTASK = {
|
||||
|
||||
--- PLAYERTASK class version.
|
||||
-- @field #string version
|
||||
PLAYERTASK.version="0.1.25"
|
||||
PLAYERTASK.version="0.1.27"
|
||||
|
||||
--- Generic task condition.
|
||||
-- @type PLAYERTASK.Condition
|
||||
@@ -556,6 +556,7 @@ end
|
||||
-- @param #PLAYERTASK self
|
||||
-- @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 #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
|
||||
-- @usage
|
||||
-- -- We can use either STATIC, SET_STATIC, SCENERY or SET_SCENERY as target objects.
|
||||
@@ -570,20 +571,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,
|
||||
-- -- and set the capturing Coalition in order to trigger a successful task.
|
||||
-- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE)
|
||||
-- mytask:AddOpsZoneCaptureSuccessCondition("capture-squad", coalition.side.BLUE, false)
|
||||
--
|
||||
-- playerTaskManager:AddPlayerTaskToQueue(mytask)
|
||||
function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition)
|
||||
function PLAYERTASK:AddOpsZoneCaptureSuccessCondition(CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone)
|
||||
local task = self
|
||||
task:AddConditionSuccess(
|
||||
function(target)
|
||||
if target:IsInstanceOf("OPSZONE") then
|
||||
return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, true)
|
||||
return task:_CheckCaptureOpsZoneSuccess(target, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true)
|
||||
elseif target:IsInstanceOf("SET_OPSZONE") then
|
||||
local successes = 0
|
||||
local isClientInZone = false
|
||||
target:ForEachZone(function(opszone)
|
||||
if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition) then
|
||||
if task:_CheckCaptureOpsZoneSuccess(opszone, CaptureSquadGroupNamePrefix, Coalition, CheckClientInZone or true) then
|
||||
successes = successes + 1
|
||||
end
|
||||
|
||||
@@ -979,6 +980,12 @@ function PLAYERTASK:onafterStatus(From, Event, To)
|
||||
|
||||
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
|
||||
local targetdead = false
|
||||
|
||||
@@ -1433,9 +1440,9 @@ do
|
||||
-- taskmanager:AddRejectZone(ZONE:FindByName("RejectZone"))
|
||||
--
|
||||
-- -- Set up using SRS for messaging
|
||||
-- local hereSRSPath = "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- local hereSRSPath = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- local hereSRSPort = 5002
|
||||
-- -- local hereSRSGoogle = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourkey.json"
|
||||
-- -- local hereSRSGoogle = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourkey.json"
|
||||
-- taskmanager:SetSRS({130,255},{radio.modulation.AM,radio.modulation.AM},hereSRSPath,"female","en-GB",hereSRSPort,"Microsoft Hazel Desktop",0.7,hereSRSGoogle)
|
||||
--
|
||||
-- -- Controller will announce itself under these broadcast frequencies, handy to use cold-start frequencies here of your aircraft
|
||||
@@ -1902,7 +1909,7 @@ PLAYERTASKCONTROLLER.Messages = {
|
||||
|
||||
--- PLAYERTASK class version.
|
||||
-- @field #string version
|
||||
PLAYERTASKCONTROLLER.version="0.1.69"
|
||||
PLAYERTASKCONTROLLER.version="0.1.70"
|
||||
|
||||
--- Create and run a new TASKCONTROLLER instance.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
@@ -1944,7 +1951,7 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter)
|
||||
self.taskinfomenu = false
|
||||
self.activehasinfomenu = false
|
||||
self.MenuName = nil
|
||||
self.menuitemlimit = 5
|
||||
self.menuitemlimit = 6
|
||||
self.holdmenutime = 30
|
||||
|
||||
self.MarkerReadOnly = false
|
||||
@@ -2415,7 +2422,7 @@ function PLAYERTASKCONTROLLER:EnablePrecisionBombing(FlightGroup,LaserCode,Holdi
|
||||
end
|
||||
)
|
||||
else
|
||||
self:E(self.lid.."No FLIGHTGROUP object passed or FLIGHTGROUP is not alive!")
|
||||
self:E(self.lid.."No OPSGROUP/SET_OPSGROUP object passed or object is not alive!")
|
||||
end
|
||||
else
|
||||
self.autolase = nil
|
||||
@@ -2574,7 +2581,7 @@ function PLAYERTASKCONTROLLER:SetMenuOptions(InfoMenu,ItemLimit,HoldTime)
|
||||
if self.activehasinfomenu then
|
||||
self:EnableTaskInfoMenu()
|
||||
end
|
||||
self.menuitemlimit = ItemLimit or 5
|
||||
self.menuitemlimit = ItemLimit+1 or 6
|
||||
self.holdmenutime = HoldTime or 30
|
||||
return self
|
||||
end
|
||||
@@ -3479,7 +3486,7 @@ end
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
|
||||
-- @param #boolean Silent If true, make no "has new task" announcement
|
||||
-- @param #boolen TaskFilter If true, apply the white/black-list task filters here, also
|
||||
-- @param #boolean TaskFilter If true, apply the white/black-list task filters here, also
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
-- @usage
|
||||
-- Example to create a PLAYERTASK of type CTLD and give Players 10 minutes to complete:
|
||||
@@ -3703,6 +3710,7 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
||||
else
|
||||
CoordText = Coordinate:ToStringA2A(Client,nil,self.ShowMagnetic)
|
||||
end
|
||||
--self:I("CoordText = "..CoordText)
|
||||
-- Threat Level
|
||||
local ThreatLevel = task.Target:GetThreatLevelMax()
|
||||
--local ThreatLevelText = "high"
|
||||
@@ -3837,7 +3845,8 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
||||
Text = string.gsub(Text,"9","niner")
|
||||
CoordText = "MGRS;"..Text
|
||||
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
|
||||
--self:I(self.lid.." | ".. CoordText)
|
||||
end
|
||||
@@ -3855,10 +3864,12 @@ function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client)
|
||||
CoordText = string.gsub(ttstext," BR, "," Bee, Arr, ")
|
||||
end
|
||||
elseif task:HasFreetext() then
|
||||
|
||||
-- add tts freetext
|
||||
local brieftxt = self.gettext:GetEntry("BRIEFING",self.locale)
|
||||
ttstext = ttstext .. string.format("; %s: ",brieftxt)..task:GetFreetextTTS()
|
||||
end
|
||||
--self:I("**** TTS Text ****\n"..ttstext.."\n*****")
|
||||
self.SRSQueue:NewTransmission(ttstext,nil,self.SRS,nil,2)
|
||||
end
|
||||
else
|
||||
@@ -4357,7 +4368,7 @@ function PLAYERTASKCONTROLLER:SwitchDetectStatics(OnOff)
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Add accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
--- [User] Add an accept zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set.
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
@@ -4371,7 +4382,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZone(AcceptZone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Add accept SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
--- [User] Add an accept 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 AcceptZoneSet Add a SET_ZONE to the accept zone set.
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
@@ -4385,7 +4396,7 @@ function PLAYERTASKCONTROLLER:AddAcceptZoneSet(AcceptZoneSet)
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Add reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
--- [User] Add a reject zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set.
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
@@ -4399,7 +4410,7 @@ function PLAYERTASKCONTROLLER:AddRejectZone(RejectZone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Add reject SET_ZONE to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
--- [User] Add a reject 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 RejectZoneSet Add a zone to the reject zone set.
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
@@ -4413,9 +4424,37 @@ function PLAYERTASKCONTROLLER:AddRejectZoneSet(RejectZoneSet)
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Remove accept zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
--- [User] Add a conflict zone to INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param Core.Zone#ZONE AcceptZone Add a zone to the accept zone set.
|
||||
-- @param Core.Zone#ZONE ConflictZone Add a zone to the conflict 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
|
||||
function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone)
|
||||
self:T(self.lid.."RemoveAcceptZone")
|
||||
@@ -4427,11 +4466,11 @@ function PLAYERTASKCONTROLLER:RemoveAcceptZone(AcceptZone)
|
||||
return self
|
||||
end
|
||||
|
||||
--- [User] Remove reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
--- [User] Remove a reject zone from INTEL detection. You need to set up detection with @{#PLAYERTASKCONTROLLER.SetupIntel}() **before** using this.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param Core.Zone#ZONE RejectZone Add a zone to the reject zone set.
|
||||
-- @param Core.Zone#ZONE RejectZone Remove this zone from the reject zone set.
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
function PLAYERTASKCONTROLLER:RemoveRejectZoneSet(RejectZone)
|
||||
function PLAYERTASKCONTROLLER:RemoveRejectZone(RejectZone)
|
||||
self:T(self.lid.."RemoveRejectZone")
|
||||
if self.Intel then
|
||||
self.Intel:RemoveRejectZone(RejectZone)
|
||||
@@ -4441,6 +4480,20 @@ function PLAYERTASKCONTROLLER:RemoveRejectZoneSet(RejectZone)
|
||||
return self
|
||||
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.
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param #string Name The name to use as the top menu designation.
|
||||
@@ -4553,7 +4606,7 @@ end
|
||||
-- @param #PLAYERTASKCONTROLLER self
|
||||
-- @param #number Frequency Frequency to be used. Can also be given as a table of multiple frequencies, e.g. 271 or {127,251}. There needs to be exactly the same number of modulations!
|
||||
-- @param #number Modulation Modulation to be used. Can also be given as a table of multiple modulations, e.g. radio.modulation.AM or {radio.modulation.FM,radio.modulation.AM}. There needs to be exactly the same number of frequencies!
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
-- @param #string PathToSRS Defaults to "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
-- @param #string Gender (Optional) Defaults to "male"
|
||||
-- @param #string Culture (Optional) Defaults to "en-US"
|
||||
-- @param #number Port (Optional) Defaults to 5002
|
||||
@@ -4567,7 +4620,7 @@ end
|
||||
-- @return #PLAYERTASKCONTROLLER self
|
||||
function PLAYERTASKCONTROLLER:SetSRS(Frequency,Modulation,PathToSRS,Gender,Culture,Port,Voice,Volume,PathToGoogleKey,AccessKey,Coordinate,Backend)
|
||||
self:T(self.lid.."SetSRS")
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone" --
|
||||
self.PathToSRS = PathToSRS or MSRS.path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio" --
|
||||
self.Gender = Gender or MSRS.gender or "male" --
|
||||
self.Culture = Culture or MSRS.culture or "en-US" --
|
||||
self.Port = Port or MSRS.port or 5002 --
|
||||
|
||||
@@ -1715,6 +1715,26 @@ function TARGET:GetAverageCoordinate()
|
||||
return nil
|
||||
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.
|
||||
-- @param #TARGET self
|
||||
-- @return #number Heading of the target in degrees.
|
||||
@@ -1968,6 +1988,21 @@ function TARGET:GetObject(RefCoordinate, Coalitions)
|
||||
return nil
|
||||
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.
|
||||
-- @param #TARGET self
|
||||
-- @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_O"] = 'en-GB-Wavenet-O', -- [12] MALE
|
||||
["en_GB_Wavenet_N"] = 'en-GB-Wavenet-N', -- [13] FEMALE
|
||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-N', -- [14] MALE
|
||||
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE
|
||||
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
||||
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
||||
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
||||
@@ -632,7 +632,7 @@ end
|
||||
-- set the path to the exe file via @{#MSRS.SetPath}.
|
||||
--
|
||||
-- @param #MSRS self
|
||||
-- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone`.
|
||||
-- @param #string Path Path to SRS directory. Default `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`.
|
||||
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies.
|
||||
-- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations.
|
||||
-- @param #string Backend Backend used: `MSRS.Backend.SRSEXE` (default) or `MSRS.Backend.GRPC`.
|
||||
@@ -767,13 +767,13 @@ end
|
||||
|
||||
--- Set path to SRS install directory. More precisely, path to where the `DCS-SR-ExternalAudio.exe` is located.
|
||||
-- @param #MSRS self
|
||||
-- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone`.
|
||||
-- @param #string Path Path to the directory, where the sound file is located. Default is `C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio`.
|
||||
-- @return #MSRS self
|
||||
function MSRS:SetPath(Path)
|
||||
self:F( {Path=Path} )
|
||||
|
||||
-- Set path.
|
||||
self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
self.path=Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
|
||||
-- Remove (back)slashes.
|
||||
local n=1 ; local nmax=1000
|
||||
@@ -1817,7 +1817,7 @@ end
|
||||
--
|
||||
-- -- Moose MSRS default Config
|
||||
-- MSRS_Config = {
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone", -- Path to SRS install directory.
|
||||
-- Path = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio", -- Path to SRS install directory.
|
||||
-- Port = 5002, -- Port of SRS server. Default 5002.
|
||||
-- Backend = "srsexe", -- Interface to SRS: "srsexe" or "grpc".
|
||||
-- Frequency = {127, 243}, -- Default frequences. Must be a table 1..n entries!
|
||||
@@ -1837,7 +1837,7 @@ end
|
||||
-- -- Google Cloud
|
||||
-- gcloud = {
|
||||
-- voice = "en-GB-Standard-A", -- The Google Cloud voice to use (see https://cloud.google.com/text-to-speech/docs/voices).
|
||||
-- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend)
|
||||
-- credentials="C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio\\yourfilename.json", -- Full path to credentials JSON file (only for SRS-TTS.exe backend)
|
||||
-- key="Your access Key", -- Google API access key (only for DCS-gRPC backend)
|
||||
-- },
|
||||
-- -- Amazon Web Service
|
||||
@@ -1905,7 +1905,7 @@ function MSRS:LoadConfigFile(Path,Filename)
|
||||
|
||||
local Self = self or MSRS --#MSRS
|
||||
|
||||
Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone"
|
||||
Self.path = MSRS_Config.Path or "C:\\Program Files\\DCS-SimpleRadio-Standalone\\ExternalAudio"
|
||||
Self.port = MSRS_Config.Port or 5002
|
||||
Self.backend = MSRS_Config.Backend or MSRS.Backend.SRSEXE
|
||||
Self.frequencies = MSRS_Config.Frequency or {127,243}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
|
||||
--- 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.
|
||||
-- It can assign a random task to a player when requested.
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
-- 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.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 1.1) DETECTION_MANAGER constructor:
|
||||
-- -----------------------------------
|
||||
-- * @{#DETECTION_MANAGER.New}(): Create a new DETECTION_MANAGER instance.
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
--- 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.
|
||||
-- These tasks need to be assigned to human players to be executed.
|
||||
--
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- # 1) Tasking from a player perspective.
|
||||
--
|
||||
-- Tasking can be controlled by using the "other" menu in the radio menu of the player group.
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
---
|
||||
-- # TASKINFO class, extends @{Core.Base#BASE}
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ## The TASKINFO class implements the methods to contain information and display information of a task.
|
||||
--
|
||||
-- # Developer Note
|
||||
|
||||
@@ -20,6 +20,9 @@ do -- TASK_A2A
|
||||
|
||||
--- Defines Air To Air tasks for a @{Core.Set} of Target Units,
|
||||
-- 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:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
|
||||
@@ -30,6 +30,8 @@ do -- TASK_A2A_DISPATCHER
|
||||
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
|
||||
|
||||
--- Orchestrates the dynamic dispatching of tasks upon groups of detected units determined a @{Core.Set} of EWR installation groups.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- 
|
||||
--
|
||||
|
||||
@@ -20,6 +20,9 @@ do -- TASK_A2G
|
||||
|
||||
--- 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}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The TASK_A2G is implemented using a @{Core.Fsm#FSM_TASK}, and has the following statuses:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
|
||||
@@ -33,6 +33,8 @@ do -- TASK_A2G_DISPATCHER
|
||||
-- @extends Tasking.DetectionManager#DETECTION_MANAGER
|
||||
|
||||
--- 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 provides a truly dynamic battle environment for pilots and ground commanders to engage upon,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user