mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-18 05:05:56 +00:00
Compare commits
147 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aaf77815ca | |||
| 3f488cc091 | |||
| bdbbdfe60e | |||
| d15c2be2d0 | |||
| 73994914eb | |||
| 63b0dae794 | |||
| 003e865ff7 | |||
| e3c03287b7 | |||
| 73493c3a23 | |||
| 562a3f6208 | |||
| 3c5f3d6c37 | |||
| a37d4214c0 | |||
| 636d6ce324 | |||
| eef8b362d2 | |||
| 4ae586ebaa | |||
| f6e673c2bb | |||
| 183a60159c | |||
| 1fdf4f371d | |||
| f50c374d04 | |||
| d59fc331f6 | |||
| b83f478294 | |||
| d5636f4a19 | |||
| 196bcf39cf | |||
| afec1c3a5b | |||
| 6025339b46 | |||
| 40c6cc59d3 | |||
| 514e568e04 | |||
| 2f34b0a5ed | |||
| 708c076885 | |||
| f0e0b918af | |||
| e45f5e1122 | |||
| 932015668b | |||
| 4011bc3fe6 | |||
| 1dcccdc434 | |||
| 3380ed9360 | |||
| ed9c14e63d | |||
| 4762793adc | |||
| 7df3946189 | |||
| d5fb75fe43 | |||
| c0b32a5584 | |||
| e2b1276d7b | |||
| f6aea13fae | |||
| 646b113c55 | |||
| 58074f499f | |||
| 1483ffd7ff | |||
| cdaef851a0 | |||
| 04068d7117 | |||
| 41e8ddea8c | |||
| cc49791997 | |||
| ba4a8050ba | |||
| 7c5067a59a | |||
| 69eb920173 | |||
| 07d761941a | |||
| ca52585759 | |||
| decc9d09f8 | |||
| 466a18447c | |||
| 27902ee107 | |||
| 8a8b806362 | |||
| 40bb181c78 | |||
| 8099847e29 | |||
| 6e8edd95ec | |||
| 5112c9598b | |||
| 749158c086 | |||
| b3d4024f21 | |||
| c283b66c1d | |||
| 3209843318 | |||
| d35e5cc0f7 | |||
| e5eeb592a2 | |||
| 3d38f4d17a | |||
| 2d91647e0b | |||
| cac0f30673 | |||
| c5ecba3389 | |||
| e0397dff47 | |||
| e08fb2e972 | |||
| c02ae82003 | |||
| e6fc301b0d | |||
| a385ed57fb | |||
| 09dafe4b1d | |||
| ba8505c983 | |||
| fba359d389 | |||
| c56763b68f | |||
| 03c2943545 | |||
| 98039b9048 | |||
| 5065d3b068 | |||
| 6828f7e262 | |||
| a685f3ffbd | |||
| e84156d2e9 | |||
| 0ce1c31e1c | |||
| f7e14bb60c | |||
| 7b907df816 | |||
| 7f5be2829c | |||
| fa5afae783 | |||
| b17507d0fa | |||
| 5ed43a3190 | |||
| d2a5144a23 | |||
| fb2031d7ca | |||
| 4a42571925 | |||
| 38413625c2 | |||
| 2d544b7a98 | |||
| b1e5e1840e | |||
| e6f9b4a125 | |||
| 5260b2b430 | |||
| 0213bc7aef | |||
| ca8b0899d0 | |||
| a1f5c0ab9b | |||
| b0e3f82d27 | |||
| 327ab4766b | |||
| 3aee8a49c1 | |||
| 57de0b7351 | |||
| 4df1e310a3 | |||
| 802a77238a | |||
| 85a7e18fae | |||
| 26b1fd3487 | |||
| ae7a363012 | |||
| 473362af45 | |||
| cde0d09f0a | |||
| 94f093826b | |||
| 84f231ea08 | |||
| 3d9bb14713 | |||
| 6c6cdcf763 | |||
| 00c8690e61 | |||
| a0d492cd2d | |||
| ba5ccc1021 | |||
| a4163017d5 | |||
| 7f4a5c48ec | |||
| 9f7588b245 | |||
| 63cbc0c55b | |||
| 28eb7a678c | |||
| a95c49915a | |||
| b7adc6add6 | |||
| 2aeebf280b | |||
| 8ac06979f0 | |||
| 2d4f90d5eb | |||
| d7a44a639d | |||
| 7bfa05f47d | |||
| c7bbb09195 | |||
| 41c9c15ae5 | |||
| 964831becf | |||
| e847b92cce | |||
| c2ecd86bb4 | |||
| 70d922fad6 | |||
| 854bee0519 | |||
| d54d991bdd | |||
| a4b600b97d | |||
| d6cfaa5050 | |||
| 00d1aec210 | |||
| f62e3391e1 |
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"ExpandedNodes": [
|
||||||
|
"",
|
||||||
|
"\\Moose Development",
|
||||||
|
"\\Moose Development\\Moose",
|
||||||
|
"\\Moose Development\\Moose\\Ops"
|
||||||
|
],
|
||||||
|
"SelectedNode": "\\Moose Development\\Moose\\Ops\\Airboss.lua",
|
||||||
|
"PreviewInSolutionExplorer": false
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -40,8 +40,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
-- * **@{#AI_A2A_CAP.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
-- * **@{#AI_A2A_CAP.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
||||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set the Range of Engagement
|
-- ## 3. Set the Range of Engagement
|
||||||
--
|
--
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -42,8 +42,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
-- * **@{#AI_A2A_GCI.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
-- * **@{#AI_A2A_GCI.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
||||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set the Range of Engagement
|
-- ## 3. Set the Range of Engagement
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -39,8 +39,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
-- * **RTB** ( Group ): Route the AI to the home base.
|
-- * **RTB** ( Group ): Route the AI to the home base.
|
||||||
-- * **Detect** ( Group ): The AI is detecting targets.
|
-- * **Detect** ( Group ): The AI is detecting targets.
|
||||||
-- * **Detected** ( Group ): The AI has detected new targets.
|
-- * **Detected** ( Group ): The AI has detected new targets.
|
||||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set or Get the AI controllable
|
-- ## 3. Set or Get the AI controllable
|
||||||
--
|
--
|
||||||
@@ -100,8 +100,8 @@
|
|||||||
-- ## 6. Manage the "out of fuel" in the AI_A2A_PATROL
|
-- ## 6. Manage the "out of fuel" in the AI_A2A_PATROL
|
||||||
--
|
--
|
||||||
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit,
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
||||||
-- while a new AI is targetted to the AI_A2A_PATROL.
|
-- while a new AI is targetted to the AI_A2A_PATROL.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place.
|
-- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place.
|
||||||
@@ -109,7 +109,7 @@
|
|||||||
-- ## 7. Manage "damage" behaviour of the AI in the AI_A2A_PATROL
|
-- ## 7. Manage "damage" behaviour of the AI in the AI_A2A_PATROL
|
||||||
--
|
--
|
||||||
-- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on.
|
-- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on.
|
||||||
-- Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB).
|
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
||||||
-- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place.
|
-- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
|
|||||||
@@ -3243,17 +3243,17 @@ do -- AI_A2G_DISPATCHER
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the default fuel treshold when defenders will RTB or Refuel in the air.
|
--- Set the default fuel threshold when defenders will RTB or Refuel in the air.
|
||||||
-- The fuel treshold is by default set to 15%, which means that an aircraft will stay in the air until 15% of its fuel is remaining.
|
-- The fuel threshold is by default set to 15%, which means that an aircraft will stay in the air until 15% of its fuel is remaining.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the treshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the threshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
||||||
-- @return #AI_A2G_DISPATCHER
|
-- @return #AI_A2G_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
||||||
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel threshold.
|
||||||
-- A2GDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2GDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
function AI_A2G_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold )
|
function AI_A2G_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold )
|
||||||
@@ -3264,18 +3264,18 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the fuel treshold for the squadron when defenders will RTB or Refuel in the air.
|
--- Set the fuel threshold for the squadron when defenders will RTB or Refuel in the air.
|
||||||
-- The fuel treshold is by default set to 15%, which means that an aircraft will stay in the air until 15% of its fuel is remaining.
|
-- The fuel threshold is by default set to 15%, which means that an aircraft will stay in the air until 15% of its fuel is remaining.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The name of the squadron.
|
-- @param #string SquadronName The name of the squadron.
|
||||||
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the treshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the threshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
||||||
-- @return #AI_A2G_DISPATCHER
|
-- @return #AI_A2G_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
||||||
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel threshold.
|
||||||
-- A2GDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2GDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
function AI_A2G_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold )
|
function AI_A2G_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold )
|
||||||
@@ -3295,7 +3295,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
||||||
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel threshold.
|
||||||
-- A2GDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2GDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default tanker.
|
-- -- Now Setup the default tanker.
|
||||||
@@ -3318,7 +3318,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the A2G dispatcher, and initialize it using the Detection object.
|
||||||
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
-- A2GDispatcher = AI_A2G_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the squadron fuel treshold.
|
-- -- Now Setup the squadron fuel threshold.
|
||||||
-- A2GDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- A2GDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
-- -- Now Setup the squadron tanker.
|
-- -- Now Setup the squadron tanker.
|
||||||
@@ -3421,7 +3421,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:CountDefendersEngaged( AttackerDetection, AttackerCount )
|
function AI_A2G_DISPATCHER:CountDefendersEngaged( AttackerDetection, AttackerCount )
|
||||||
|
|
||||||
-- First, count the active AIGroups Units, targetting the DetectedSet
|
-- First, count the active AIGroups Units, targeting the DetectedSet
|
||||||
local DefendersEngaged = 0
|
local DefendersEngaged = 0
|
||||||
local DefendersTotal = 0
|
local DefendersTotal = 0
|
||||||
|
|
||||||
@@ -4729,5 +4729,29 @@ do
|
|||||||
self:Patrol( SquadronName, PatrolTaskType )
|
self:Patrol( SquadronName, PatrolTaskType )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add resources to a Squadron
|
||||||
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
|
-- @param #string Squadron The squadron name.
|
||||||
|
-- @param #number Amount Number of resources to add.
|
||||||
|
function AI_A2G_DISPATCHER:AddToSquadron(Squadron,Amount)
|
||||||
|
local Squadron = self:GetSquadron(Squadron)
|
||||||
|
if Squadron.ResourceCount then
|
||||||
|
Squadron.ResourceCount = Squadron.ResourceCount + Amount
|
||||||
|
end
|
||||||
|
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove resources from a Squadron
|
||||||
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
|
-- @param #string Squadron The squadron name.
|
||||||
|
-- @param #number Amount Number of resources to remove.
|
||||||
|
function AI_A2G_DISPATCHER:RemoveFromSquadron(Squadron,Amount)
|
||||||
|
local Squadron = self:GetSquadron(Squadron)
|
||||||
|
if Squadron.ResourceCount then
|
||||||
|
Squadron.ResourceCount = Squadron.ResourceCount - Amount
|
||||||
|
end
|
||||||
|
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -253,6 +253,9 @@ function AI_AIR:New( AIGroup )
|
|||||||
|
|
||||||
self.IdleCount = 0
|
self.IdleCount = 0
|
||||||
|
|
||||||
|
self.RTBSpeedMaxFactor = 0.6
|
||||||
|
self.RTBSpeedMinFactor = 0.5
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -370,11 +373,11 @@ end
|
|||||||
|
|
||||||
|
|
||||||
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_AIR.
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_AIR.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param #number FuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
-- @param #number FuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||||
-- @param #number OutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
|
-- @param #number OutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
|
||||||
-- @return #AI_AIR self
|
-- @return #AI_AIR self
|
||||||
function AI_AIR:SetFuelThreshold( FuelThresholdPercentage, OutOfFuelOrbitTime )
|
function AI_AIR:SetFuelThreshold( FuelThresholdPercentage, OutOfFuelOrbitTime )
|
||||||
@@ -387,14 +390,14 @@ function AI_AIR:SetFuelThreshold( FuelThresholdPercentage, OutOfFuelOrbitTime )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base.
|
--- When the AI is damaged beyond a certain threshold, it is required that the AI returns to the home base.
|
||||||
-- However, damage cannot be foreseen early on.
|
-- However, damage cannot be foreseen early on.
|
||||||
-- Therefore, when the damage treshold is reached,
|
-- Therefore, when the damage threshold is reached,
|
||||||
-- the AI will return immediately to the home base (RTB).
|
-- the AI will return immediately to the home base (RTB).
|
||||||
-- Note that for groups, the average damage of the complete group will be calculated.
|
-- Note that for groups, the average damage of the complete group will be calculated.
|
||||||
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25.
|
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage threshold will be 0.25.
|
||||||
-- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
-- @param #number PatrolDamageThreshold The threshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
||||||
-- @return #AI_AIR self
|
-- @return #AI_AIR self
|
||||||
function AI_AIR:SetDamageThreshold( PatrolDamageThreshold )
|
function AI_AIR:SetDamageThreshold( PatrolDamageThreshold )
|
||||||
|
|
||||||
@@ -476,7 +479,7 @@ function AI_AIR:onafterStatus()
|
|||||||
|
|
||||||
local Fuel = self.Controllable:GetFuelMin()
|
local Fuel = self.Controllable:GetFuelMin()
|
||||||
|
|
||||||
-- If the fuel in the controllable is below the treshold percentage,
|
-- If the fuel in the controllable is below the threshold percentage,
|
||||||
-- then send for refuel in case of a tanker, otherwise RTB.
|
-- then send for refuel in case of a tanker, otherwise RTB.
|
||||||
if Fuel < self.FuelThresholdPercentage then
|
if Fuel < self.FuelThresholdPercentage then
|
||||||
|
|
||||||
@@ -576,6 +579,19 @@ function AI_AIR.RTBHold( AIGroup, Fsm )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set the min and max factors on RTB speed. Use this, if your planes are heading back to base too fast. Default values are 0.5 and 0.6.
|
||||||
|
-- The RTB speed is calculated as the max speed of the unit multiplied by MinFactor (lower bracket) and multiplied by MaxFactor (upper bracket).
|
||||||
|
-- A random value in this bracket is then applied in the waypoint routing generation.
|
||||||
|
-- @param #AI_AIR self
|
||||||
|
-- @param #number MinFactor Lower bracket factor. Defaults to 0.5.
|
||||||
|
-- @param #number MaxFactor Upper bracket factor. Defaults to 0.6.
|
||||||
|
-- @return #AI_AIR self
|
||||||
|
function AI_AIR:SetRTBSpeedFactors(MinFactor,MaxFactor)
|
||||||
|
self.RTBSpeedMaxFactor = MaxFactor or 0.6
|
||||||
|
self.RTBSpeedMinFactor = MinFactor or 0.5
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
--- @param #AI_AIR self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
@@ -590,6 +606,8 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
self:ClearTargetDistance()
|
self:ClearTargetDistance()
|
||||||
--AIGroup:ClearTasks()
|
--AIGroup:ClearTasks()
|
||||||
|
|
||||||
|
AIGroup:OptionProhibitAfterburner(true)
|
||||||
|
|
||||||
local EngageRoute = {}
|
local EngageRoute = {}
|
||||||
|
|
||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
@@ -597,12 +615,14 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
local FromCoord = AIGroup:GetCoordinate()
|
local FromCoord = AIGroup:GetCoordinate()
|
||||||
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
||||||
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
||||||
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+1000 -- let's set this 1000m/3000 feet above ground
|
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+3000 -- let's set this 1000m/3000 feet above ground
|
||||||
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
||||||
|
|
||||||
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
|
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
|
||||||
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
||||||
self:SetRTBSpeed( RTBSpeedMax * 0.5, RTBSpeedMax * 0.6 )
|
local RTBSpeedMaxFactor = self.RTBSpeedMaxFactor or 0.6
|
||||||
|
local RTBSpeedMinFactor = self.RTBSpeedMinFactor or 0.5
|
||||||
|
self:SetRTBSpeed( RTBSpeedMax * RTBSpeedMinFactor, RTBSpeedMax * RTBSpeedMaxFactor)
|
||||||
end
|
end
|
||||||
|
|
||||||
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
||||||
|
|||||||
@@ -10,11 +10,11 @@
|
|||||||
-- * Setup (CAS) Controlled Air Support squadrons, to attack closeby enemy ground units near friendly installations.
|
-- * Setup (CAS) Controlled Air Support squadrons, to attack closeby enemy ground units near friendly installations.
|
||||||
-- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets.
|
-- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets.
|
||||||
-- * Define and use a detection network controlled by recce.
|
-- * Define and use a detection network controlled by recce.
|
||||||
-- * Define AIR defense squadrons at airbases, farps and carriers.
|
-- * Define AIR defense squadrons at airbases, FARPs and carriers.
|
||||||
-- * Enable airbases for AIR defenses.
|
-- * Enable airbases for AIR defenses.
|
||||||
-- * Add different planes and helicopter templates to squadrons.
|
-- * Add different planes and helicopter templates to squadrons.
|
||||||
-- * Assign squadrons to execute a specific engagement type depending on threat level of the detected ground enemy unit composition.
|
-- * Assign squadrons to execute a specific engagement type depending on threat level of the detected ground enemy unit composition.
|
||||||
-- * Add multiple squadrons to different airbases, farps or carriers.
|
-- * Add multiple squadrons to different airbases, FARPs or carriers.
|
||||||
-- * Define different ranges to engage upon.
|
-- * Define different ranges to engage upon.
|
||||||
-- * Establish an automatic in air refuel process for planes using refuel tankers.
|
-- * Establish an automatic in air refuel process for planes using refuel tankers.
|
||||||
-- * Setup default settings for all squadrons and AIR defenses.
|
-- * Setup default settings for all squadrons and AIR defenses.
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
--
|
--
|
||||||
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
|
-- AI_AIR_DISPATCHER is the main AIR defense class that models the AIR defense system.
|
||||||
--
|
--
|
||||||
-- Before you start using the AI_AIR_DISPATCHER, ask youself the following questions.
|
-- Before you start using the AI_AIR_DISPATCHER, ask yourself the following questions.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## 1. Which coalition am I modeling an AIR defense system for? blue or red?
|
-- ## 1. Which coalition am I modeling an AIR defense system for? blue or red?
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
-- Depending on the defense type, different payloads will be needed. See further points on squadron definition.
|
-- Depending on the defense type, different payloads will be needed. See further points on squadron definition.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## 7. Where will the Squadrons be located? On Airbases? On Carrier Ships? On Farps?
|
-- ## 7. Where will the Squadrons be located? On Airbases? On Carrier Ships? On FARPs?
|
||||||
--
|
--
|
||||||
-- Squadrons are placed at the **home base** on an **airfield**, **carrier** or **farp**.
|
-- Squadrons are placed at the **home base** on an **airfield**, **carrier** or **farp**.
|
||||||
-- Carefully plan where each Squadron will be located as part of the defense system required for mission effective defenses.
|
-- Carefully plan where each Squadron will be located as part of the defense system required for mission effective defenses.
|
||||||
@@ -354,7 +354,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- **DetectionSetGroup** is then calling `FilterStart()`, which is starting the dynamic filtering or inclusion of these groups.
|
-- **DetectionSetGroup** is then calling `FilterStart()`, which is starting the dynamic filtering or inclusion of these groups.
|
||||||
-- Note that any destroy or new spawn of a group having a name, starting with the above prefix, will be removed or added to the set.
|
-- Note that any destroy or new spawn of a group having a name, starting with the above prefix, will be removed or added to the set.
|
||||||
--
|
--
|
||||||
-- Then a new detection object is created from the class `DETECTION_AREAS`. A grouping radius of 1000 meters (1km) is choosen.
|
-- Then a new detection object is created from the class `DETECTION_AREAS`. A grouping radius of 1000 meters (1km) is chosen.
|
||||||
--
|
--
|
||||||
-- The `Detection` object is then passed to the @{#AI_AIR_DISPATCHER.New}() method to indicate the reconnaissance network
|
-- The `Detection` object is then passed to the @{#AI_AIR_DISPATCHER.New}() method to indicate the reconnaissance network
|
||||||
-- configuration and setup the AIR defense detection mechanism.
|
-- configuration and setup the AIR defense detection mechanism.
|
||||||
@@ -647,7 +647,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtRunway}() will despawn the returning aircraft directly after landing at the runway.
|
-- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtRunway}() will despawn the returning aircraft directly after landing at the runway.
|
||||||
-- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtEngineShutdown}() will despawn the returning aircraft when the aircraft has returned to its parking spot and has turned off its engines.
|
-- * @{#AI_AIR_DISPATCHER.SetSquadronLandingAtEngineShutdown}() will despawn the returning aircraft when the aircraft has returned to its parking spot and has turned off its engines.
|
||||||
--
|
--
|
||||||
-- You can use these methods to minimize the airbase coodination overhead and to increase the airbase efficiency.
|
-- You can use these methods to minimize the airbase coordination overhead and to increase the airbase efficiency.
|
||||||
-- When there are lots of aircraft returning for landing, at the same airbase, the takeoff process will be halted, which can cause a complete failure of the
|
-- When there are lots of aircraft returning for landing, at the same airbase, the takeoff process will be halted, which can cause a complete failure of the
|
||||||
-- A2A defense system, as no new CAP or GCI planes can takeoff.
|
-- A2A defense system, as no new CAP or GCI planes can takeoff.
|
||||||
-- Note that the method @{#AI_AIR_DISPATCHER.SetSquadronLandingNearAirbase}() will only work for returning aircraft, not for damaged or out of fuel aircraft.
|
-- Note that the method @{#AI_AIR_DISPATCHER.SetSquadronLandingNearAirbase}() will only work for returning aircraft, not for damaged or out of fuel aircraft.
|
||||||
@@ -724,13 +724,13 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronEngageLimit}() to limit the amount of aircraft that will engage with the enemy, per squadron.
|
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronEngageLimit}() to limit the amount of aircraft that will engage with the enemy, per squadron.
|
||||||
--
|
--
|
||||||
-- ## 4. Set the **fuel treshold**.
|
-- ## 4. Set the **fuel threshold**.
|
||||||
--
|
--
|
||||||
-- When aircraft get **out of fuel** to a certain %-tage, which is by default **15% (0.15)**, there are two possible actions that can be taken:
|
-- When aircraft get **out of fuel** to a certain %, which is by default **15% (0.15)**, there are two possible actions that can be taken:
|
||||||
-- - The aircraft will go RTB, and will be replaced with a new aircraft if possible.
|
-- - The aircraft will go RTB, and will be replaced with a new aircraft if possible.
|
||||||
-- - The aircraft will refuel at a tanker, if a tanker has been specified for the squadron.
|
-- - The aircraft will refuel at a tanker, if a tanker has been specified for the squadron.
|
||||||
--
|
--
|
||||||
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronFuelThreshold}() to set the **squadron fuel treshold** of the aircraft for all squadrons.
|
-- Use the method @{#AI_AIR_DISPATCHER.SetSquadronFuelThreshold}() to set the **squadron fuel threshold** of the aircraft for all squadrons.
|
||||||
--
|
--
|
||||||
-- ## 6. Other configuration options
|
-- ## 6. Other configuration options
|
||||||
--
|
--
|
||||||
@@ -786,17 +786,17 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultGrouping}() to set the **default grouping** of spawned airplanes for all squadrons.
|
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultGrouping}() to set the **default grouping** of spawned airplanes for all squadrons.
|
||||||
--
|
--
|
||||||
-- ## 10.5. Default RTB fuel treshold.
|
-- ## 10.5. Default RTB fuel threshold.
|
||||||
--
|
--
|
||||||
-- When an airplane gets **out of fuel** to a certain %-tage, which is **15% (0.15)**, it will go RTB, and will be replaced with a new airplane when applicable.
|
-- When an airplane gets **out of fuel** to a certain %, which is **15% (0.15)**, it will go RTB, and will be replaced with a new airplane when applicable.
|
||||||
--
|
--
|
||||||
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the **default fuel treshold** of spawned airplanes for all squadrons.
|
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the **default fuel threshold** of spawned airplanes for all squadrons.
|
||||||
--
|
--
|
||||||
-- ## 10.6. Default RTB damage treshold.
|
-- ## 10.6. Default RTB damage threshold.
|
||||||
--
|
--
|
||||||
-- When an airplane is **damaged** to a certain %-tage, which is **40% (0.40)**, it will go RTB, and will be replaced with a new airplane when applicable.
|
-- When an airplane is **damaged** to a certain %, which is **40% (0.40)**, it will go RTB, and will be replaced with a new airplane when applicable.
|
||||||
--
|
--
|
||||||
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultDamageThreshold}() to set the **default damage treshold** of spawned airplanes for all squadrons.
|
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultDamageThreshold}() to set the **default damage threshold** of spawned airplanes for all squadrons.
|
||||||
--
|
--
|
||||||
-- ## 10.7. Default settings for **patrol**.
|
-- ## 10.7. Default settings for **patrol**.
|
||||||
--
|
--
|
||||||
@@ -829,7 +829,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- In the mission editor, setup a group with task Refuelling. A tanker unit of the correct coalition will be automatically selected.
|
-- In the mission editor, setup a group with task Refuelling. A tanker unit of the correct coalition will be automatically selected.
|
||||||
-- Then, use the method @{#AI_AIR_DISPATCHER.SetDefaultTanker}() to set the tanker for the dispatcher.
|
-- Then, use the method @{#AI_AIR_DISPATCHER.SetDefaultTanker}() to set the tanker for the dispatcher.
|
||||||
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the %-tage left in the defender airplane tanks when a refuel action is needed.
|
-- Use the method @{#AI_AIR_DISPATCHER.SetDefaultFuelThreshold}() to set the % left in the defender airplane tanks when a refuel action is needed.
|
||||||
--
|
--
|
||||||
-- When the tanker specified is alive and in the air, the tanker will be used for refuelling.
|
-- When the tanker specified is alive and in the air, the tanker will be used for refuelling.
|
||||||
--
|
--
|
||||||
@@ -843,7 +843,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- A2ADispatcher:SetSquadronCapInterval("Sochi", 2, 30, 600, 1 )
|
-- A2ADispatcher:SetSquadronCapInterval("Sochi", 2, 30, 600, 1 )
|
||||||
-- A2ADispatcher:SetSquadronGci( "Sochi", 900, 1200 )
|
-- A2ADispatcher:SetSquadronGci( "Sochi", 900, 1200 )
|
||||||
--
|
--
|
||||||
-- -- Set the default tanker for refuelling to "Tanker", when the default fuel treshold has reached 90% fuel left.
|
-- -- Set the default tanker for refuelling to "Tanker", when the default fuel threshold has reached 90% fuel left.
|
||||||
-- A2ADispatcher:SetDefaultFuelThreshold( 0.9 )
|
-- A2ADispatcher:SetDefaultFuelThreshold( 0.9 )
|
||||||
-- A2ADispatcher:SetDefaultTanker( "Tanker" )
|
-- A2ADispatcher:SetDefaultTanker( "Tanker" )
|
||||||
--
|
--
|
||||||
@@ -883,9 +883,6 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- However, the squadron will still stay alive. Any airplane that is airborne will continue its operations until all airborne airplanes
|
-- However, the squadron will still stay alive. Any airplane that is airborne will continue its operations until all airborne airplanes
|
||||||
-- of the squadron will be destroyed. This to keep consistency of air operations not to confuse the players.
|
-- of the squadron will be destroyed. This to keep consistency of air operations not to confuse the players.
|
||||||
--
|
--
|
||||||
--
|
|
||||||
--
|
|
||||||
--
|
|
||||||
-- @field #AI_AIR_DISPATCHER
|
-- @field #AI_AIR_DISPATCHER
|
||||||
AI_AIR_DISPATCHER = {
|
AI_AIR_DISPATCHER = {
|
||||||
ClassName = "AI_AIR_DISPATCHER",
|
ClassName = "AI_AIR_DISPATCHER",
|
||||||
@@ -949,7 +946,6 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue
|
--- @field #AI_AIR_DISPATCHER.DefenseQueue DefenseQueue
|
||||||
AI_AIR_DISPATCHER.DefenseQueue = {}
|
AI_AIR_DISPATCHER.DefenseQueue = {}
|
||||||
|
|
||||||
|
|
||||||
--- Defense approach types
|
--- Defense approach types
|
||||||
-- @type #AI_AIR_DISPATCHER.DefenseApproach
|
-- @type #AI_AIR_DISPATCHER.DefenseApproach
|
||||||
AI_AIR_DISPATCHER.DefenseApproach = {
|
AI_AIR_DISPATCHER.DefenseApproach = {
|
||||||
@@ -958,9 +954,9 @@ do -- AI_AIR_DISPATCHER
|
|||||||
}
|
}
|
||||||
|
|
||||||
--- AI_AIR_DISPATCHER constructor.
|
--- AI_AIR_DISPATCHER constructor.
|
||||||
-- This is defining the AIR DISPATCHER for one coaliton.
|
-- This is defining the AIR DISPATCHER for one coalition.
|
||||||
-- The Dispatcher works with a @{Functional.Detection#DETECTION_BASE} object that is taking of the detection of targets using the EWR units.
|
-- The Dispatcher works with a @{Functional.Detection#DETECTION_BASE} object that is taking of the detection of targets using the EWR units.
|
||||||
-- The Detection object is polymorphic, depending on the type of detection object choosen, the detection will work differently.
|
-- The Detection object is polymorphic, depending on the type of detection object chosen, the detection will work differently.
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network.
|
-- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network.
|
||||||
-- @return #AI_AIR_DISPATCHER self
|
-- @return #AI_AIR_DISPATCHER self
|
||||||
@@ -977,7 +973,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- Detection = DETECTION_AREAS:New( DetectionSetGroup, 30000 )
|
-- Detection = DETECTION_AREAS:New( DetectionSetGroup, 30000 )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
||||||
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection ) --
|
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
function AI_AIR_DISPATCHER:New( Detection )
|
function AI_AIR_DISPATCHER:New( Detection )
|
||||||
|
|
||||||
@@ -1435,17 +1431,17 @@ do -- AI_AIR_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the default damage treshold when defenders will RTB.
|
--- Set the default damage threshold when defenders will RTB.
|
||||||
-- The default damage treshold is by default set to 40%, which means that when the airplane is 40% damaged, it will go RTB.
|
-- The default damage threshold is by default set to 40%, which means that when the airplane is 40% damaged, it will go RTB.
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #number DamageThreshold A decimal number between 0 and 1, that expresses the %-tage of the damage treshold before going RTB.
|
-- @param #number DamageThreshold A decimal number between 0 and 1, that expresses the % of the damage threshold before going RTB.
|
||||||
-- @return #AI_AIR_DISPATCHER
|
-- @return #AI_AIR_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
||||||
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default damage treshold.
|
-- -- Now Setup the default damage threshold.
|
||||||
-- AIRDispatcher:SetDefaultDamageThreshold( 0.90 ) -- Go RTB when the airplane 90% damaged.
|
-- AIRDispatcher:SetDefaultDamageThreshold( 0.90 ) -- Go RTB when the airplane 90% damaged.
|
||||||
--
|
--
|
||||||
function AI_AIR_DISPATCHER:SetDefaultDamageThreshold( DamageThreshold )
|
function AI_AIR_DISPATCHER:SetDefaultDamageThreshold( DamageThreshold )
|
||||||
@@ -1989,7 +1985,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
|
|
||||||
--- Defines the default amount of extra planes that will take-off as part of the defense system.
|
--- Defines the default amount of extra planes that will take-off as part of the defense system.
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #number Overhead The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
|
-- @param #number Overhead The % of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
|
||||||
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
|
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
|
||||||
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
|
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
|
||||||
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
|
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
|
||||||
@@ -2028,7 +2024,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--- Defines the amount of extra planes that will take-off as part of the defense system.
|
--- Defines the amount of extra planes that will take-off as part of the defense system.
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #string SquadronName The name of the squadron.
|
-- @param #string SquadronName The name of the squadron.
|
||||||
-- @param #number Overhead The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
|
-- @param #number Overhead The % of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
|
||||||
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
|
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
|
||||||
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
|
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
|
||||||
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
|
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
|
||||||
@@ -2068,7 +2064,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--- Gets the overhead of planes as part of the defense system, in comparison with the attackers.
|
--- Gets the overhead of planes as part of the defense system, in comparison with the attackers.
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #string SquadronName The name of the squadron.
|
-- @param #string SquadronName The name of the squadron.
|
||||||
-- @return #number The %-tage of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
|
-- @return #number The % of Units that dispatching command will allocate to intercept in surplus of detected amount of units.
|
||||||
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
|
-- The default overhead is 1, so equal balance. The @{#AI_AIR_DISPATCHER.SetOverhead}() method can be used to tweak the defense strength,
|
||||||
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
|
-- taking into account the plane types of the squadron. For example, a MIG-31 with full long-distance AIR missiles payload, may still be less effective than a F-15C with short missiles...
|
||||||
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
|
-- So in this case, one may want to use the Overhead method to allocate more defending planes as the amount of detected attacking planes.
|
||||||
@@ -2674,17 +2670,17 @@ do -- AI_AIR_DISPATCHER
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the default fuel treshold when defenders will RTB or Refuel in the air.
|
--- Set the default fuel threshold when defenders will RTB or Refuel in the air.
|
||||||
-- The fuel treshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed.
|
-- The fuel threshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed.
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the %-tage of the treshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the threshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
||||||
-- @return #AI_AIR_DISPATCHER
|
-- @return #AI_AIR_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
||||||
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel threshold.
|
||||||
-- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
function AI_AIR_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold )
|
function AI_AIR_DISPATCHER:SetDefaultFuelThreshold( FuelThreshold )
|
||||||
@@ -2695,18 +2691,18 @@ do -- AI_AIR_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the fuel treshold for the squadron when defenders will RTB or Refuel in the air.
|
--- Set the fuel threshold for the squadron when defenders will RTB or Refuel in the air.
|
||||||
-- The fuel treshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed.
|
-- The fuel threshold is by default set to 15%, which means that an airplane will stay in the air until 15% of its fuel has been consumed.
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param #string SquadronName The name of the squadron.
|
-- @param #string SquadronName The name of the squadron.
|
||||||
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the %-tage of the treshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
-- @param #number FuelThreshold A decimal number between 0 and 1, that expresses the % of the threshold of fuel remaining in the tank when the plane will go RTB or Refuel.
|
||||||
-- @return #AI_AIR_DISPATCHER
|
-- @return #AI_AIR_DISPATCHER
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
||||||
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel threshold.
|
||||||
-- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
function AI_AIR_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold )
|
function AI_AIR_DISPATCHER:SetSquadronFuelThreshold( SquadronName, FuelThreshold )
|
||||||
@@ -2726,7 +2722,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
||||||
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default fuel treshold.
|
-- -- Now Setup the default fuel threshold.
|
||||||
-- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- AIRDispatcher:SetDefaultFuelThreshold( 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
-- -- Now Setup the default tanker.
|
-- -- Now Setup the default tanker.
|
||||||
@@ -2749,7 +2745,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the AIR dispatcher, and initialize it using the Detection object.
|
||||||
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
-- AIRDispatcher = AI_AIR_DISPATCHER:New( Detection )
|
||||||
--
|
--
|
||||||
-- -- Now Setup the squadron fuel treshold.
|
-- -- Now Setup the squadron fuel threshold.
|
||||||
-- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
-- AIRDispatcher:SetSquadronRefuelThreshold( "SquadronName", 0.30 ) -- Go RTB when only 30% of fuel remaining in the tank.
|
||||||
--
|
--
|
||||||
-- -- Now Setup the squadron tanker.
|
-- -- Now Setup the squadron tanker.
|
||||||
@@ -2847,7 +2843,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
function AI_AIR_DISPATCHER:CountDefendersEngaged( AttackerDetection, AttackerCount )
|
function AI_AIR_DISPATCHER:CountDefendersEngaged( AttackerDetection, AttackerCount )
|
||||||
|
|
||||||
-- First, count the active AIGroups Units, targetting the DetectedSet
|
-- First, count the active AIGroups Units, targeting the DetectedSet
|
||||||
local DefendersEngaged = 0
|
local DefendersEngaged = 0
|
||||||
local DefendersTotal = 0
|
local DefendersTotal = 0
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -533,6 +533,10 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||||
|
|
||||||
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
||||||
|
if not TargetCoord then
|
||||||
|
self:Return()
|
||||||
|
return
|
||||||
|
end
|
||||||
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||||
|
|
||||||
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
||||||
|
|||||||
@@ -39,8 +39,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_AIR_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
-- * **@{#AI_AIR_PATROL.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_AIR_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
-- * **@{#AI_AIR_PATROL.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
||||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set the Range of Engagement
|
-- ## 3. Set the Range of Engagement
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone,
|
-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone,
|
||||||
-- using a random speed within the given altitude and speed limits.
|
-- using a random speed within the given altitude and speed limits.
|
||||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||||
-- This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- This cycle will continue until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
-- It will keep patrolling there, until it is notified to RTB or move to another BOMB Zone.
|
-- It will keep patrolling there, until it is notified to RTB or move to another BOMB Zone.
|
||||||
-- It can be notified to go RTB through the **RTB** event.
|
-- It can be notified to go RTB through the **RTB** event.
|
||||||
--
|
--
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
-- * **@{#AI_BAI_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task.
|
-- * **@{#AI_BAI_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the BOMB task.
|
||||||
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status**: The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object**
|
-- ## 3. Modify the Engage Zone behaviour to pinpoint a **map object** or **scenery object**
|
||||||
--
|
--
|
||||||
@@ -515,8 +515,8 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -602,7 +602,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
|
|
||||||
self:SetRefreshTimeInterval( 2 )
|
self:SetRefreshTimeInterval( 2 )
|
||||||
self:SetDetectionActivated()
|
self:SetDetectionActivated()
|
||||||
self:__Target( -2 ) -- Start Targetting
|
self:__Target( -2 ) -- Start targeting
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
--
|
--
|
||||||
-- * Patrol AI airplanes within a given zone.
|
-- * Patrol AI airplanes within a given zone.
|
||||||
-- * Trigger detected events when enemy airplanes are detected.
|
-- * Trigger detected events when enemy airplanes are detected.
|
||||||
-- * Manage a fuel treshold to RTB on time.
|
-- * Manage a fuel threshold to RTB on time.
|
||||||
-- * Engage the enemy when detected.
|
-- * Engage the enemy when detected.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -65,8 +65,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
-- * **@{#AI_CAP_ZONE.Destroy}**: The AI has destroyed a bogey @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
-- * **@{#AI_CAP_ZONE.Destroyed}**: The AI has destroyed all bogeys @{Wrapper.Unit}s assigned in the CAS task.
|
||||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set the Range of Engagement
|
-- ## 3. Set the Range of Engagement
|
||||||
--
|
--
|
||||||
@@ -428,8 +428,12 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
if not CurrentVec2 then -- flight dead at this point
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAS%20-%20Close%20Air%20Support)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone,
|
-- Upon started, The AI will **Route** itself towards the random 3D point within a patrol zone,
|
||||||
-- using a random speed within the given altitude and speed limits.
|
-- using a random speed within the given altitude and speed limits.
|
||||||
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
-- Upon arrival at the 3D point, a new random 3D point will be selected within the patrol zone using the given limits.
|
||||||
-- This cycle will continue until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- This cycle will continue until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
-- It will keep patrolling there, until it is notified to RTB or move to another CAS Zone.
|
-- It will keep patrolling there, until it is notified to RTB or move to another CAS Zone.
|
||||||
-- It can be notified to go RTB through the **RTB** event.
|
-- It can be notified to go RTB through the **RTB** event.
|
||||||
--
|
--
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
-- * **@{AI.AI_Patrol#AI_PATROL_ZONE.Detected}**: The AI has detected new targets.
|
||||||
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
-- * **@{#AI_CAS_ZONE.Destroy}**: The AI has destroyed a target @{Wrapper.Unit}.
|
||||||
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task.
|
-- * **@{#AI_CAS_ZONE.Destroyed}**: The AI has destroyed all target @{Wrapper.Unit}s assigned in the CAS task.
|
||||||
-- * **Status**: The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status**: The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -460,7 +460,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -520,7 +520,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
|
|
||||||
self:SetRefreshTimeInterval( 2 )
|
self:SetRefreshTimeInterval( 2 )
|
||||||
self:SetDetectionActivated()
|
self:SetDetectionActivated()
|
||||||
self:__Target( -2 ) -- Start Targetting
|
self:__Target( -2 ) -- Start targeting
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
--
|
--
|
||||||
-- * Patrol AI airplanes within a given zone.
|
-- * Patrol AI airplanes within a given zone.
|
||||||
-- * Trigger detected events when enemy airplanes are detected.
|
-- * Trigger detected events when enemy airplanes are detected.
|
||||||
-- * Manage a fuel treshold to RTB on time.
|
-- * Manage a fuel threshold to RTB on time.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -72,8 +72,8 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Until a fuel or damage treshold has been reached by the AI, or when the AI is commanded to RTB.
|
-- Until a fuel or damage threshold has been reached by the AI, or when the AI is commanded to RTB.
|
||||||
-- When the fuel treshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
-- When the fuel threshold has been reached, the airplane will fly towards the nearest friendly airbase and will land.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
-- * **RTB** ( Group ): Route the AI to the home base.
|
-- * **RTB** ( Group ): Route the AI to the home base.
|
||||||
-- * **Detect** ( Group ): The AI is detecting targets.
|
-- * **Detect** ( Group ): The AI is detecting targets.
|
||||||
-- * **Detected** ( Group ): The AI has detected new targets.
|
-- * **Detected** ( Group ): The AI has detected new targets.
|
||||||
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the tresholds have been reached, the AI will RTB.
|
-- * **Status** ( Group ): The AI is checking status (fuel and damage). When the thresholds have been reached, the AI will RTB.
|
||||||
--
|
--
|
||||||
-- ## 3. Set or Get the AI controllable
|
-- ## 3. Set or Get the AI controllable
|
||||||
--
|
--
|
||||||
@@ -133,8 +133,8 @@
|
|||||||
-- ## 6. Manage the "out of fuel" in the AI_PATROL_ZONE
|
-- ## 6. Manage the "out of fuel" in the AI_PATROL_ZONE
|
||||||
--
|
--
|
||||||
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit,
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
||||||
-- while a new AI is targetted to the AI_PATROL_ZONE.
|
-- while a new AI is targetted to the AI_PATROL_ZONE.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place.
|
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place.
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
-- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE
|
-- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE
|
||||||
--
|
--
|
||||||
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
|
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
|
||||||
-- Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB).
|
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
||||||
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place.
|
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -581,11 +581,11 @@ function AI_PATROL_ZONE:ClearDetectedUnits()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param #number PatrolFuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
-- @param #number PatrolFuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||||
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
|
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
|
||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
||||||
@@ -596,14 +596,14 @@ function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFu
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- When the AI is damaged beyond a certain treshold, it is required that the AI returns to the home base.
|
--- When the AI is damaged beyond a certain threshold, it is required that the AI returns to the home base.
|
||||||
-- However, damage cannot be foreseen early on.
|
-- However, damage cannot be foreseen early on.
|
||||||
-- Therefore, when the damage treshold is reached,
|
-- Therefore, when the damage threshold is reached,
|
||||||
-- the AI will return immediately to the home base (RTB).
|
-- the AI will return immediately to the home base (RTB).
|
||||||
-- Note that for groups, the average damage of the complete group will be calculated.
|
-- Note that for groups, the average damage of the complete group will be calculated.
|
||||||
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25.
|
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage threshold will be 0.25.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
-- @param #number PatrolDamageThreshold The threshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
|
function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
|
||||||
|
|
||||||
@@ -726,7 +726,8 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if self.Controllable:IsAlive() then
|
local life = self.Controllable:GetLife() or 0
|
||||||
|
if self.Controllable:IsAlive() and life > 1 then
|
||||||
-- Determine if the AIControllable is within the PatrolZone.
|
-- Determine if the AIControllable is within the PatrolZone.
|
||||||
-- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point.
|
-- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point.
|
||||||
|
|
||||||
@@ -743,8 +744,9 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
if self.Controllable:InAir() == false then
|
if self.Controllable:InAir() == false then
|
||||||
self:T( "Not in the air, finding route path within PatrolZone" )
|
self:T( "Not in the air, finding route path within PatrolZone" )
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
if not CurrentVec2 then return end
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -758,8 +760,9 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
else
|
else
|
||||||
self:T( "In the air, finding route path within PatrolZone" )
|
self:T( "In the air, finding route path within PatrolZone" )
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
if not CurrentVec2 then return end
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -870,9 +873,10 @@ function AI_PATROL_ZONE:onafterRTB()
|
|||||||
|
|
||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
if not CurrentVec2 then return end
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
--local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
|
|||||||
@@ -194,7 +194,7 @@
|
|||||||
-- * is of type `Workmaterials`
|
-- * is of type `Workmaterials`
|
||||||
-- * will report when a carrier is within 500 meters
|
-- * will report when a carrier is within 500 meters
|
||||||
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
||||||
-- * will dissapear when the cargo is within 25 meters from the carrier during boarding
|
-- * will disappear when the cargo is within 25 meters from the carrier during boarding
|
||||||
--
|
--
|
||||||
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
||||||
--
|
--
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
-- * is of type `Workmaterials`
|
-- * is of type `Workmaterials`
|
||||||
-- * will report when a carrier is within 500 meters
|
-- * will report when a carrier is within 500 meters
|
||||||
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
||||||
-- * will dissapear when the cargo is within 25 meters from the carrier during boarding
|
-- * will disappear when the cargo is within 25 meters from the carrier during boarding
|
||||||
--
|
--
|
||||||
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -731,13 +731,14 @@ end
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param DCS#Time EventTime The time stamp of the event.
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
-- @param DCS#Object Initiator The initiating object of the event.
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
function BASE:CreateEventCrash( EventTime, Initiator )
|
function BASE:CreateEventCrash( EventTime, Initiator, IniObjectCategory )
|
||||||
self:F( { EventTime, Initiator } )
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = world.event.S_EVENT_CRASH,
|
id = world.event.S_EVENT_CRASH,
|
||||||
time = EventTime,
|
time = EventTime,
|
||||||
initiator = Initiator,
|
initiator = Initiator,
|
||||||
|
IniObjectCategory = IniObjectCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
|
|||||||
@@ -16,20 +16,20 @@
|
|||||||
--- *In order for the light to shine so brightly, the darkness must be present.* -- Francis Bacon
|
--- *In order for the light to shine so brightly, the darkness must be present.* -- Francis Bacon
|
||||||
--
|
--
|
||||||
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
||||||
-- There are two types of BEACONs available : the AA TACAN Beacon and the general purpose Radio Beacon.
|
-- There are two types of BEACONs available : the (aircraft) TACAN Beacon and the general purpose Radio Beacon.
|
||||||
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is
|
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very useful to simulate the battery time if your BEACON is
|
||||||
-- attach to a cargo crate, for exemple.
|
-- attach to a cargo crate, for exemple.
|
||||||
--
|
--
|
||||||
-- ## AA TACAN Beacon usage
|
-- ## Aircraft TACAN Beacon usage
|
||||||
--
|
--
|
||||||
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon.
|
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON.ActivateTACAN}() to set the beacon parameters and start the beacon.
|
||||||
-- Use @#BEACON:StopAATACAN}() to stop it.
|
-- Use @{#BEACON.StopRadioBeacon}() to stop it.
|
||||||
--
|
--
|
||||||
-- ## General Purpose Radio Beacon usage
|
-- ## General Purpose Radio Beacon usage
|
||||||
--
|
--
|
||||||
-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with
|
-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with
|
||||||
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon.
|
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON.RadioBeacon}() to set the beacon parameters and start the beacon.
|
||||||
-- Use @{#BEACON:StopRadioBeacon}() to stop it.
|
-- Use @{#BEACON.StopRadioBeacon}() to stop it.
|
||||||
--
|
--
|
||||||
-- @type BEACON
|
-- @type BEACON
|
||||||
-- @field #string ClassName Name of the class "BEACON".
|
-- @field #string ClassName Name of the class "BEACON".
|
||||||
@@ -95,13 +95,13 @@ BEACON.Type={
|
|||||||
-- @field #number TACAN TACtical Air Navigation system on ground.
|
-- @field #number TACAN TACtical Air Navigation system on ground.
|
||||||
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
||||||
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
||||||
-- @field #number VOR Very High Frequency Omnidirectional Range
|
-- @field #number VOR Very High Frequency Omni-Directional Range
|
||||||
-- @field #number ILS_LOCALIZER ILS localizer
|
-- @field #number ILS_LOCALIZER ILS localizer
|
||||||
-- @field #number ILS_GLIDESLOPE ILS glide slope.
|
-- @field #number ILS_GLIDESLOPE ILS glide slope.
|
||||||
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
||||||
-- @field #number PRGM_GLIDESLOPE PRGM glide slope.
|
-- @field #number PRGM_GLIDESLOPE PRGM glide slope.
|
||||||
-- @field #number BROADCAST_STATION Broadcast station.
|
-- @field #number BROADCAST_STATION Broadcast station.
|
||||||
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omni-directional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
||||||
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
||||||
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
|
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
|
||||||
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
|
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
|
||||||
@@ -131,7 +131,7 @@ BEACON.System={
|
|||||||
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
||||||
-- @return #BEACON Beacon object or #nil if the POSITIONABLE is invalid.
|
-- @return #BEACON Beacon object or #nil if the positionable is invalid.
|
||||||
function BEACON:New(Positionable)
|
function BEACON:New(Positionable)
|
||||||
|
|
||||||
-- Inherit BASE.
|
-- Inherit BASE.
|
||||||
@@ -141,17 +141,18 @@ function BEACON:New( Positionable )
|
|||||||
self:F(Positionable)
|
self:F(Positionable)
|
||||||
|
|
||||||
-- Set positionable.
|
-- Set positionable.
|
||||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure POSITIONABLE is valid
|
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
||||||
self.Positionable = Positionable
|
self.Positionable = Positionable
|
||||||
self.name=Positionable:GetName()
|
self.name=Positionable:GetName()
|
||||||
self:I(string.format("New BEACON %s", tostring(self.name)))
|
self:I(string.format("New BEACON %s", tostring(self.name)))
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E( { "The passed POSITIONABLE is invalid, no BEACON created", Positionable } )
|
self:E({"The passed positionable is invalid, no BEACON created", Positionable})
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Activates a TACAN BEACON.
|
--- Activates a TACAN BEACON.
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
|
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
|
||||||
@@ -161,16 +162,16 @@ end
|
|||||||
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
|
||||||
-- -- Let's create a TACAN Beacon for a tanker
|
-- -- Let's create a TACAN Beacon for a tanker
|
||||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||||
--
|
--
|
||||||
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
|
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
|
||||||
--
|
|
||||||
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||||
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
|
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
|
||||||
|
|
||||||
|
Mode=Mode or "Y"
|
||||||
|
|
||||||
-- Get frequency.
|
-- Get frequency.
|
||||||
local Frequency=UTILS.TACANToFrequency(Channel, Mode)
|
local Frequency=UTILS.TACANToFrequency(Channel, Mode)
|
||||||
|
|
||||||
@@ -188,11 +189,16 @@ function BEACON:ActivateTACAN( Channel, Mode, Message, Bearing, Duration )
|
|||||||
|
|
||||||
-- Check if unit is an aircraft and set system accordingly.
|
-- Check if unit is an aircraft and set system accordingly.
|
||||||
local AA=self.Positionable:IsAir()
|
local AA=self.Positionable:IsAir()
|
||||||
|
|
||||||
|
|
||||||
if AA then
|
if AA then
|
||||||
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||||
-- Check if "Y" mode is selected for aircraft.
|
-- Check if "Y" mode is selected for aircraft.
|
||||||
if Mode ~= "Y" then
|
if Mode=="X" then
|
||||||
self:E( { "WARNING: The POSITIONABLE you want to attach the AA TACAN Beacon is an aircraft: Mode should Y! The BEACON is not emitting.", self.Positionable } )
|
--self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y!", self.Positionable})
|
||||||
|
System=BEACON.System.TACAN_TANKER_X
|
||||||
|
else
|
||||||
|
System=BEACON.System.TACAN_TANKER_Y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -239,7 +245,35 @@ function BEACON:ActivateICLS( Channel, Callsign, Duration )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Activates a TACAN BEACON on an Aircraft.
|
--- Activates a LINK4 BEACON. The unit the BEACON is attached to should be an aircraft carrier supporting this system.
|
||||||
|
-- @param #BEACON self
|
||||||
|
-- @param #number Frequency LINK4 FRequency in MHz, eg 336.
|
||||||
|
-- @param #string Morse The ID that is going to be coded in Morse and broadcasted by the beacon.
|
||||||
|
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||||
|
-- @return #BEACON self
|
||||||
|
function BEACON:ActivateLink4(Frequency, Morse, Duration)
|
||||||
|
self:F({Frequency=Frequency, Morse=Morse, Duration=Duration})
|
||||||
|
|
||||||
|
-- Attached unit.
|
||||||
|
local UnitID=self.Positionable:GetID()
|
||||||
|
|
||||||
|
-- Debug
|
||||||
|
self:T2({"LINK4 BEACON started!"})
|
||||||
|
|
||||||
|
-- Start beacon.
|
||||||
|
self.Positionable:CommandActivateLink4(Frequency,UnitID,Morse)
|
||||||
|
|
||||||
|
-- Stop sheduler
|
||||||
|
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
|
self.Positionable:DeactivateLink4(Duration)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- DEPRECATED: Please use @{BEACON:ActivateTACAN}() instead.
|
||||||
|
-- Activates a TACAN BEACON on an Aircraft.
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param #number TACANChannel (the "10" part in "10Y"). Note that AA TACAN are only available on Y Channels
|
-- @param #number TACANChannel (the "10" part in "10Y"). Note that AA TACAN are only available on Y Channels
|
||||||
-- @param #string Message The Message that is going to be coded in Morse and broadcasted by the beacon
|
-- @param #string Message The Message that is going to be coded in Morse and broadcasted by the beacon
|
||||||
@@ -247,20 +281,18 @@ end
|
|||||||
-- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever.
|
-- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever.
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
|
||||||
-- -- Let's create a TACAN Beacon for a tanker
|
-- -- Let's create a TACAN Beacon for a tanker
|
||||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||||
--
|
--
|
||||||
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
||||||
--
|
|
||||||
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||||
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
||||||
|
|
||||||
local IsValid = true
|
local IsValid = true
|
||||||
|
|
||||||
if not self.Positionable:IsAir() then
|
if not self.Positionable:IsAir() then
|
||||||
self:E( { "The POSITIONABLE you want to attach the AA TACAN Beacon is not an aircraft! The BEACON is not emitting", self.Positionable } )
|
self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting", self.Positionable})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -270,13 +302,12 @@ function BEACON:AATACAN( TACANChannel, Message, Bearing, BeaconDuration )
|
|||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing
|
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing or 14 (TACAN_AA_MODE_Y) if it does not
|
||||||
-- or 14 (TACAN_AA_MODE_Y) if it does not
|
|
||||||
local System
|
local System
|
||||||
if Bearing then
|
if Bearing then
|
||||||
System = 5
|
System = BEACON.System.TACAN_TANKER_Y
|
||||||
else
|
else
|
||||||
System = 14
|
System = BEACON.System.TACAN_AA_MODE_Y
|
||||||
end
|
end
|
||||||
|
|
||||||
if IsValid then -- Starts the BEACON
|
if IsValid then -- Starts the BEACON
|
||||||
@@ -284,15 +315,19 @@ function BEACON:AATACAN( TACANChannel, Message, Bearing, BeaconDuration )
|
|||||||
self.Positionable:SetCommand({
|
self.Positionable:SetCommand({
|
||||||
id = "ActivateBeacon",
|
id = "ActivateBeacon",
|
||||||
params = {
|
params = {
|
||||||
type = 4,
|
type = BEACON.Type.TACAN,
|
||||||
system = System,
|
system = System,
|
||||||
callsign = Message,
|
callsign = Message,
|
||||||
|
AA = true,
|
||||||
frequency = Frequency,
|
frequency = Frequency,
|
||||||
},
|
bearing = Bearing,
|
||||||
|
modeChannel = "Y",
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
SCHEDULER:New( nil, function()
|
SCHEDULER:New(nil,
|
||||||
|
function()
|
||||||
self:StopAATACAN()
|
self:StopAATACAN()
|
||||||
end, {}, BeaconDuration)
|
end, {}, BeaconDuration)
|
||||||
end
|
end
|
||||||
@@ -307,19 +342,21 @@ end
|
|||||||
function BEACON:StopAATACAN()
|
function BEACON:StopAATACAN()
|
||||||
self:F()
|
self:F()
|
||||||
if not self.Positionable then
|
if not self.Positionable then
|
||||||
self:E( { "Start the beacon first before stopping it!" } )
|
self:E({"Start the beacon first before stoping it !"})
|
||||||
else
|
else
|
||||||
self.Positionable:SetCommand({
|
self.Positionable:SetCommand({
|
||||||
id = 'DeactivateBeacon',
|
id = 'DeactivateBeacon',
|
||||||
params = {},
|
params = {
|
||||||
|
}
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Activates a general purpose Radio Beacon
|
--- Activates a general purpose Radio Beacon
|
||||||
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
|
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
|
||||||
-- Although any frequency could be used, only 2 DCS Modules can home on radio beacons at the time of writing : the Huey and the Mi-8.
|
-- Although any frequency could be used, only a few DCS Modules can home on radio beacons at the time of writing, i.e. the Mi-8, Huey, Gazelle etc.
|
||||||
-- They can home in on these specific frequencies :
|
-- The following e.g. can home in on these specific frequencies :
|
||||||
-- * **Mi8**
|
-- * **Mi8**
|
||||||
-- * R-828 -> 20-60MHz
|
-- * R-828 -> 20-60MHz
|
||||||
-- * ARKUD -> 100-150MHz (canal 1 : 114166, canal 2 : 114333, canal 3 : 114583, canal 4 : 121500, canal 5 : 123100, canal 6 : 124100) AM
|
-- * ARKUD -> 100-150MHz (canal 1 : 114166, canal 2 : 114333, canal 3 : 114583, canal 4 : 121500, canal 5 : 123100, canal 6 : 124100) AM
|
||||||
@@ -367,7 +404,7 @@ function BEACON:RadioBeacon( FileName, Frequency, Modulation, Power, BeaconDurat
|
|||||||
Frequency = Frequency * 1000000 -- Conversion to Hz
|
Frequency = Frequency * 1000000 -- Conversion to Hz
|
||||||
|
|
||||||
-- Check the modulation
|
-- Check the modulation
|
||||||
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then -- TODO: Maybe make this future proof if ED decides to add an other modulation ?
|
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then --TODO Maybe make this future proof if ED decides to add an other modulation ?
|
||||||
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation})
|
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
@@ -377,7 +414,7 @@ function BEACON:RadioBeacon( FileName, Frequency, Modulation, Power, BeaconDurat
|
|||||||
self:E({"Power is invalid. ", Power})
|
self:E({"Power is invalid. ", Power})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
Power = math.floor( math.abs( Power ) ) -- TODO: Find what is the maximum power allowed by DCS and limit power to that
|
Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
|
||||||
|
|
||||||
if IsValid then
|
if IsValid then
|
||||||
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
||||||
@@ -385,14 +422,15 @@ function BEACON:RadioBeacon( FileName, Frequency, Modulation, Power, BeaconDurat
|
|||||||
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
|
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
|
||||||
|
|
||||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
SCHEDULER:New( nil, function()
|
SCHEDULER:New( nil,
|
||||||
|
function()
|
||||||
self:StopRadioBeacon()
|
self:StopRadioBeacon()
|
||||||
end, {}, BeaconDuration)
|
end, {}, BeaconDuration)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stops the AA TACAN BEACON
|
--- Stop the Radio Beacon
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
function BEACON:StopRadioBeacon()
|
function BEACON:StopRadioBeacon()
|
||||||
@@ -406,7 +444,7 @@ end
|
|||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param #number TACANChannel
|
-- @param #number TACANChannel
|
||||||
-- @param #string TACANMode
|
-- @param #string TACANMode
|
||||||
-- @return #number Frequency
|
-- @return #number Frequecy
|
||||||
-- @return #nil if parameters are invalid
|
-- @return #nil if parameters are invalid
|
||||||
function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
||||||
self:F3({TACANChannel, TACANMode})
|
self:F3({TACANChannel, TACANMode})
|
||||||
|
|||||||
@@ -241,16 +241,6 @@ function DATABASE:DeleteAirbase( AirbaseName )
|
|||||||
self.AIRBASES[AirbaseName] = nil
|
self.AIRBASES[AirbaseName] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Finds an AIRBASE based on the AirbaseName.
|
|
||||||
-- @param #DATABASE self
|
|
||||||
-- @param #string AirbaseName
|
|
||||||
-- @return Wrapper.Airbase#AIRBASE The found AIRBASE.
|
|
||||||
function DATABASE:FindAirbase( AirbaseName )
|
|
||||||
|
|
||||||
local AirbaseFound = self.AIRBASES[AirbaseName]
|
|
||||||
return AirbaseFound
|
|
||||||
end
|
|
||||||
|
|
||||||
do -- Zones
|
do -- Zones
|
||||||
|
|
||||||
--- Finds a @{Zone} based on the zone name.
|
--- Finds a @{Zone} based on the zone name.
|
||||||
@@ -757,7 +747,9 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
|||||||
|
|
||||||
local StaticTemplate = UTILS.DeepCopy( StaticTemplate )
|
local StaticTemplate = UTILS.DeepCopy( StaticTemplate )
|
||||||
|
|
||||||
local StaticTemplateName = env.getValueDictByKey( StaticTemplate.name )
|
local StaticTemplateGroupName = env.getValueDictByKey( StaticTemplate.name )
|
||||||
|
|
||||||
|
local StaticTemplateName=StaticTemplate.units[1].name
|
||||||
|
|
||||||
self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {}
|
self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {}
|
||||||
|
|
||||||
@@ -765,7 +757,7 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
|||||||
StaticTemplate.CoalitionID = CoalitionID
|
StaticTemplate.CoalitionID = CoalitionID
|
||||||
StaticTemplate.CountryID = CountryID
|
StaticTemplate.CountryID = CountryID
|
||||||
|
|
||||||
self.Templates.Statics[StaticTemplateName].StaticName = StaticTemplateName
|
self.Templates.Statics[StaticTemplateName].StaticName = StaticTemplateGroupName
|
||||||
self.Templates.Statics[StaticTemplateName].GroupTemplate = StaticTemplate
|
self.Templates.Statics[StaticTemplateName].GroupTemplate = StaticTemplate
|
||||||
self.Templates.Statics[StaticTemplateName].UnitTemplate = StaticTemplate.units[1]
|
self.Templates.Statics[StaticTemplateName].UnitTemplate = StaticTemplate.units[1]
|
||||||
self.Templates.Statics[StaticTemplateName].CategoryID = CategoryID
|
self.Templates.Statics[StaticTemplateName].CategoryID = CategoryID
|
||||||
@@ -903,7 +895,7 @@ function DATABASE:_RegisterPlayers()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Private method that registers all Groups and Units within in the mission.
|
--- Private method that registers all Groups and Units within the mission.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterGroupsAndUnits()
|
function DATABASE:_RegisterGroupsAndUnits()
|
||||||
@@ -944,7 +936,7 @@ function DATABASE:_RegisterGroupsAndUnits()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Private method that registers all Units of skill Client or Player within in the mission.
|
--- Private method that registers all Units of skill Client or Player within the mission.
|
||||||
-- @param #DATABASE self
|
-- @param #DATABASE self
|
||||||
-- @return #DATABASE self
|
-- @return #DATABASE self
|
||||||
function DATABASE:_RegisterClients()
|
function DATABASE:_RegisterClients()
|
||||||
@@ -957,7 +949,8 @@ function DATABASE:_RegisterClients()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #DATABASE self
|
--- Private method that registers all Statics within the mission.
|
||||||
|
-- @param #DATABASE self
|
||||||
function DATABASE:_RegisterStatics()
|
function DATABASE:_RegisterStatics()
|
||||||
|
|
||||||
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ), GroupsNeutral = coalition.getStaticObjects( coalition.side.NEUTRAL ) }
|
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ), GroupsNeutral = coalition.getStaticObjects( coalition.side.NEUTRAL ) }
|
||||||
|
|||||||
@@ -32,11 +32,11 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- There are 5 levels of kind of objects that the _EVENTDISPATCHER services:
|
-- There are 5 types/levels of objects that the _EVENTDISPATCHER services:
|
||||||
--
|
--
|
||||||
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
|
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
|
||||||
-- * SET_ derived classes: Subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
|
-- * SET_ derived classes: These are subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
|
||||||
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to teh subscribed UNIT object.
|
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed UNIT object.
|
||||||
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
|
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
|
||||||
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
|
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
|
||||||
--
|
--
|
||||||
@@ -141,6 +141,7 @@
|
|||||||
-- EventData.IniUnit:SmokeGreen()
|
-- EventData.IniUnit:SmokeGreen()
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
|
--
|
||||||
-- Find below an overview which events populate which information categories:
|
-- Find below an overview which events populate which information categories:
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -171,6 +172,7 @@
|
|||||||
-- @module Core.Event
|
-- @module Core.Event
|
||||||
-- @image Core_Event.JPG
|
-- @image Core_Event.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type EVENT
|
--- @type EVENT
|
||||||
-- @field #EVENT.Events Events
|
-- @field #EVENT.Events Events
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
@@ -192,6 +194,7 @@ world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
|||||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
||||||
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
|
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
|
||||||
|
|
||||||
|
|
||||||
--- The different types of events supported by MOOSE.
|
--- The different types of events supported by MOOSE.
|
||||||
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
|
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
|
||||||
-- @type EVENTS
|
-- @type EVENTS
|
||||||
@@ -301,6 +304,8 @@ EVENTS = {
|
|||||||
-- @field Core.ZONE#ZONE Zone The zone object.
|
-- @field Core.ZONE#ZONE Zone The zone object.
|
||||||
-- @field #string ZoneName The name of the zone.
|
-- @field #string ZoneName The name of the zone.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local _EVENTMETA = {
|
local _EVENTMETA = {
|
||||||
[world.event.S_EVENT_SHOT] = {
|
[world.event.S_EVENT_SHOT] = {
|
||||||
Order = 1,
|
Order = 1,
|
||||||
@@ -557,6 +562,7 @@ local _EVENTMETA = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--- The Events structure
|
--- The Events structure
|
||||||
-- @type EVENT.Events
|
-- @type EVENT.Events
|
||||||
-- @field #number IniUnit
|
-- @field #number IniUnit
|
||||||
@@ -575,6 +581,7 @@ function EVENT:New()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Initializes the Events structure for the event.
|
--- Initializes the Events structure for the event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param DCS#world.event EventID Event ID.
|
-- @param DCS#world.event EventID Event ID.
|
||||||
@@ -588,7 +595,7 @@ function EVENT:Init( EventID, EventClass )
|
|||||||
self.Events[EventID] = {}
|
self.Events[EventID] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Each event has a sub-table of EventClasses, ordered by EventPriority.
|
-- Each event has a subtable of EventClasses, ordered by EventPriority.
|
||||||
local EventPriority = EventClass:GetEventPriority()
|
local EventPriority = EventClass:GetEventPriority()
|
||||||
|
|
||||||
if not self.Events[EventID][EventPriority] then
|
if not self.Events[EventID][EventPriority] then
|
||||||
@@ -650,6 +657,7 @@ function EVENT:Reset( EventObject ) -- R2.1
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventClass The self class object for which the events are removed.
|
-- @param Core.Base#BASE EventClass The self class object for which the events are removed.
|
||||||
@@ -668,6 +676,8 @@ function EVENT:RemoveAll( EventClass )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Create an OnDead event handler for a group
|
--- Create an OnDead event handler for a group
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #table EventTemplate
|
-- @param #table EventTemplate
|
||||||
@@ -699,6 +709,7 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set a new listener for an `S_EVENT_X` event for a UNIT.
|
--- Set a new listener for an `S_EVENT_X` event for a UNIT.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #string UnitName The name of the UNIT.
|
-- @param #string UnitName The name of the UNIT.
|
||||||
@@ -786,6 +797,7 @@ do -- OnDead
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
do -- OnLand
|
do -- OnLand
|
||||||
|
|
||||||
--- Create an OnLand event handler for a group
|
--- Create an OnLand event handler for a group
|
||||||
@@ -917,6 +929,7 @@ do -- Event Creation
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creation of a ZoneGoal Deletion Event.
|
--- Creation of a ZoneGoal Deletion Event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||||
@@ -932,6 +945,7 @@ do -- Event Creation
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
||||||
@@ -941,7 +955,7 @@ do -- Event Creation
|
|||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.PlayerEnterUnit,
|
id = EVENTS.PlayerEnterUnit,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
initiator = PlayerUnit:GetDCSObject(),
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
@@ -956,7 +970,7 @@ do -- Event Creation
|
|||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.PlayerEnterAircraft,
|
id = EVENTS.PlayerEnterAircraft,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
initiator = PlayerUnit:GetDCSObject(),
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
@@ -969,16 +983,16 @@ end
|
|||||||
-- @param #EVENTDATA Event Event data table.
|
-- @param #EVENTDATA Event Event data table.
|
||||||
function EVENT:onEvent( Event )
|
function EVENT:onEvent( Event )
|
||||||
|
|
||||||
|
--- Function to handle errors.
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
|
|
||||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||||
if BASE.Debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( debug.traceback() )
|
env.info( debug.traceback() )
|
||||||
end
|
end
|
||||||
|
|
||||||
return errmsg
|
return errmsg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Get event meta data.
|
-- Get event meta data.
|
||||||
local EventMeta = _EVENTMETA[Event.id]
|
local EventMeta = _EVENTMETA[Event.id]
|
||||||
|
|
||||||
@@ -987,6 +1001,7 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
if self and self.Events and self.Events[Event.id] and self.MissionEnd==false and (Event.initiator~=nil or (Event.initiator==nil and Event.id~=EVENTS.PlayerLeaveUnit)) then
|
if self and self.Events and self.Events[Event.id] and self.MissionEnd==false and (Event.initiator~=nil or (Event.initiator==nil and Event.id~=EVENTS.PlayerLeaveUnit)) then
|
||||||
|
|
||||||
|
-- Check if mission has ended.
|
||||||
if Event.id and Event.id == EVENTS.MissionEnd then
|
if Event.id and Event.id == EVENTS.MissionEnd then
|
||||||
self.MissionEnd = true
|
self.MissionEnd = true
|
||||||
end
|
end
|
||||||
@@ -995,34 +1010,11 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
Event.IniObjectCategory = Event.initiator:getCategory()
|
Event.IniObjectCategory = Event.initiator:getCategory()
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.UNIT then
|
|
||||||
Event.IniDCSUnit = Event.initiator
|
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
|
||||||
Event.IniDCSGroup = Event.IniDCSUnit:getGroup()
|
|
||||||
Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName )
|
|
||||||
if not Event.IniUnit then
|
|
||||||
-- Unit can be a CLIENT. Most likely this will be the case ...
|
|
||||||
Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true )
|
|
||||||
end
|
|
||||||
Event.IniDCSGroupName = ""
|
|
||||||
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
|
||||||
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
|
||||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
|
||||||
-- if Event.IniGroup then
|
|
||||||
Event.IniGroupName = Event.IniDCSGroupName
|
|
||||||
-- end
|
|
||||||
end
|
|
||||||
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
|
|
||||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
|
||||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
|
||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
|
||||||
end
|
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||||
|
---
|
||||||
|
-- Static
|
||||||
|
---
|
||||||
if Event.id==31 then
|
if Event.id==31 then
|
||||||
|
|
||||||
-- Event.initiator is a Static object representing the pilot. But getName() errors due to DCS bug.
|
-- Event.initiator is a Static object representing the pilot. But getName() errors due to DCS bug.
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
local ID=Event.initiator.id_
|
local ID=Event.initiator.id_
|
||||||
@@ -1048,9 +1040,47 @@ function EVENT:onEvent( Event )
|
|||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Dead events of units can be delayed and the initiator changed to a static.
|
||||||
|
-- Take care of that.
|
||||||
|
local Unit=UNIT:FindByName(Event.IniDCSUnitName)
|
||||||
|
if Unit then
|
||||||
|
Event.IniObjectCategory = Object.Category.UNIT
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if Event.IniObjectCategory == Object.Category.UNIT then
|
||||||
|
---
|
||||||
|
-- Unit
|
||||||
|
---
|
||||||
|
Event.IniDCSUnit = Event.initiator
|
||||||
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
|
Event.IniDCSGroup = Event.IniDCSUnit:getGroup()
|
||||||
|
Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName )
|
||||||
|
|
||||||
|
if not Event.IniUnit then
|
||||||
|
-- Unit can be a CLIENT. Most likely this will be the case ...
|
||||||
|
Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true )
|
||||||
|
end
|
||||||
|
|
||||||
|
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or ""
|
||||||
|
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
||||||
|
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
||||||
|
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||||
|
Event.IniGroupName = Event.IniDCSGroupName
|
||||||
|
end
|
||||||
|
|
||||||
|
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
|
||||||
|
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||||
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.CARGO then
|
if Event.IniObjectCategory == Object.Category.CARGO then
|
||||||
|
---
|
||||||
|
-- Cargo
|
||||||
|
---
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
@@ -1061,15 +1091,22 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.SCENERY then
|
if Event.IniObjectCategory == Object.Category.SCENERY then
|
||||||
|
---
|
||||||
|
-- Scenery
|
||||||
|
---
|
||||||
|
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY" -- TODO: Bug fix for 2.1!
|
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.BASE then
|
if Event.IniObjectCategory == Object.Category.BASE then
|
||||||
|
---
|
||||||
|
-- Base Object
|
||||||
|
---
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
@@ -1082,6 +1119,11 @@ function EVENT:onEvent( Event )
|
|||||||
|
|
||||||
if Event.target then
|
if Event.target then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- TARGET
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Target category.
|
||||||
Event.TgtObjectCategory = Event.target:getCategory()
|
Event.TgtObjectCategory = Event.target:getCategory()
|
||||||
|
|
||||||
if Event.TgtObjectCategory == Object.Category.UNIT then
|
if Event.TgtObjectCategory == Object.Category.UNIT then
|
||||||
@@ -1094,9 +1136,7 @@ function EVENT:onEvent( Event )
|
|||||||
if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then
|
if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then
|
||||||
Event.TgtDCSGroupName = Event.TgtDCSGroup:getName()
|
Event.TgtDCSGroupName = Event.TgtDCSGroup:getName()
|
||||||
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
||||||
-- if Event.TgtGroup then
|
|
||||||
Event.TgtGroupName = Event.TgtDCSGroupName
|
Event.TgtGroupName = Event.TgtDCSGroupName
|
||||||
-- end
|
|
||||||
end
|
end
|
||||||
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
|
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
|
||||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||||
@@ -1144,6 +1184,7 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Weapon.
|
||||||
if Event.weapon then
|
if Event.weapon then
|
||||||
Event.Weapon = Event.weapon
|
Event.Weapon = Event.weapon
|
||||||
Event.WeaponName = Event.Weapon:getTypeName()
|
Event.WeaponName = Event.Weapon:getTypeName()
|
||||||
@@ -1178,24 +1219,23 @@ function EVENT:onEvent( Event )
|
|||||||
Event.MarkGroupID = Event.groupID
|
Event.MarkGroupID = Event.groupID
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cargo object.
|
||||||
if Event.cargo then
|
if Event.cargo then
|
||||||
Event.Cargo = Event.cargo
|
Event.Cargo = Event.cargo
|
||||||
Event.CargoName = Event.cargo.Name
|
Event.CargoName = Event.cargo.Name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Zone object.
|
||||||
if Event.zone then
|
if Event.zone then
|
||||||
Event.Zone = Event.zone
|
Event.Zone = Event.zone
|
||||||
Event.ZoneName = Event.zone.ZoneName
|
Event.ZoneName = Event.zone.ZoneName
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Priority order.
|
||||||
local PriorityOrder = EventMeta.Order
|
local PriorityOrder = EventMeta.Order
|
||||||
local PriorityBegin = PriorityOrder == -1 and 5 or 1
|
local PriorityBegin = PriorityOrder == -1 and 5 or 1
|
||||||
local PriorityEnd = PriorityOrder == -1 and 1 or 5
|
local PriorityEnd = PriorityOrder == -1 and 1 or 5
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= Object.Category.STATIC then
|
|
||||||
self:F( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
|
|
||||||
end
|
|
||||||
|
|
||||||
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
|
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
|
||||||
|
|
||||||
if self.Events[Event.id][EventPriority] then
|
if self.Events[Event.id][EventPriority] then
|
||||||
@@ -1207,8 +1247,8 @@ function EVENT:onEvent( Event )
|
|||||||
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
||||||
--end
|
--end
|
||||||
|
|
||||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
Event.IniGroup = Event.IniGroup or GROUP:FindByName( Event.IniDCSGroupName )
|
||||||
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
Event.TgtGroup = Event.TgtGroup or GROUP:FindByName( Event.TgtDCSGroupName )
|
||||||
|
|
||||||
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
|
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
|
||||||
if EventData.EventUnit then
|
if EventData.EventUnit then
|
||||||
@@ -1218,7 +1258,8 @@ function EVENT:onEvent( Event )
|
|||||||
Event.id == EVENTS.PlayerEnterUnit or
|
Event.id == EVENTS.PlayerEnterUnit or
|
||||||
Event.id == EVENTS.Crash or
|
Event.id == EVENTS.Crash or
|
||||||
Event.id == EVENTS.Dead or
|
Event.id == EVENTS.Dead or
|
||||||
Event.id == EVENTS.RemoveUnit then
|
Event.id == EVENTS.RemoveUnit or
|
||||||
|
Event.id == EVENTS.UnitLost then
|
||||||
|
|
||||||
local UnitName = EventClass:GetName()
|
local UnitName = EventClass:GetName()
|
||||||
|
|
||||||
@@ -1228,11 +1269,8 @@ function EVENT:onEvent( Event )
|
|||||||
-- First test if a EventFunction is Set, otherwise search for the default function
|
-- First test if a EventFunction is Set, otherwise search for the default function
|
||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
function()
|
||||||
end
|
|
||||||
|
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventData.EventFunction( EventClass, Event )
|
return EventData.EventFunction( EventClass, Event )
|
||||||
end, ErrorHandler )
|
end, ErrorHandler )
|
||||||
|
|
||||||
@@ -1243,14 +1281,12 @@ function EVENT:onEvent( Event )
|
|||||||
if EventFunction and type( EventFunction ) == "function" then
|
if EventFunction and type( EventFunction ) == "function" then
|
||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
|
||||||
|
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventFunction( EventClass, Event )
|
return EventFunction( EventClass, Event )
|
||||||
end, ErrorHandler )
|
end, ErrorHandler )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1268,7 +1304,8 @@ function EVENT:onEvent( Event )
|
|||||||
Event.id == EVENTS.PlayerEnterUnit or
|
Event.id == EVENTS.PlayerEnterUnit or
|
||||||
Event.id == EVENTS.Crash or
|
Event.id == EVENTS.Crash or
|
||||||
Event.id == EVENTS.Dead or
|
Event.id == EVENTS.Dead or
|
||||||
Event.id == EVENTS.RemoveUnit then
|
Event.id == EVENTS.RemoveUnit or
|
||||||
|
Event.id == EVENTS.UnitLost then
|
||||||
|
|
||||||
-- We can get the name of the EventClass, which is now always a GROUP object.
|
-- We can get the name of the EventClass, which is now always a GROUP object.
|
||||||
local GroupName = EventClass:GetName()
|
local GroupName = EventClass:GetName()
|
||||||
@@ -1279,11 +1316,8 @@ function EVENT:onEvent( Event )
|
|||||||
-- First test if a EventFunction is Set, otherwise search for the default function
|
-- First test if a EventFunction is Set, otherwise search for the default function
|
||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
function()
|
||||||
end
|
|
||||||
|
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||||
end, ErrorHandler )
|
end, ErrorHandler )
|
||||||
|
|
||||||
@@ -1294,11 +1328,8 @@ function EVENT:onEvent( Event )
|
|||||||
if EventFunction and type( EventFunction ) == "function" then
|
if EventFunction and type( EventFunction ) == "function" then
|
||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
|
||||||
|
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||||
end, ErrorHandler )
|
end, ErrorHandler )
|
||||||
end
|
end
|
||||||
@@ -1318,10 +1349,8 @@ function EVENT:onEvent( Event )
|
|||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
-- There is an EventFunction defined, so call the EventFunction.
|
-- There is an EventFunction defined, so call the EventFunction.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventData.EventFunction( EventClass, Event )
|
return EventData.EventFunction( EventClass, Event )
|
||||||
end, ErrorHandler )
|
end, ErrorHandler )
|
||||||
else
|
else
|
||||||
@@ -1331,15 +1360,14 @@ function EVENT:onEvent( Event )
|
|||||||
if EventFunction and type( EventFunction ) == "function" then
|
if EventFunction and type( EventFunction ) == "function" then
|
||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
|
||||||
|
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
local Result, Value = EventFunction( EventClass, Event )
|
local Result, Value = EventFunction( EventClass, Event )
|
||||||
return Result, Value
|
return Result, Value
|
||||||
end, ErrorHandler )
|
end, ErrorHandler )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
-- A FSM can only be in one of a finite number of states.
|
-- A FSM can only be in one of a finite number of states.
|
||||||
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
|
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
|
||||||
-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**.
|
-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**.
|
||||||
-- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**.
|
-- A **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**.
|
||||||
-- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions.
|
-- A FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions.
|
||||||
--
|
--
|
||||||
-- The FSM class supports a **hierarchical implementation of a Finite State Machine**,
|
-- The FSM class supports a **hierarchical implementation of a Finite State Machine**,
|
||||||
-- that is, it allows to **embed existing FSM implementations in a master FSM**.
|
-- that is, it allows to **embed existing FSM implementations in a master FSM**.
|
||||||
@@ -34,21 +34,21 @@
|
|||||||
-- orders him to destroy x targets and account the results.
|
-- orders him to destroy x targets and account the results.
|
||||||
-- Other examples of ready made FSM could be:
|
-- Other examples of ready made FSM could be:
|
||||||
--
|
--
|
||||||
-- * route a plane to a zone flown by a human
|
-- * Route a plane to a zone flown by a human.
|
||||||
-- * detect targets by an AI and report to humans
|
-- * Detect targets by an AI and report to humans.
|
||||||
-- * account for destroyed targets by human players
|
-- * Account for destroyed targets by human players.
|
||||||
-- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle
|
-- * Handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle.
|
||||||
-- * let an AI patrol a zone
|
-- * Let an AI patrol a zone.
|
||||||
--
|
--
|
||||||
-- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes,
|
-- The **MOOSE framework** extensively uses the FSM class and derived FSM\_ classes,
|
||||||
-- because **the goal of MOOSE is to simplify mission design complexity for mission building**.
|
-- because **the goal of MOOSE is to simplify mission design complexity for mission building**.
|
||||||
-- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes.
|
-- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes.
|
||||||
-- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used,
|
-- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used,
|
||||||
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
||||||
-- Each of these FSM implementation classes start either with:
|
-- Each of these FSM implementation classes start either with:
|
||||||
--
|
--
|
||||||
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
-- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
||||||
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
-- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
||||||
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
||||||
--
|
--
|
||||||
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
|
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
-- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator.
|
-- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator.
|
||||||
-- Additionally, I've added extendability and created an API that allows seamless FSM implementation.
|
-- Additionally, I've added extendability and created an API that allows seamless FSM implementation.
|
||||||
--
|
--
|
||||||
-- The following derived classes are available in the MOOSE framework, that implement a specialised form of a FSM:
|
-- The following derived classes are available in the MOOSE framework, that implement a specialized form of a FSM:
|
||||||
--
|
--
|
||||||
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
|
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
|
||||||
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
|
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ MENU_INDEX.Coalition[coalition.side.RED].Menus = {}
|
|||||||
MENU_INDEX.Group = {}
|
MENU_INDEX.Group = {}
|
||||||
|
|
||||||
function MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
function MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
|
|
||||||
local Path = ParentMenu and "@" .. table.concat( ParentMenu.MenuPath or {}, "@" ) or ""
|
local Path = ParentMenu and "@" .. table.concat( ParentMenu.MenuPath or {}, "@" ) or ""
|
||||||
if ParentMenu then
|
if ParentMenu then
|
||||||
if ParentMenu:IsInstanceOf( "MENU_GROUP" ) or ParentMenu:IsInstanceOf( "MENU_GROUP_COMMAND" ) then
|
if ParentMenu:IsInstanceOf( "MENU_GROUP" ) or ParentMenu:IsInstanceOf( "MENU_GROUP_COMMAND" ) then
|
||||||
@@ -92,7 +91,6 @@ function MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
|||||||
|
|
||||||
Path = Path .. "@" .. MenuText
|
Path = Path .. "@" .. MenuText
|
||||||
return Path
|
return Path
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:PrepareMission()
|
function MENU_INDEX:PrepareMission()
|
||||||
@@ -103,7 +101,6 @@ function MENU_INDEX:PrepareCoalition( CoalitionSide )
|
|||||||
self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {}
|
self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {}
|
||||||
self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {}
|
self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param Wrapper.Group#GROUP Group
|
-- @param Wrapper.Group#GROUP Group
|
||||||
function MENU_INDEX:PrepareGroup( Group )
|
function MENU_INDEX:PrepareGroup( Group )
|
||||||
@@ -115,32 +112,22 @@ function MENU_INDEX:PrepareGroup( Group )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:HasMissionMenu( Path )
|
function MENU_INDEX:HasMissionMenu( Path )
|
||||||
|
|
||||||
return self.MenuMission.Menus[Path]
|
return self.MenuMission.Menus[Path]
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:SetMissionMenu( Path, Menu )
|
function MENU_INDEX:SetMissionMenu( Path, Menu )
|
||||||
|
|
||||||
self.MenuMission.Menus[Path] = Menu
|
self.MenuMission.Menus[Path] = Menu
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:ClearMissionMenu( Path )
|
function MENU_INDEX:ClearMissionMenu( Path )
|
||||||
|
|
||||||
self.MenuMission.Menus[Path] = nil
|
self.MenuMission.Menus[Path] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
function MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
||||||
|
|
||||||
return self.Coalition[Coalition].Menus[Path]
|
return self.Coalition[Coalition].Menus[Path]
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:SetCoalitionMenu( Coalition, Path, Menu )
|
function MENU_INDEX:SetCoalitionMenu( Coalition, Path, Menu )
|
||||||
|
|
||||||
self.Coalition[Coalition].Menus[Path] = Menu
|
self.Coalition[Coalition].Menus[Path] = Menu
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:ClearCoalitionMenu( Coalition, Path )
|
function MENU_INDEX:ClearCoalitionMenu( Coalition, Path )
|
||||||
|
|
||||||
self.Coalition[Coalition].Menus[Path] = nil
|
self.Coalition[Coalition].Menus[Path] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -151,46 +138,36 @@ function MENU_INDEX:HasGroupMenu( Group, Path )
|
|||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:SetGroupMenu( Group, Path, Menu )
|
function MENU_INDEX:SetGroupMenu( Group, Path, Menu )
|
||||||
|
|
||||||
local MenuGroupName = Group:GetName()
|
local MenuGroupName = Group:GetName()
|
||||||
Group:F({MenuGroupName=MenuGroupName,Path=Path})
|
Group:F({MenuGroupName=MenuGroupName,Path=Path})
|
||||||
self.Group[MenuGroupName].Menus[Path] = Menu
|
self.Group[MenuGroupName].Menus[Path] = Menu
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:ClearGroupMenu( Group, Path )
|
function MENU_INDEX:ClearGroupMenu( Group, Path )
|
||||||
|
|
||||||
local MenuGroupName = Group:GetName()
|
local MenuGroupName = Group:GetName()
|
||||||
self.Group[MenuGroupName].Menus[Path] = nil
|
self.Group[MenuGroupName].Menus[Path] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_INDEX:Refresh( Group )
|
function MENU_INDEX:Refresh( Group )
|
||||||
|
|
||||||
for MenuID, Menu in pairs( self.MenuMission.Menus ) do
|
for MenuID, Menu in pairs( self.MenuMission.Menus ) do
|
||||||
Menu:Refresh()
|
Menu:Refresh()
|
||||||
end
|
end
|
||||||
|
|
||||||
for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do
|
for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do
|
||||||
Menu:Refresh()
|
Menu:Refresh()
|
||||||
end
|
end
|
||||||
|
|
||||||
for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do
|
for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do
|
||||||
Menu:Refresh()
|
Menu:Refresh()
|
||||||
end
|
end
|
||||||
|
|
||||||
local GroupName = Group:GetName()
|
local GroupName = Group:GetName()
|
||||||
for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do
|
for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do
|
||||||
Menu:Refresh()
|
Menu:Refresh()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_BASE
|
do -- MENU_BASE
|
||||||
|
|
||||||
--- @type MENU_BASE
|
--- @type MENU_BASE
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- Defines the main MENU class where other MENU classes are derived from.
|
--- Defines the main MENU class where other MENU classes are derived from.
|
||||||
-- This is an abstract class, so don't use it.
|
-- This is an abstract class, so don't use it.
|
||||||
-- @field #MENU_BASE
|
-- @field #MENU_BASE
|
||||||
@@ -210,7 +187,6 @@ do -- MENU_BASE
|
|||||||
if ParentMenu ~= nil then
|
if ParentMenu ~= nil then
|
||||||
MenuParentPath = ParentMenu.MenuPath
|
MenuParentPath = ParentMenu.MenuPath
|
||||||
end
|
end
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
|
|
||||||
self.MenuPath = nil
|
self.MenuPath = nil
|
||||||
@@ -230,7 +206,6 @@ do -- MENU_BASE
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_BASE:SetParentMenu( MenuText, Menu )
|
function MENU_BASE:SetParentMenu( MenuText, Menu )
|
||||||
if self.ParentMenu then
|
if self.ParentMenu then
|
||||||
self.ParentMenu.Menus = self.ParentMenu.Menus or {}
|
self.ParentMenu.Menus = self.ParentMenu.Menus or {}
|
||||||
@@ -238,7 +213,6 @@ do -- MENU_BASE
|
|||||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1
|
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MENU_BASE:ClearParentMenu( MenuText )
|
function MENU_BASE:ClearParentMenu( MenuText )
|
||||||
if self.ParentMenu and self.ParentMenu.Menus[MenuText] then
|
if self.ParentMenu and self.ParentMenu.Menus[MenuText] then
|
||||||
self.ParentMenu.Menus[MenuText] = nil
|
self.ParentMenu.Menus[MenuText] = nil
|
||||||
@@ -248,7 +222,6 @@ do -- MENU_BASE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets a @{Menu} to remove automatically the parent menu when the menu removed is the last child menu of that parent @{Menu}.
|
--- Sets a @{Menu} to remove automatically the parent menu when the menu removed is the last child menu of that parent @{Menu}.
|
||||||
-- @param #MENU_BASE self
|
-- @param #MENU_BASE self
|
||||||
-- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}.
|
-- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}.
|
||||||
@@ -266,7 +239,6 @@ do -- MENU_BASE
|
|||||||
function MENU_BASE:GetMenu( MenuText )
|
function MENU_BASE:GetMenu( MenuText )
|
||||||
return self.Menus[MenuText]
|
return self.Menus[MenuText]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets a menu stamp for later prevention of menu removal.
|
--- Sets a menu stamp for later prevention of menu removal.
|
||||||
-- @param #MENU_BASE self
|
-- @param #MENU_BASE self
|
||||||
-- @param MenuStamp
|
-- @param MenuStamp
|
||||||
@@ -276,6 +248,7 @@ do -- MENU_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Gets a menu stamp for later prevention of menu removal.
|
--- Gets a menu stamp for later prevention of menu removal.
|
||||||
-- @param #MENU_BASE self
|
-- @param #MENU_BASE self
|
||||||
-- @return MenuStamp
|
-- @return MenuStamp
|
||||||
@@ -283,6 +256,7 @@ do -- MENU_BASE
|
|||||||
return timer.getTime()
|
return timer.getTime()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Sets a time stamp for later prevention of menu removal.
|
--- Sets a time stamp for later prevention of menu removal.
|
||||||
-- @param #MENU_BASE self
|
-- @param #MENU_BASE self
|
||||||
-- @param MenuStamp
|
-- @param MenuStamp
|
||||||
@@ -302,9 +276,7 @@ do -- MENU_BASE
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_COMMAND_BASE
|
do -- MENU_COMMAND_BASE
|
||||||
|
|
||||||
--- @type MENU_COMMAND_BASE
|
--- @type MENU_COMMAND_BASE
|
||||||
-- @field #function MenuCallHandler
|
-- @field #function MenuCallHandler
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
@@ -326,7 +298,6 @@ do -- MENU_COMMAND_BASE
|
|||||||
function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments )
|
function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE
|
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE
|
||||||
|
|
||||||
-- When a menu function goes into error, DCS displays an obscure menu message.
|
-- When a menu function goes into error, DCS displays an obscure menu message.
|
||||||
-- This error handler catches the menu error and displays the full call stack.
|
-- This error handler catches the menu error and displays the full call stack.
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
@@ -359,7 +330,6 @@ do -- MENU_COMMAND_BASE
|
|||||||
self.CommandMenuFunction = CommandMenuFunction
|
self.CommandMenuFunction = CommandMenuFunction
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- This sets the new command arguments of a menu,
|
--- This sets the new command arguments of a menu,
|
||||||
-- so that if a menu is regenerated, or if command arguments change,
|
-- so that if a menu is regenerated, or if command arguments change,
|
||||||
-- that the arguments set for the menu are loosely coupled with the menu itself!!!
|
-- that the arguments set for the menu are loosely coupled with the menu itself!!!
|
||||||
@@ -370,14 +340,11 @@ do -- MENU_COMMAND_BASE
|
|||||||
self.CommandMenuArguments = CommandMenuArguments
|
self.CommandMenuArguments = CommandMenuArguments
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_MISSION
|
do -- MENU_MISSION
|
||||||
|
|
||||||
--- @type MENU_MISSION
|
--- @type MENU_MISSION
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
--- Manages the main menus for a complete mission.
|
--- Manages the main menus for a complete mission.
|
||||||
--
|
--
|
||||||
-- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference.
|
-- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference.
|
||||||
@@ -397,7 +364,6 @@ do -- MENU_MISSION
|
|||||||
MENU_INDEX:PrepareMission()
|
MENU_INDEX:PrepareMission()
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
||||||
|
|
||||||
if MissionMenu then
|
if MissionMenu then
|
||||||
return MissionMenu
|
return MissionMenu
|
||||||
else
|
else
|
||||||
@@ -410,17 +376,15 @@ do -- MENU_MISSION
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a mission
|
--- Refreshes a radio item for a mission
|
||||||
-- @param #MENU_MISSION self
|
-- @param #MENU_MISSION self
|
||||||
-- @return #MENU_MISSION
|
-- @return #MENU_MISSION
|
||||||
function MENU_MISSION:Refresh()
|
function MENU_MISSION:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItem( self.MenuPath )
|
missionCommands.removeItem( self.MenuPath )
|
||||||
self.MenuPath = missionCommands.addSubMenu( self.MenuText, self.MenuParentPath )
|
self.MenuPath = missionCommands.addSubMenu( self.MenuText, self.MenuParentPath )
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes the sub menus recursively of this MENU_MISSION. Note that the main menu is kept!
|
--- Removes the sub menus recursively of this MENU_MISSION. Note that the main menu is kept!
|
||||||
@@ -444,7 +408,6 @@ do -- MENU_MISSION
|
|||||||
MENU_INDEX:PrepareMission()
|
MENU_INDEX:PrepareMission()
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
||||||
|
|
||||||
if MissionMenu == self then
|
if MissionMenu == self then
|
||||||
self:RemoveSubMenus()
|
self:RemoveSubMenus()
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
@@ -466,7 +429,6 @@ do -- MENU_MISSION
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_MISSION_COMMAND
|
do -- MENU_MISSION_COMMAND
|
||||||
|
|
||||||
--- @type MENU_MISSION_COMMAND
|
--- @type MENU_MISSION_COMMAND
|
||||||
@@ -494,7 +456,6 @@ do -- MENU_MISSION_COMMAND
|
|||||||
MENU_INDEX:PrepareMission()
|
MENU_INDEX:PrepareMission()
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
||||||
|
|
||||||
if MissionMenu then
|
if MissionMenu then
|
||||||
MissionMenu:SetCommandMenuFunction( CommandMenuFunction )
|
MissionMenu:SetCommandMenuFunction( CommandMenuFunction )
|
||||||
MissionMenu:SetCommandMenuArguments( arg )
|
MissionMenu:SetCommandMenuArguments( arg )
|
||||||
@@ -508,17 +469,15 @@ do -- MENU_MISSION_COMMAND
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a mission
|
--- Refreshes a radio item for a mission
|
||||||
-- @param #MENU_MISSION_COMMAND self
|
-- @param #MENU_MISSION_COMMAND self
|
||||||
-- @return #MENU_MISSION_COMMAND
|
-- @return #MENU_MISSION_COMMAND
|
||||||
function MENU_MISSION_COMMAND:Refresh()
|
function MENU_MISSION_COMMAND:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItem( self.MenuPath )
|
missionCommands.removeItem( self.MenuPath )
|
||||||
missionCommands.addCommand( self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
missionCommands.addCommand( self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a radio command item for a coalition
|
--- Removes a radio command item for a coalition
|
||||||
@@ -529,7 +488,6 @@ do -- MENU_MISSION_COMMAND
|
|||||||
MENU_INDEX:PrepareMission()
|
MENU_INDEX:PrepareMission()
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
local MissionMenu = MENU_INDEX:HasMissionMenu( Path )
|
||||||
|
|
||||||
if MissionMenu == self then
|
if MissionMenu == self then
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||||
@@ -548,11 +506,8 @@ do -- MENU_MISSION_COMMAND
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_COALITION
|
do -- MENU_COALITION
|
||||||
|
|
||||||
--- @type MENU_COALITION
|
--- @type MENU_COALITION
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
@@ -601,7 +556,7 @@ do -- MENU_COALITION
|
|||||||
--
|
--
|
||||||
-- @field #MENU_COALITION
|
-- @field #MENU_COALITION
|
||||||
MENU_COALITION = {
|
MENU_COALITION = {
|
||||||
ClassName = "MENU_COALITION",
|
ClassName = "MENU_COALITION"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition.
|
--- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition.
|
||||||
@@ -611,15 +566,12 @@ do -- MENU_COALITION
|
|||||||
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other).
|
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other).
|
||||||
-- @return #MENU_COALITION self
|
-- @return #MENU_COALITION self
|
||||||
function MENU_COALITION:New( Coalition, MenuText, ParentMenu )
|
function MENU_COALITION:New( Coalition, MenuText, ParentMenu )
|
||||||
|
|
||||||
MENU_INDEX:PrepareCoalition( Coalition )
|
MENU_INDEX:PrepareCoalition( Coalition )
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
||||||
|
|
||||||
if CoalitionMenu then
|
if CoalitionMenu then
|
||||||
return CoalitionMenu
|
return CoalitionMenu
|
||||||
else
|
else
|
||||||
|
|
||||||
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
||||||
MENU_INDEX:SetCoalitionMenu( Coalition, Path, self )
|
MENU_INDEX:SetCoalitionMenu( Coalition, Path, self )
|
||||||
|
|
||||||
@@ -630,17 +582,15 @@ do -- MENU_COALITION
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a coalition
|
--- Refreshes a radio item for a coalition
|
||||||
-- @param #MENU_COALITION self
|
-- @param #MENU_COALITION self
|
||||||
-- @return #MENU_COALITION
|
-- @return #MENU_COALITION
|
||||||
function MENU_COALITION:Refresh()
|
function MENU_COALITION:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
|
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
|
||||||
missionCommands.addSubMenuForCoalition( self.Coalition, self.MenuText, self.MenuParentPath )
|
missionCommands.addSubMenuForCoalition( self.Coalition, self.MenuText, self.MenuParentPath )
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes the sub menus recursively of this MENU_COALITION. Note that the main menu is kept!
|
--- Removes the sub menus recursively of this MENU_COALITION. Note that the main menu is kept!
|
||||||
@@ -663,7 +613,6 @@ do -- MENU_COALITION
|
|||||||
MENU_INDEX:PrepareCoalition( self.Coalition )
|
MENU_INDEX:PrepareCoalition( self.Coalition )
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path )
|
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path )
|
||||||
|
|
||||||
if CoalitionMenu == self then
|
if CoalitionMenu == self then
|
||||||
self:RemoveSubMenus()
|
self:RemoveSubMenus()
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
@@ -683,9 +632,7 @@ do -- MENU_COALITION
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- MENU_COALITION_COMMAND
|
do -- MENU_COALITION_COMMAND
|
||||||
|
|
||||||
--- @type MENU_COALITION_COMMAND
|
--- @type MENU_COALITION_COMMAND
|
||||||
@@ -698,7 +645,7 @@ do -- MENU_COALITION_COMMAND
|
|||||||
--
|
--
|
||||||
-- @field #MENU_COALITION_COMMAND
|
-- @field #MENU_COALITION_COMMAND
|
||||||
MENU_COALITION_COMMAND = {
|
MENU_COALITION_COMMAND = {
|
||||||
ClassName = "MENU_COALITION_COMMAND",
|
ClassName = "MENU_COALITION_COMMAND"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters.
|
--- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters.
|
||||||
@@ -714,7 +661,6 @@ do -- MENU_COALITION_COMMAND
|
|||||||
MENU_INDEX:PrepareCoalition( Coalition )
|
MENU_INDEX:PrepareCoalition( Coalition )
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
||||||
|
|
||||||
if CoalitionMenu then
|
if CoalitionMenu then
|
||||||
CoalitionMenu:SetCommandMenuFunction( CommandMenuFunction )
|
CoalitionMenu:SetCommandMenuFunction( CommandMenuFunction )
|
||||||
CoalitionMenu:SetCommandMenuArguments( arg )
|
CoalitionMenu:SetCommandMenuArguments( arg )
|
||||||
@@ -729,19 +675,17 @@ do -- MENU_COALITION_COMMAND
|
|||||||
self:SetParentMenu( self.MenuText, self )
|
self:SetParentMenu( self.MenuText, self )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a coalition
|
--- Refreshes a radio item for a coalition
|
||||||
-- @param #MENU_COALITION_COMMAND self
|
-- @param #MENU_COALITION_COMMAND self
|
||||||
-- @return #MENU_COALITION_COMMAND
|
-- @return #MENU_COALITION_COMMAND
|
||||||
function MENU_COALITION_COMMAND:Refresh()
|
function MENU_COALITION_COMMAND:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
|
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
|
||||||
missionCommands.addCommandForCoalition( self.Coalition, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
missionCommands.addCommandForCoalition( self.Coalition, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a radio command item for a coalition
|
--- Removes a radio command item for a coalition
|
||||||
@@ -752,7 +696,6 @@ do -- MENU_COALITION_COMMAND
|
|||||||
MENU_INDEX:PrepareCoalition( self.Coalition )
|
MENU_INDEX:PrepareCoalition( self.Coalition )
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path )
|
local CoalitionMenu = MENU_INDEX:HasCoalitionMenu( self.Coalition, Path )
|
||||||
|
|
||||||
if CoalitionMenu == self then
|
if CoalitionMenu == self then
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||||
@@ -771,22 +714,20 @@ do -- MENU_COALITION_COMMAND
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- MENU_GROUP
|
--- MENU_GROUP
|
||||||
|
|
||||||
do
|
do
|
||||||
-- This local variable is used to cache the menus registered under groups.
|
-- This local variable is used to cache the menus registered under groups.
|
||||||
-- Menus don't dissapear when groups for players are destroyed and restarted.
|
-- Menus don't disappear when groups for players are destroyed and restarted.
|
||||||
-- So every menu for a client created must be tracked so that program logic accidentally does not create.
|
-- So every menu for a client created must be tracked so that program logic accidentally does not create.
|
||||||
-- the same menus twice during initialization logic.
|
-- the same menus twice during initialization logic.
|
||||||
-- These menu classes are handling this logic with this variable.
|
-- These menu classes are handling this logic with this variable.
|
||||||
local _MENUGROUPS = {}
|
local _MENUGROUPS = {}
|
||||||
|
|
||||||
--- @type MENU_GROUP
|
--- @type MENU_GROUP
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
|
|
||||||
--- Manages the main menus for @{Wrapper.Group}s.
|
--- Manages the main menus for @{Wrapper.Group}s.
|
||||||
--
|
--
|
||||||
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
|
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
|
||||||
@@ -844,7 +785,7 @@ do
|
|||||||
--
|
--
|
||||||
-- @field #MENU_GROUP
|
-- @field #MENU_GROUP
|
||||||
MENU_GROUP = {
|
MENU_GROUP = {
|
||||||
ClassName = "MENU_GROUP",
|
ClassName = "MENU_GROUP"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- MENU_GROUP constructor. Creates a new radio menu item for a group.
|
--- MENU_GROUP constructor. Creates a new radio menu item for a group.
|
||||||
@@ -858,16 +799,13 @@ do
|
|||||||
MENU_INDEX:PrepareGroup( Group )
|
MENU_INDEX:PrepareGroup( Group )
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
||||||
|
|
||||||
if GroupMenu then
|
if GroupMenu then
|
||||||
return GroupMenu
|
return GroupMenu
|
||||||
else
|
else
|
||||||
self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
||||||
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
||||||
|
|
||||||
self.Group = Group
|
self.Group = Group
|
||||||
self.GroupID = Group:GetID()
|
self.GroupID = Group:GetID()
|
||||||
|
|
||||||
self.MenuPath = missionCommands.addSubMenuForGroup( self.GroupID, MenuText, self.MenuParentPath )
|
self.MenuPath = missionCommands.addSubMenuForGroup( self.GroupID, MenuText, self.MenuParentPath )
|
||||||
|
|
||||||
self:SetParentMenu( self.MenuText, self )
|
self:SetParentMenu( self.MenuText, self )
|
||||||
@@ -875,12 +813,10 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a new radio item for a group and submenus
|
--- Refreshes a new radio item for a group and submenus
|
||||||
-- @param #MENU_GROUP self
|
-- @param #MENU_GROUP self
|
||||||
-- @return #MENU_GROUP
|
-- @return #MENU_GROUP
|
||||||
function MENU_GROUP:Refresh()
|
function MENU_GROUP:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||||
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
||||||
@@ -890,6 +826,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes the sub menus recursively of this MENU_GROUP.
|
--- Removes the sub menus recursively of this MENU_GROUP.
|
||||||
@@ -898,7 +835,6 @@ do
|
|||||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||||
-- @return #MENU_GROUP self
|
-- @return #MENU_GROUP self
|
||||||
function MENU_GROUP:RemoveSubMenus( MenuStamp, MenuTag )
|
function MENU_GROUP:RemoveSubMenus( MenuStamp, MenuTag )
|
||||||
|
|
||||||
for MenuText, Menu in pairs( self.Menus or {} ) do
|
for MenuText, Menu in pairs( self.Menus or {} ) do
|
||||||
Menu:Remove( MenuStamp, MenuTag )
|
Menu:Remove( MenuStamp, MenuTag )
|
||||||
end
|
end
|
||||||
@@ -913,11 +849,9 @@ do
|
|||||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||||
-- @return #nil
|
-- @return #nil
|
||||||
function MENU_GROUP:Remove( MenuStamp, MenuTag )
|
function MENU_GROUP:Remove( MenuStamp, MenuTag )
|
||||||
|
|
||||||
MENU_INDEX:PrepareGroup( self.Group )
|
MENU_INDEX:PrepareGroup( self.Group )
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
||||||
|
|
||||||
if GroupMenu == self then
|
if GroupMenu == self then
|
||||||
self:RemoveSubMenus( MenuStamp, MenuTag )
|
self:RemoveSubMenus( MenuStamp, MenuTag )
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
@@ -939,6 +873,7 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @type MENU_GROUP_COMMAND
|
--- @type MENU_GROUP_COMMAND
|
||||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||||
|
|
||||||
@@ -948,7 +883,7 @@ do
|
|||||||
--
|
--
|
||||||
-- @field #MENU_GROUP_COMMAND
|
-- @field #MENU_GROUP_COMMAND
|
||||||
MENU_GROUP_COMMAND = {
|
MENU_GROUP_COMMAND = {
|
||||||
ClassName = "MENU_GROUP_COMMAND",
|
ClassName = "MENU_GROUP_COMMAND"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Creates a new radio command item for a group
|
--- Creates a new radio command item for a group
|
||||||
@@ -960,18 +895,15 @@ do
|
|||||||
-- @param CommandMenuArgument An argument for the function.
|
-- @param CommandMenuArgument An argument for the function.
|
||||||
-- @return #MENU_GROUP_COMMAND
|
-- @return #MENU_GROUP_COMMAND
|
||||||
function MENU_GROUP_COMMAND:New( Group, MenuText, ParentMenu, CommandMenuFunction, ... )
|
function MENU_GROUP_COMMAND:New( Group, MenuText, ParentMenu, CommandMenuFunction, ... )
|
||||||
|
|
||||||
MENU_INDEX:PrepareGroup( Group )
|
MENU_INDEX:PrepareGroup( Group )
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
||||||
|
|
||||||
if GroupMenu then
|
if GroupMenu then
|
||||||
GroupMenu:SetCommandMenuFunction( CommandMenuFunction )
|
GroupMenu:SetCommandMenuFunction( CommandMenuFunction )
|
||||||
GroupMenu:SetCommandMenuArguments( arg )
|
GroupMenu:SetCommandMenuArguments( arg )
|
||||||
return GroupMenu
|
return GroupMenu
|
||||||
else
|
else
|
||||||
self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
||||||
|
|
||||||
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
||||||
|
|
||||||
self.Group = Group
|
self.Group = Group
|
||||||
@@ -982,19 +914,17 @@ do
|
|||||||
self:SetParentMenu( self.MenuText, self )
|
self:SetParentMenu( self.MenuText, self )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a group
|
--- Refreshes a radio item for a group
|
||||||
-- @param #MENU_GROUP_COMMAND self
|
-- @param #MENU_GROUP_COMMAND self
|
||||||
-- @return #MENU_GROUP_COMMAND
|
-- @return #MENU_GROUP_COMMAND
|
||||||
function MENU_GROUP_COMMAND:Refresh()
|
function MENU_GROUP_COMMAND:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||||
missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a menu structure for a group.
|
--- Removes a menu structure for a group.
|
||||||
@@ -1003,11 +933,9 @@ do
|
|||||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||||
-- @return #nil
|
-- @return #nil
|
||||||
function MENU_GROUP_COMMAND:Remove( MenuStamp, MenuTag )
|
function MENU_GROUP_COMMAND:Remove( MenuStamp, MenuTag )
|
||||||
|
|
||||||
MENU_INDEX:PrepareGroup( self.Group )
|
MENU_INDEX:PrepareGroup( self.Group )
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
||||||
|
|
||||||
if GroupMenu == self then
|
if GroupMenu == self then
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||||
@@ -1026,16 +954,13 @@ do
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- MENU_GROUP_DELAYED
|
--- MENU_GROUP_DELAYED
|
||||||
|
|
||||||
do
|
do
|
||||||
|
|
||||||
--- @type MENU_GROUP_DELAYED
|
--- @type MENU_GROUP_DELAYED
|
||||||
-- @extends Core.Menu#MENU_BASE
|
-- @extends Core.Menu#MENU_BASE
|
||||||
|
|
||||||
|
|
||||||
--- The MENU_GROUP_DELAYED class manages the main menus for groups.
|
--- The MENU_GROUP_DELAYED class manages the main menus for groups.
|
||||||
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
|
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
|
||||||
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}.
|
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}.
|
||||||
@@ -1045,7 +970,7 @@ do
|
|||||||
--
|
--
|
||||||
-- @field #MENU_GROUP_DELAYED
|
-- @field #MENU_GROUP_DELAYED
|
||||||
MENU_GROUP_DELAYED = {
|
MENU_GROUP_DELAYED = {
|
||||||
ClassName = "MENU_GROUP_DELAYED",
|
ClassName = "MENU_GROUP_DELAYED"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- MENU_GROUP_DELAYED constructor. Creates a new radio menu item for a group.
|
--- MENU_GROUP_DELAYED constructor. Creates a new radio menu item for a group.
|
||||||
@@ -1059,16 +984,13 @@ do
|
|||||||
MENU_INDEX:PrepareGroup( Group )
|
MENU_INDEX:PrepareGroup( Group )
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
||||||
|
|
||||||
if GroupMenu then
|
if GroupMenu then
|
||||||
return GroupMenu
|
return GroupMenu
|
||||||
else
|
else
|
||||||
self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
||||||
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
||||||
|
|
||||||
self.Group = Group
|
self.Group = Group
|
||||||
self.GroupID = Group:GetID()
|
self.GroupID = Group:GetID()
|
||||||
|
|
||||||
if self.MenuParentPath then
|
if self.MenuParentPath then
|
||||||
self.MenuPath = UTILS.DeepCopy( self.MenuParentPath )
|
self.MenuPath = UTILS.DeepCopy( self.MenuParentPath )
|
||||||
else
|
else
|
||||||
@@ -1086,7 +1008,6 @@ do
|
|||||||
-- @param #MENU_GROUP_DELAYED self
|
-- @param #MENU_GROUP_DELAYED self
|
||||||
-- @return #MENU_GROUP_DELAYED
|
-- @return #MENU_GROUP_DELAYED
|
||||||
function MENU_GROUP_DELAYED:Set()
|
function MENU_GROUP_DELAYED:Set()
|
||||||
|
|
||||||
do
|
do
|
||||||
if not self.MenuSet then
|
if not self.MenuSet then
|
||||||
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
||||||
@@ -1097,14 +1018,12 @@ do
|
|||||||
Menu:Set()
|
Menu:Set()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a new radio item for a group and submenus
|
--- Refreshes a new radio item for a group and submenus
|
||||||
-- @param #MENU_GROUP_DELAYED self
|
-- @param #MENU_GROUP_DELAYED self
|
||||||
-- @return #MENU_GROUP_DELAYED
|
-- @return #MENU_GROUP_DELAYED
|
||||||
function MENU_GROUP_DELAYED:Refresh()
|
function MENU_GROUP_DELAYED:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||||
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
||||||
@@ -1114,6 +1033,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes the sub menus recursively of this MENU_GROUP_DELAYED.
|
--- Removes the sub menus recursively of this MENU_GROUP_DELAYED.
|
||||||
@@ -1122,7 +1042,6 @@ do
|
|||||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||||
-- @return #MENU_GROUP_DELAYED self
|
-- @return #MENU_GROUP_DELAYED self
|
||||||
function MENU_GROUP_DELAYED:RemoveSubMenus( MenuStamp, MenuTag )
|
function MENU_GROUP_DELAYED:RemoveSubMenus( MenuStamp, MenuTag )
|
||||||
|
|
||||||
for MenuText, Menu in pairs( self.Menus or {} ) do
|
for MenuText, Menu in pairs( self.Menus or {} ) do
|
||||||
Menu:Remove( MenuStamp, MenuTag )
|
Menu:Remove( MenuStamp, MenuTag )
|
||||||
end
|
end
|
||||||
@@ -1137,11 +1056,9 @@ do
|
|||||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||||
-- @return #nil
|
-- @return #nil
|
||||||
function MENU_GROUP_DELAYED:Remove( MenuStamp, MenuTag )
|
function MENU_GROUP_DELAYED:Remove( MenuStamp, MenuTag )
|
||||||
|
|
||||||
MENU_INDEX:PrepareGroup( self.Group )
|
MENU_INDEX:PrepareGroup( self.Group )
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
||||||
|
|
||||||
if GroupMenu == self then
|
if GroupMenu == self then
|
||||||
self:RemoveSubMenus( MenuStamp, MenuTag )
|
self:RemoveSubMenus( MenuStamp, MenuTag )
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
@@ -1163,6 +1080,7 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @type MENU_GROUP_COMMAND_DELAYED
|
--- @type MENU_GROUP_COMMAND_DELAYED
|
||||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||||
|
|
||||||
@@ -1173,7 +1091,7 @@ do
|
|||||||
--
|
--
|
||||||
-- @field #MENU_GROUP_COMMAND_DELAYED
|
-- @field #MENU_GROUP_COMMAND_DELAYED
|
||||||
MENU_GROUP_COMMAND_DELAYED = {
|
MENU_GROUP_COMMAND_DELAYED = {
|
||||||
ClassName = "MENU_GROUP_COMMAND_DELAYED",
|
ClassName = "MENU_GROUP_COMMAND_DELAYED"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Creates a new radio command item for a group
|
--- Creates a new radio command item for a group
|
||||||
@@ -1185,18 +1103,15 @@ do
|
|||||||
-- @param CommandMenuArgument An argument for the function.
|
-- @param CommandMenuArgument An argument for the function.
|
||||||
-- @return #MENU_GROUP_COMMAND_DELAYED
|
-- @return #MENU_GROUP_COMMAND_DELAYED
|
||||||
function MENU_GROUP_COMMAND_DELAYED:New( Group, MenuText, ParentMenu, CommandMenuFunction, ... )
|
function MENU_GROUP_COMMAND_DELAYED:New( Group, MenuText, ParentMenu, CommandMenuFunction, ... )
|
||||||
|
|
||||||
MENU_INDEX:PrepareGroup( Group )
|
MENU_INDEX:PrepareGroup( Group )
|
||||||
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
local Path = MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( Group, Path )
|
||||||
|
|
||||||
if GroupMenu then
|
if GroupMenu then
|
||||||
GroupMenu:SetCommandMenuFunction( CommandMenuFunction )
|
GroupMenu:SetCommandMenuFunction( CommandMenuFunction )
|
||||||
GroupMenu:SetCommandMenuArguments( arg )
|
GroupMenu:SetCommandMenuArguments( arg )
|
||||||
return GroupMenu
|
return GroupMenu
|
||||||
else
|
else
|
||||||
self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
||||||
|
|
||||||
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
MENU_INDEX:SetGroupMenu( Group, Path, self )
|
||||||
|
|
||||||
self.Group = Group
|
self.Group = Group
|
||||||
@@ -1212,33 +1127,29 @@ do
|
|||||||
self:SetParentMenu( self.MenuText, self )
|
self:SetParentMenu( self.MenuText, self )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a group
|
--- Refreshes a radio item for a group
|
||||||
-- @param #MENU_GROUP_COMMAND_DELAYED self
|
-- @param #MENU_GROUP_COMMAND_DELAYED self
|
||||||
-- @return #MENU_GROUP_COMMAND_DELAYED
|
-- @return #MENU_GROUP_COMMAND_DELAYED
|
||||||
function MENU_GROUP_COMMAND_DELAYED:Set()
|
function MENU_GROUP_COMMAND_DELAYED:Set()
|
||||||
|
|
||||||
do
|
do
|
||||||
if not self.MenuSet then
|
if not self.MenuSet then
|
||||||
self.MenuPath = missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
self.MenuPath = missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||||
self.MenuSet = true
|
self.MenuSet = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a group
|
--- Refreshes a radio item for a group
|
||||||
-- @param #MENU_GROUP_COMMAND_DELAYED self
|
-- @param #MENU_GROUP_COMMAND_DELAYED self
|
||||||
-- @return #MENU_GROUP_COMMAND_DELAYED
|
-- @return #MENU_GROUP_COMMAND_DELAYED
|
||||||
function MENU_GROUP_COMMAND_DELAYED:Refresh()
|
function MENU_GROUP_COMMAND_DELAYED:Refresh()
|
||||||
|
|
||||||
do
|
do
|
||||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||||
missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
missionCommands.addCommandForGroup( self.GroupID, self.MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a menu structure for a group.
|
--- Removes a menu structure for a group.
|
||||||
@@ -1247,11 +1158,9 @@ do
|
|||||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||||
-- @return #nil
|
-- @return #nil
|
||||||
function MENU_GROUP_COMMAND_DELAYED:Remove( MenuStamp, MenuTag )
|
function MENU_GROUP_COMMAND_DELAYED:Remove( MenuStamp, MenuTag )
|
||||||
|
|
||||||
MENU_INDEX:PrepareGroup( self.Group )
|
MENU_INDEX:PrepareGroup( self.Group )
|
||||||
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
local Path = MENU_INDEX:ParentPath( self.ParentMenu, self.MenuText )
|
||||||
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
local GroupMenu = MENU_INDEX:HasGroupMenu( self.Group, Path )
|
||||||
|
|
||||||
if GroupMenu == self then
|
if GroupMenu == self then
|
||||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||||
@@ -1270,6 +1179,5 @@ do
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
-- * Send message to all players.
|
-- * Send message to all players.
|
||||||
-- * Send messages to a coalition.
|
-- * Send messages to a coalition.
|
||||||
-- * Send messages to a specific group.
|
-- * Send messages to a specific group.
|
||||||
|
-- * Send messages to a specific unit or client.
|
||||||
|
--
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -35,6 +37,7 @@
|
|||||||
--
|
--
|
||||||
-- * To a @{Client} using @{#MESSAGE.ToClient}().
|
-- * To a @{Client} using @{#MESSAGE.ToClient}().
|
||||||
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
||||||
|
-- * To a @{Wrapper.Unit} using @{#MESSAGE.ToUnit}()
|
||||||
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
||||||
-- * To the red coalition using @{#MESSAGE.ToRed}().
|
-- * To the red coalition using @{#MESSAGE.ToRed}().
|
||||||
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
|
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
|
||||||
@@ -199,10 +202,13 @@ function MESSAGE:ToClient( Client, Settings )
|
|||||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local Unit = Client:GetClient()
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
local ClientGroupID = Client:GetClientGroupID()
|
local ClientGroupID = Client:GetClientGroupID()
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
--trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -232,6 +238,31 @@ function MESSAGE:ToGroup( Group, Settings )
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sends a MESSAGE to a Unit.
|
||||||
|
-- @param #MESSAGE self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
|
||||||
|
-- @return #MESSAGE Message object.
|
||||||
|
function MESSAGE:ToUnit( Unit, Settings )
|
||||||
|
self:F( Unit.IdentifiableName )
|
||||||
|
|
||||||
|
if Unit then
|
||||||
|
|
||||||
|
if self.MessageType then
|
||||||
|
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.MessageDuration ~= 0 then
|
||||||
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Sends a MESSAGE to the Blue coalition.
|
--- Sends a MESSAGE to the Blue coalition.
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
|||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SCH%20-%20Scheduler)
|
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||||
--
|
--
|
||||||
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ do -- SET_BASE
|
|||||||
self:F2( { ObjectName = ObjectName } )
|
self:F2( { ObjectName = ObjectName } )
|
||||||
|
|
||||||
local TriggerEvent = true
|
local TriggerEvent = true
|
||||||
if NoTriggerEvent == false then
|
if NoTriggerEvent then
|
||||||
TriggerEvent = false
|
TriggerEvent = false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -317,7 +317,7 @@ do -- SET_BASE
|
|||||||
|
|
||||||
for _, Object in pairs( union.Set ) do
|
for _, Object in pairs( union.Set ) do
|
||||||
if self:IsIncludeObject( Object ) and SetB:IsIncludeObject( Object ) then
|
if self:IsIncludeObject( Object ) and SetB:IsIncludeObject( Object ) then
|
||||||
intersection:AddObject( intersection )
|
intersection:AddObject( Object )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1004,7 +1004,7 @@ do -- SET_GROUP
|
|||||||
|
|
||||||
--- Gets the Set.
|
--- Gets the Set.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @return #SET_GROUP self
|
-- @return #table Table of objects
|
||||||
function SET_GROUP:GetAliveSet()
|
function SET_GROUP:GetAliveSet()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
@@ -1065,10 +1065,15 @@ do -- SET_GROUP
|
|||||||
|
|
||||||
self:Add( group:GetName(), group )
|
self:Add( group:GetName(), group )
|
||||||
|
|
||||||
|
if not DontSetCargoBayLimit then
|
||||||
-- I set the default cargo bay weight limit each time a new group is added to the set.
|
-- I set the default cargo bay weight limit each time a new group is added to the set.
|
||||||
|
-- TODO Why is this here in the first place?
|
||||||
for UnitID, UnitData in pairs( group:GetUnits() ) do
|
for UnitID, UnitData in pairs( group:GetUnits() ) do
|
||||||
|
if UnitData and UnitData:IsAlive() then
|
||||||
UnitData:SetCargoBayWeightLimit()
|
UnitData:SetCargoBayWeightLimit()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1123,7 +1128,9 @@ do -- SET_GROUP
|
|||||||
local NearestGroup = nil -- Wrapper.Group#GROUP
|
local NearestGroup = nil -- Wrapper.Group#GROUP
|
||||||
local ClosestDistance = nil
|
local ClosestDistance = nil
|
||||||
|
|
||||||
for ObjectID, ObjectData in pairs( self.Set ) do
|
local Set = self:GetAliveSet()
|
||||||
|
|
||||||
|
for ObjectID, ObjectData in pairs( Set ) do
|
||||||
if NearestGroup == nil then
|
if NearestGroup == nil then
|
||||||
NearestGroup = ObjectData
|
NearestGroup = ObjectData
|
||||||
ClosestDistance = PointVec2:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
ClosestDistance = PointVec2:DistanceFromPointVec2( ObjectData:GetCoordinate() )
|
||||||
@@ -1327,7 +1334,11 @@ do -- SET_GROUP
|
|||||||
if Event.IniDCSUnit then
|
if Event.IniDCSUnit then
|
||||||
local ObjectName, Object = self:FindInDatabase( Event )
|
local ObjectName, Object = self:FindInDatabase( Event )
|
||||||
if ObjectName then
|
if ObjectName then
|
||||||
if Event.IniDCSGroup:getSize() == 1 then -- Only remove if the last unit of the group was destroyed.
|
local size = 1
|
||||||
|
if Event.IniDCSGroup then
|
||||||
|
size = Event.IniDCSGroup:getSize()
|
||||||
|
end
|
||||||
|
if size == 1 then -- Only remove if the last unit of the group was destroyed.
|
||||||
self:Remove( ObjectName )
|
self:Remove( ObjectName )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -5618,7 +5629,7 @@ do -- SET_ZONE
|
|||||||
if self.Filter.Prefixes then
|
if self.Filter.Prefixes then
|
||||||
local MZonePrefix = false
|
local MZonePrefix = false
|
||||||
for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do
|
for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do
|
||||||
self:T3( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } )
|
self:T2( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } )
|
||||||
if string.find( MZoneName, ZonePrefix, 1 ) then
|
if string.find( MZoneName, ZonePrefix, 1 ) then
|
||||||
MZonePrefix = true
|
MZonePrefix = true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPA%20-%20Spawning)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -1373,7 +1373,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
SpawnTemplate.modulation = self.SpawnInitModu
|
SpawnTemplate.modulation = self.SpawnInitModu
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set country, coaliton and categroy.
|
-- Set country, coalition and category.
|
||||||
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
SpawnTemplate.CategoryID = self.SpawnInitCategory or SpawnTemplate.CategoryID
|
||||||
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
SpawnTemplate.CountryID = self.SpawnInitCountry or SpawnTemplate.CountryID
|
||||||
SpawnTemplate.CoalitionID = self.SpawnInitCoalition or SpawnTemplate.CoalitionID
|
SpawnTemplate.CoalitionID = self.SpawnInitCoalition or SpawnTemplate.CoalitionID
|
||||||
@@ -2360,7 +2360,7 @@ end
|
|||||||
-- The known AIRBASE objects are automatically imported at mission start by MOOSE.
|
-- The known AIRBASE objects are automatically imported at mission start by MOOSE.
|
||||||
-- Therefore, there isn't any New() constructor defined for AIRBASE objects.
|
-- Therefore, there isn't any New() constructor defined for AIRBASE objects.
|
||||||
--
|
--
|
||||||
-- Ships and Farps are added within the mission, and are therefore not known.
|
-- Ships and FARPs are added within the mission, and are therefore not known.
|
||||||
-- For these AIRBASE objects, there isn't an @{Wrapper.Airbase#AIRBASE} enumeration defined.
|
-- For these AIRBASE objects, there isn't an @{Wrapper.Airbase#AIRBASE} enumeration defined.
|
||||||
-- You need to provide the **exact name** of the airbase as the parameter to the @{Wrapper.Airbase#AIRBASE.FindByName}() method!
|
-- You need to provide the **exact name** of the airbase as the parameter to the @{Wrapper.Airbase#AIRBASE.FindByName}() method!
|
||||||
--
|
--
|
||||||
@@ -2827,18 +2827,37 @@ end
|
|||||||
-- The method will search for a #-mark, and will return the text before the #-mark.
|
-- The method will search for a #-mark, and will return the text before the #-mark.
|
||||||
-- It will return nil of no prefix was found.
|
-- It will return nil of no prefix was found.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param DCS#UNIT DCSUnit The @{DCSUnit} to be searched.
|
-- @param Wrapper.Group#GROUP SpawnGroup The GROUP object.
|
||||||
-- @return #string The prefix
|
-- @return #string The prefix or #nil if nothing was found.
|
||||||
-- @return #nil Nothing found
|
|
||||||
function SPAWN:_GetPrefixFromGroup( SpawnGroup )
|
function SPAWN:_GetPrefixFromGroup( SpawnGroup )
|
||||||
self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } )
|
|
||||||
|
|
||||||
local GroupName = SpawnGroup:GetName()
|
local GroupName = SpawnGroup:GetName()
|
||||||
|
|
||||||
if GroupName then
|
if GroupName then
|
||||||
local SpawnPrefix = string.match( GroupName, ".*#" )
|
|
||||||
|
local SpawnPrefix=self:_GetPrefixFromGroupName(GroupName)
|
||||||
|
|
||||||
|
return SpawnPrefix
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return the prefix of a spawned group.
|
||||||
|
-- The method will search for a `#`-mark, and will return the text before the `#`-mark. It will return nil of no prefix was found.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #string SpawnGroupName The name of the spawned group.
|
||||||
|
-- @return #string The prefix or #nil if nothing was found.
|
||||||
|
function SPAWN:_GetPrefixFromGroupName(SpawnGroupName)
|
||||||
|
|
||||||
|
if SpawnGroupName then
|
||||||
|
|
||||||
|
local SpawnPrefix=string.match(SpawnGroupName, ".*#")
|
||||||
|
|
||||||
if SpawnPrefix then
|
if SpawnPrefix then
|
||||||
SpawnPrefix = SpawnPrefix:sub(1, -2)
|
SpawnPrefix = SpawnPrefix:sub(1, -2)
|
||||||
end
|
end
|
||||||
|
|
||||||
return SpawnPrefix
|
return SpawnPrefix
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3235,24 +3254,27 @@ function SPAWN:_OnBirth( EventData )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Obscolete
|
|
||||||
-- @todo Need to delete this... _DATABASE does this now ...
|
|
||||||
|
|
||||||
--- @param #SPAWN self
|
--- @param #SPAWN self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SPAWN:_OnDeadOrCrash( EventData )
|
function SPAWN:_OnDeadOrCrash( EventData )
|
||||||
self:F( self.SpawnTemplatePrefix )
|
self:F( self.SpawnTemplatePrefix )
|
||||||
|
|
||||||
local SpawnGroup = EventData.IniGroup
|
local unit=UNIT:FindByName(EventData.IniUnitName)
|
||||||
|
|
||||||
|
if unit then
|
||||||
|
|
||||||
|
local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName)
|
||||||
|
|
||||||
if SpawnGroup then
|
|
||||||
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
|
|
||||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||||
self:T( { "Dead event: " .. EventPrefix } )
|
self:T( { "Dead event: " .. EventPrefix } )
|
||||||
|
|
||||||
if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then
|
if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then
|
||||||
|
|
||||||
self.AliveUnits = self.AliveUnits - 1
|
self.AliveUnits = self.AliveUnits - 1
|
||||||
|
|
||||||
self:T( "Alive Units: " .. self.AliveUnits )
|
self:T( "Alive Units: " .. self.AliveUnits )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -46,14 +46,14 @@
|
|||||||
-- @field #number InitOffsetAngle Link offset angle in degrees.
|
-- @field #number InitOffsetAngle Link offset angle in degrees.
|
||||||
-- @field #number InitStaticHeading Heading of the static.
|
-- @field #number InitStaticHeading Heading of the static.
|
||||||
-- @field #string InitStaticLivery Livery for aircraft.
|
-- @field #string InitStaticLivery Livery for aircraft.
|
||||||
-- @field #string InitStaticShape Shape of teh static.
|
-- @field #string InitStaticShape Shape of the static.
|
||||||
-- @field #string InitStaticType Type of the static.
|
-- @field #string InitStaticType Type of the static.
|
||||||
-- @field #string InitStaticCategory Categrory of the static.
|
-- @field #string InitStaticCategory Categrory of the static.
|
||||||
-- @field #string InitStaticName Name of the static.
|
-- @field #string InitStaticName Name of the static.
|
||||||
-- @field Core.Point#COORDINATE InitStaticCoordinate Coordinate where to spawn the static.
|
-- @field Core.Point#COORDINATE InitStaticCoordinate Coordinate where to spawn the static.
|
||||||
-- @field #boolean InitDead Set static to be dead if true.
|
-- @field #boolean InitStaticDead Set static to be dead if true.
|
||||||
-- @field #boolean InitCargo If true, static can act as cargo.
|
-- @field #boolean InitStaticCargo If true, static can act as cargo.
|
||||||
-- @field #number InitCargoMass Mass of cargo in kg.
|
-- @field #number InitStaticCargoMass Mass of cargo in kg.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ end
|
|||||||
-- @param #number Mass Mass of the cargo in kg.
|
-- @param #number Mass Mass of the cargo in kg.
|
||||||
-- @return #SPAWNSTATIC self
|
-- @return #SPAWNSTATIC self
|
||||||
function SPAWNSTATIC:InitCargoMass(Mass)
|
function SPAWNSTATIC:InitCargoMass(Mass)
|
||||||
self.InitCargoMass=Mass
|
self.InitStaticCargoMass=Mass
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -269,7 +269,16 @@ end
|
|||||||
-- @param #boolean IsCargo If true, this static can act as cargo.
|
-- @param #boolean IsCargo If true, this static can act as cargo.
|
||||||
-- @return #SPAWNSTATIC self
|
-- @return #SPAWNSTATIC self
|
||||||
function SPAWNSTATIC:InitCargo(IsCargo)
|
function SPAWNSTATIC:InitCargo(IsCargo)
|
||||||
self.InitCargo=IsCargo
|
self.InitStaticCargo=IsCargo
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize as dead.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #boolean IsCargo If true, this static is dead.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitDead(IsDead)
|
||||||
|
self.InitStaticDead=IsDead
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -417,16 +426,16 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
Template.livery_id=self.InitStaticLivery
|
Template.livery_id=self.InitStaticLivery
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitDead~=nil then
|
if self.InitStaticDead~=nil then
|
||||||
Template.dead=self.InitDead
|
Template.dead=self.InitStaticDead
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitCargo~=nil then
|
if self.InitStaticCargo~=nil then
|
||||||
Template.canCargo=self.InitCargo
|
Template.canCargo=self.InitStaticCargo
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitCargoMass~=nil then
|
if self.InitStaticCargoMass~=nil then
|
||||||
Template.mass=self.InitCargoMass
|
Template.mass=self.InitStaticCargoMass
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitLinkUnit then
|
if self.InitLinkUnit then
|
||||||
@@ -479,6 +488,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
-- ED's dirty way to spawn FARPS.
|
-- ED's dirty way to spawn FARPS.
|
||||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||||
else
|
else
|
||||||
|
self:T("Spawning Static")
|
||||||
|
self:T2({Template=Template})
|
||||||
Static=coalition.addStaticObject(CountryID, Template)
|
Static=coalition.addStaticObject(CountryID, Template)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
-- * Create polygon zones.
|
-- * Create polygon zones.
|
||||||
-- * Create moving zones around a unit.
|
-- * Create moving zones around a unit.
|
||||||
-- * Create moving zones around a group.
|
-- * Create moving zones around a group.
|
||||||
-- * Provide the zone behaviour. Some zones are static, while others are moveable.
|
-- * Provide the zone behavior. Some zones are static, while others are moveable.
|
||||||
-- * Enquiry if a coordinate is within a zone.
|
-- * Enquiry if a coordinate is within a zone.
|
||||||
-- * Smoke zones.
|
-- * Smoke zones.
|
||||||
-- * Set a zone probability to control zone selection.
|
-- * Set a zone probability to control zone selection.
|
||||||
@@ -20,10 +20,10 @@
|
|||||||
-- * Draw zones (circular and polygon) on the F10 map.
|
-- * Draw zones (circular and polygon) on the F10 map.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- There are essentially two core functions that zones accomodate:
|
-- There are essentially two core functions that zones accommodate:
|
||||||
--
|
--
|
||||||
-- * Test if an object is within the zone boundaries.
|
-- * Test if an object is within the zone boundaries.
|
||||||
-- * Provide the zone behaviour. Some zones are static, while others are moveable.
|
-- * Provide the zone behavior. Some zones are static, while others are moveable.
|
||||||
--
|
--
|
||||||
-- The object classes are using the zone classes to test the zone boundaries, which can take various forms:
|
-- The object classes are using the zone classes to test the zone boundaries, which can take various forms:
|
||||||
--
|
--
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
-- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability.
|
-- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability.
|
||||||
-- @field #number DrawID Unique ID of the drawn zone on the F10 map.
|
-- @field #number DrawID Unique ID of the drawn zone on the F10 map.
|
||||||
-- @field #table Color Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
-- @field #table Color Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
||||||
|
-- @field #number ZoneID ID of zone. Only zones defined in the ME have an ID!
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -108,7 +109,8 @@ ZONE_BASE = {
|
|||||||
ZoneName = "",
|
ZoneName = "",
|
||||||
ZoneProbability = 1,
|
ZoneProbability = 1,
|
||||||
DrawID=nil,
|
DrawID=nil,
|
||||||
Color={}
|
Color={},
|
||||||
|
ZoneID=nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -130,6 +132,8 @@ function ZONE_BASE:New( ZoneName )
|
|||||||
|
|
||||||
self.ZoneName = ZoneName
|
self.ZoneName = ZoneName
|
||||||
|
|
||||||
|
--_DATABASE:AddZone(ZoneName,self)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -170,6 +174,7 @@ end
|
|||||||
-- @param DCS#Vec3 Vec3 The point to test.
|
-- @param DCS#Vec3 Vec3 The point to test.
|
||||||
-- @return #boolean true if the Vec3 is within the zone.
|
-- @return #boolean true if the Vec3 is within the zone.
|
||||||
function ZONE_BASE:IsVec3InZone( Vec3 )
|
function ZONE_BASE:IsVec3InZone( Vec3 )
|
||||||
|
if not Vec3 then return false end
|
||||||
local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } )
|
local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } )
|
||||||
return InZone
|
return InZone
|
||||||
end
|
end
|
||||||
@@ -288,6 +293,23 @@ function ZONE_BASE:GetCoordinate( Height ) --R2.1
|
|||||||
return self.Coordinate
|
return self.Coordinate
|
||||||
end
|
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.
|
||||||
|
-- @return #number Distance to the reference coordinate in meters.
|
||||||
|
function ZONE_BASE:Get2DDistance(Coordinate)
|
||||||
|
local a=self:GetVec2()
|
||||||
|
local b={}
|
||||||
|
if Coordinate.z then
|
||||||
|
b.x=Coordinate.x
|
||||||
|
b.y=Coordinate.z
|
||||||
|
else
|
||||||
|
b.x=Coordinate.x
|
||||||
|
b.y=Coordinate.y
|
||||||
|
end
|
||||||
|
local dist=UTILS.VecDist2D(a,b)
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
--- Define a random @{DCS#Vec2} within the zone.
|
--- Define a random @{DCS#Vec2} within the zone.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
@@ -601,7 +623,7 @@ function ZONE_RADIUS:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, Lin
|
|||||||
|
|
||||||
Color=Color or self:GetColorRGB()
|
Color=Color or self:GetColorRGB()
|
||||||
Alpha=Alpha or 1
|
Alpha=Alpha or 1
|
||||||
FillColor=FillColor or Color
|
FillColor=FillColor or UTILS.DeepCopy(Color)
|
||||||
FillAlpha=FillAlpha or self:GetColorAlpha()
|
FillAlpha=FillAlpha or self:GetColorAlpha()
|
||||||
|
|
||||||
self.DrawID=coordinate:CircleToAll(Radius, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
self.DrawID=coordinate:CircleToAll(Radius, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
||||||
@@ -789,7 +811,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
--- Scan the zone for the presence of units of the given ObjectCategories.
|
--- Scan the zone for the presence of units of the given ObjectCategories.
|
||||||
-- Note that after a zone has been scanned, the zone can be evaluated by:
|
-- Note that **only after** a zone has been scanned, the zone can be evaluated by:
|
||||||
--
|
--
|
||||||
-- * @{ZONE_RADIUS.IsAllInZoneOfCoalition}(): Scan the presence of units in the zone of a coalition.
|
-- * @{ZONE_RADIUS.IsAllInZoneOfCoalition}(): Scan the presence of units in the zone of a coalition.
|
||||||
-- * @{ZONE_RADIUS.IsAllInZoneOfOtherCoalition}(): Scan the presence of units in the zone of an other coalition.
|
-- * @{ZONE_RADIUS.IsAllInZoneOfOtherCoalition}(): Scan the presence of units in the zone of an other coalition.
|
||||||
@@ -798,10 +820,10 @@ end
|
|||||||
-- * @{ZONE_RADIUS.IsNoneInZone}(): Scan if the zone is empty.
|
-- * @{ZONE_RADIUS.IsNoneInZone}(): Scan if the zone is empty.
|
||||||
-- @{#ZONE_RADIUS.
|
-- @{#ZONE_RADIUS.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param ObjectCategories An array of categories of the objects to find in the zone.
|
-- @param ObjectCategories An array of categories of the objects to find in the zone. E.g. `{Object.Category.UNIT}`
|
||||||
-- @param UnitCategories An array of unit categories of the objects to find in the zone.
|
-- @param UnitCategories An array of unit categories of the objects to find in the zone. E.g. `{Unit.Category.GROUND_UNIT,Unit.Category.SHIP}`
|
||||||
-- @usage
|
-- @usage
|
||||||
-- self.Zone:Scan()
|
-- self.Zone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
||||||
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||||
function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
||||||
|
|
||||||
@@ -1135,7 +1157,7 @@ end
|
|||||||
-- @return #boolean true if the location is within the zone.
|
-- @return #boolean true if the location is within the zone.
|
||||||
function ZONE_RADIUS:IsVec2InZone( Vec2 )
|
function ZONE_RADIUS:IsVec2InZone( Vec2 )
|
||||||
self:F2( Vec2 )
|
self:F2( Vec2 )
|
||||||
|
if not Vec2 then return false end
|
||||||
local ZoneVec2 = self:GetVec2()
|
local ZoneVec2 = self:GetVec2()
|
||||||
|
|
||||||
if ZoneVec2 then
|
if ZoneVec2 then
|
||||||
@@ -1153,7 +1175,7 @@ end
|
|||||||
-- @return #boolean true if the point is within the zone.
|
-- @return #boolean true if the point is within the zone.
|
||||||
function ZONE_RADIUS:IsVec3InZone( Vec3 )
|
function ZONE_RADIUS:IsVec3InZone( Vec3 )
|
||||||
self:F2( Vec3 )
|
self:F2( Vec3 )
|
||||||
|
if not Vec3 then return false end
|
||||||
local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } )
|
local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } )
|
||||||
|
|
||||||
return InZone
|
return InZone
|
||||||
@@ -1161,24 +1183,54 @@ end
|
|||||||
|
|
||||||
--- Returns a random Vec2 location within the zone.
|
--- Returns a random Vec2 location within the zone.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
|
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 100 times to find the right type!
|
||||||
-- @return DCS#Vec2 The random location within the zone.
|
-- @return DCS#Vec2 The random location within the zone.
|
||||||
function ZONE_RADIUS:GetRandomVec2( inner, outer )
|
function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
||||||
self:F( self.ZoneName, inner, outer )
|
|
||||||
|
|
||||||
local Point = {}
|
|
||||||
local Vec2 = self:GetVec2()
|
local Vec2 = self:GetVec2()
|
||||||
local _inner = inner or 0
|
local _inner = inner or 0
|
||||||
local _outer = outer or self:GetRadius()
|
local _outer = outer or self:GetRadius()
|
||||||
|
|
||||||
local angle = math.random() * math.pi * 2;
|
if surfacetypes and type(surfacetypes)~="table" then
|
||||||
Point.x = Vec2.x + math.cos( angle ) * math.random(_inner, _outer);
|
surfacetypes={surfacetypes}
|
||||||
Point.y = Vec2.y + math.sin( angle ) * math.random(_inner, _outer);
|
end
|
||||||
|
|
||||||
self:T( { Point } )
|
local function _getpoint()
|
||||||
|
local point = {}
|
||||||
|
local angle = math.random() * math.pi * 2
|
||||||
|
point.x = Vec2.x + math.cos(angle) * math.random(_inner, _outer)
|
||||||
|
point.y = Vec2.y + math.sin(angle) * math.random(_inner, _outer)
|
||||||
|
return point
|
||||||
|
end
|
||||||
|
|
||||||
return Point
|
local function _checkSurface(point)
|
||||||
|
local stype=land.getSurfaceType(point)
|
||||||
|
for _,sf in pairs(surfacetypes) do
|
||||||
|
if sf==stype then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local point=_getpoint()
|
||||||
|
|
||||||
|
if surfacetypes then
|
||||||
|
local N=1 ; local Nmax=100 ; local gotit=false
|
||||||
|
while gotit==false and N<=Nmax do
|
||||||
|
gotit=_checkSurface(point)
|
||||||
|
if gotit then
|
||||||
|
--env.info(string.format("Got random coordinate with surface type %d after N=%d/%d iterations", land.getSurfaceType(point), N, Nmax))
|
||||||
|
else
|
||||||
|
point=_getpoint()
|
||||||
|
N=N+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
||||||
@@ -1230,15 +1282,15 @@ end
|
|||||||
|
|
||||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone.
|
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||||
-- @return Core.Point#COORDINATE
|
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
|
||||||
function ZONE_RADIUS:GetRandomCoordinate( inner, outer )
|
-- @return Core.Point#COORDINATE The random coordinate.
|
||||||
self:F( self.ZoneName, inner, outer )
|
function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
|
||||||
|
|
||||||
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2(inner, outer) )
|
local vec2=self:GetRandomVec2(inner, outer, surfacetypes)
|
||||||
|
|
||||||
self:T3( { Coordinate = Coordinate } )
|
local Coordinate = COORDINATE:NewFromVec2(vec2)
|
||||||
|
|
||||||
return Coordinate
|
return Coordinate
|
||||||
end
|
end
|
||||||
@@ -1301,7 +1353,7 @@ function ZONE:New( ZoneName )
|
|||||||
|
|
||||||
-- Error!
|
-- Error!
|
||||||
if not Zone then
|
if not Zone then
|
||||||
error( "Zone " .. ZoneName .. " does not exist." )
|
env.error( "ERROR: Zone " .. ZoneName .. " does not exist!" )
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1811,7 +1863,8 @@ function ZONE_POLYGON_BASE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlph
|
|||||||
|
|
||||||
Color=Color or self:GetColorRGB()
|
Color=Color or self:GetColorRGB()
|
||||||
Alpha=Alpha or 1
|
Alpha=Alpha or 1
|
||||||
FillColor=FillColor or Color
|
|
||||||
|
FillColor=FillColor or UTILS.DeepCopy(Color)
|
||||||
FillAlpha=FillAlpha or self:GetColorAlpha()
|
FillAlpha=FillAlpha or self:GetColorAlpha()
|
||||||
|
|
||||||
|
|
||||||
@@ -1913,7 +1966,7 @@ end
|
|||||||
-- @return #boolean true if the location is within the zone.
|
-- @return #boolean true if the location is within the zone.
|
||||||
function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 )
|
function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 )
|
||||||
self:F2( Vec2 )
|
self:F2( Vec2 )
|
||||||
|
if not Vec2 then return false end
|
||||||
local Next
|
local Next
|
||||||
local Prev
|
local Prev
|
||||||
local InPolygon = false
|
local InPolygon = false
|
||||||
@@ -1937,32 +1990,48 @@ function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 )
|
|||||||
return InPolygon
|
return InPolygon
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns if a point is within the zone.
|
||||||
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
|
-- @param DCS#Vec3 Vec3 The point to test.
|
||||||
|
-- @return #boolean true if the point is within the zone.
|
||||||
|
function ZONE_POLYGON_BASE:IsVec3InZone( Vec3 )
|
||||||
|
self:F2( Vec3 )
|
||||||
|
|
||||||
|
if not Vec3 then return false end
|
||||||
|
|
||||||
|
local InZone = self:IsVec2InZone( { x = Vec3.x, y = Vec3.z } )
|
||||||
|
|
||||||
|
return InZone
|
||||||
|
end
|
||||||
|
|
||||||
--- Define a random @{DCS#Vec2} within the zone.
|
--- Define a random @{DCS#Vec2} within the zone.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return DCS#Vec2 The Vec2 coordinate.
|
-- @return DCS#Vec2 The Vec2 coordinate.
|
||||||
function ZONE_POLYGON_BASE:GetRandomVec2()
|
function ZONE_POLYGON_BASE:GetRandomVec2()
|
||||||
self:F2()
|
|
||||||
|
|
||||||
--- It is a bit tricky to find a random point within a polygon. Right now i am doing it the dirty and inefficient way...
|
-- It is a bit tricky to find a random point within a polygon. Right now i am doing it the dirty and inefficient way...
|
||||||
local Vec2Found = false
|
|
||||||
local Vec2
|
-- Get the bounding square.
|
||||||
local BS = self:GetBoundingSquare()
|
local BS = self:GetBoundingSquare()
|
||||||
|
|
||||||
self:T2( BS )
|
local Nmax=1000 ; local n=0
|
||||||
|
while n<Nmax do
|
||||||
|
|
||||||
while Vec2Found == false do
|
-- Random point in the bounding square.
|
||||||
Vec2 = { x = math.random( BS.x1, BS.x2 ), y = math.random( BS.y1, BS.y2 ) }
|
local Vec2={x=math.random(BS.x1, BS.x2), y=math.random(BS.y1, BS.y2)}
|
||||||
self:T2( Vec2 )
|
|
||||||
|
-- Check if this is in the polygon.
|
||||||
if self:IsVec2InZone(Vec2) then
|
if self:IsVec2InZone(Vec2) then
|
||||||
Vec2Found = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self:T2( Vec2 )
|
|
||||||
|
|
||||||
return Vec2
|
return Vec2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
n=n+1
|
||||||
|
end
|
||||||
|
|
||||||
|
self:E("Could not find a random point in the polygon zone!")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone.
|
--- Return a @{Core.Point#POINT_VEC2} object representing a random 2D point at landheight within the zone.
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @return @{Core.Point#POINT_VEC2}
|
-- @return @{Core.Point#POINT_VEC2}
|
||||||
@@ -2075,12 +2144,12 @@ end
|
|||||||
--
|
--
|
||||||
-- ## Declare a ZONE_POLYGON directly in the DCS mission editor!
|
-- ## Declare a ZONE_POLYGON directly in the DCS mission editor!
|
||||||
--
|
--
|
||||||
-- You can declare a ZONE_POLYGON using the DCS mission editor by adding the ~ZONE_POLYGON tag in the group name.
|
-- You can declare a ZONE_POLYGON using the DCS mission editor by adding the #ZONE_POLYGON tag in the group name.
|
||||||
--
|
--
|
||||||
-- So, imagine you have a group declared in the mission editor, with group name `DefenseZone~ZONE_POLYGON`.
|
-- So, imagine you have a group declared in the mission editor, with group name `DefenseZone#ZONE_POLYGON`.
|
||||||
-- Then during mission startup, when loading Moose.lua, this group will be detected as a ZONE_POLYGON declaration.
|
-- Then during mission startup, when loading Moose.lua, this group will be detected as a ZONE_POLYGON declaration.
|
||||||
-- Within the background, a ZONE_POLYGON object will be created within the @{Core.Database} using the properties of the group.
|
-- Within the background, a ZONE_POLYGON object will be created within the @{Core.Database} using the properties of the group.
|
||||||
-- The ZONE_POLYGON name will be the group name without the ~ZONE_POLYGON tag.
|
-- The ZONE_POLYGON name will be the group name without the #ZONE_POLYGON tag.
|
||||||
--
|
--
|
||||||
-- So, you can search yourself for the ZONE_POLYGON by using the @{#ZONE_POLYGON.FindByName}() method.
|
-- So, you can search yourself for the ZONE_POLYGON by using the @{#ZONE_POLYGON.FindByName}() method.
|
||||||
-- In this example, `local PolygonZone = ZONE_POLYGON:FindByName( "DefenseZone" )` would return the ZONE_POLYGON object
|
-- In this example, `local PolygonZone = ZONE_POLYGON:FindByName( "DefenseZone" )` would return the ZONE_POLYGON object
|
||||||
@@ -2152,6 +2221,9 @@ end
|
|||||||
do -- ZONE_AIRBASE
|
do -- ZONE_AIRBASE
|
||||||
|
|
||||||
--- @type ZONE_AIRBASE
|
--- @type ZONE_AIRBASE
|
||||||
|
-- @field #boolean isShip If `true`, airbase is a ship.
|
||||||
|
-- @field #boolean isHelipad If `true`, airbase is a helipad.
|
||||||
|
-- @field #boolean isAirdrome If `true`, airbase is an airdrome.
|
||||||
-- @extends #ZONE_RADIUS
|
-- @extends #ZONE_RADIUS
|
||||||
|
|
||||||
|
|
||||||
@@ -2181,6 +2253,20 @@ do -- ZONE_AIRBASE
|
|||||||
self._.ZoneAirbase = Airbase
|
self._.ZoneAirbase = Airbase
|
||||||
self._.ZoneVec2Cache = self._.ZoneAirbase:GetVec2()
|
self._.ZoneVec2Cache = self._.ZoneAirbase:GetVec2()
|
||||||
|
|
||||||
|
if Airbase:IsShip() then
|
||||||
|
self.isShip=true
|
||||||
|
self.isHelipad=false
|
||||||
|
self.isAirdrome=false
|
||||||
|
elseif Airbase:IsHelipad() then
|
||||||
|
self.isShip=false
|
||||||
|
self.isHelipad=true
|
||||||
|
self.isAirdrome=false
|
||||||
|
elseif Airbase:IsAirdrome() then
|
||||||
|
self.isShip=false
|
||||||
|
self.isHelipad=false
|
||||||
|
self.isAirdrome=true
|
||||||
|
end
|
||||||
|
|
||||||
-- Zone objects are added to the _DATABASE and SET_ZONE objects.
|
-- Zone objects are added to the _DATABASE and SET_ZONE objects.
|
||||||
_EVENTDISPATCHER:CreateEventNewZone( self )
|
_EVENTDISPATCHER:CreateEventNewZone( self )
|
||||||
|
|
||||||
@@ -2194,9 +2280,9 @@ do -- ZONE_AIRBASE
|
|||||||
return self._.ZoneAirbase
|
return self._.ZoneAirbase
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the current location of the @{Wrapper.Group}.
|
--- Returns the current location of the AIRBASE.
|
||||||
-- @param #ZONE_AIRBASE self
|
-- @param #ZONE_AIRBASE self
|
||||||
-- @return DCS#Vec2 The location of the zone based on the @{Wrapper.Group} location.
|
-- @return DCS#Vec2 The location of the zone based on the AIRBASE location.
|
||||||
function ZONE_AIRBASE:GetVec2()
|
function ZONE_AIRBASE:GetVec2()
|
||||||
self:F( self.ZoneName )
|
self:F( self.ZoneName )
|
||||||
|
|
||||||
@@ -2214,24 +2300,6 @@ do -- ZONE_AIRBASE
|
|||||||
return ZoneVec2
|
return ZoneVec2
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a random location within the zone of the @{Wrapper.Group}.
|
|
||||||
-- @param #ZONE_AIRBASE self
|
|
||||||
-- @return DCS#Vec2 The random location of the zone based on the @{Wrapper.Group} location.
|
|
||||||
function ZONE_AIRBASE:GetRandomVec2()
|
|
||||||
self:F( self.ZoneName )
|
|
||||||
|
|
||||||
local Point = {}
|
|
||||||
local Vec2 = self._.ZoneAirbase:GetVec2()
|
|
||||||
|
|
||||||
local angle = math.random() * math.pi*2;
|
|
||||||
Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius();
|
|
||||||
Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius();
|
|
||||||
|
|
||||||
self:T( { Point } )
|
|
||||||
|
|
||||||
return Point
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
||||||
-- @param #ZONE_AIRBASE self
|
-- @param #ZONE_AIRBASE self
|
||||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||||
|
|||||||
@@ -487,8 +487,10 @@ do -- Object
|
|||||||
-- @field UNIT
|
-- @field UNIT
|
||||||
-- @field WEAPON
|
-- @field WEAPON
|
||||||
-- @field STATIC
|
-- @field STATIC
|
||||||
-- @field SCENERY
|
|
||||||
-- @field BASE
|
-- @field BASE
|
||||||
|
-- @field SCENERY
|
||||||
|
-- @field CARGO
|
||||||
|
|
||||||
|
|
||||||
--- @type Object.Desc
|
--- @type Object.Desc
|
||||||
-- @extends #Desc
|
-- @extends #Desc
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -73,7 +73,7 @@
|
|||||||
-- @field Core.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there.
|
-- @field Core.Point#COORDINATE RearmingPlaceCoord Coordinates of the rearming place. If the place is more than 100 m away from the ARTY group, the group will go there.
|
||||||
-- @field #boolean RearmingArtyOnRoad If true, ARTY group will move to rearming place using mainly roads. Default false.
|
-- @field #boolean RearmingArtyOnRoad If true, ARTY group will move to rearming place using mainly roads. Default false.
|
||||||
-- @field Core.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group.
|
-- @field Core.Point#COORDINATE InitialCoord Initial coordinates of the ARTY group.
|
||||||
-- @field #boolean report Arty group sends messages about their current state or target to its coaliton.
|
-- @field #boolean report Arty group sends messages about their current state or target to its coalition.
|
||||||
-- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells.
|
-- @field #table ammoshells Table holding names of the shell types which are included when counting the ammo. Default is {"weapons.shells"} which include most shells.
|
||||||
-- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets.
|
-- @field #table ammorockets Table holding names of the rocket types which are included when counting the ammo. Default is {"weapons.nurs"} which includes most unguided rockets.
|
||||||
-- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles.
|
-- @field #table ammomissiles Table holding names of the missile types which are included when counting the ammo. Default is {"weapons.missiles"} which includes some guided missiles.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- Facilitate the detection of enemy units within the battle zone executed by FACs (Forward Air Controllers) or RECCEs (Reconnassance Units).
|
-- Facilitate the detection of enemy units within the battle zone executed by FACs (Forward Air Controllers) or RECCEs (Reconnaissance Units).
|
||||||
-- It uses the in-built detection capabilities of DCS World, but adds new functionalities.
|
-- It uses the in-built detection capabilities of DCS World, but adds new functionalities.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -37,7 +37,6 @@
|
|||||||
-- @module Functional.Detection
|
-- @module Functional.Detection
|
||||||
-- @image Detection.JPG
|
-- @image Detection.JPG
|
||||||
|
|
||||||
|
|
||||||
do -- DETECTION_BASE
|
do -- DETECTION_BASE
|
||||||
|
|
||||||
--- @type DETECTION_BASE
|
--- @type DETECTION_BASE
|
||||||
@@ -92,7 +91,6 @@ do -- DETECTION_BASE
|
|||||||
--
|
--
|
||||||
-- DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
|
-- DetectionObject:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
|
||||||
--
|
--
|
||||||
--
|
|
||||||
-- ## **DETECTION_ derived classes** group the detected units into a **DetectedItems[]** list
|
-- ## **DETECTION_ derived classes** group the detected units into a **DetectedItems[]** list
|
||||||
--
|
--
|
||||||
-- DETECTION_BASE derived classes build a list called DetectedItems[], which is essentially a first later
|
-- DETECTION_BASE derived classes build a list called DetectedItems[], which is essentially a first later
|
||||||
@@ -128,11 +126,10 @@ do -- DETECTION_BASE
|
|||||||
-- * A probability factor based on the alpha angle between the detected object and the unit detecting.
|
-- * A probability factor based on the alpha angle between the detected object and the unit detecting.
|
||||||
-- A detection from a higher altitude allows for better detection than when on the ground.
|
-- A detection from a higher altitude allows for better detection than when on the ground.
|
||||||
-- * Define a probability factor for "cloudy zones", which are zones where forests or villages are located. In these zones, detection will be much more difficult.
|
-- * Define a probability factor for "cloudy zones", which are zones where forests or villages are located. In these zones, detection will be much more difficult.
|
||||||
-- The mission designer needs to define these cloudy zones within the mission, and needs to register these zones in the DETECTION_ objects additing a probability factor per zone.
|
-- The mission designer needs to define these cloudy zones within the mission, and needs to register these zones in the DETECTION_ objects adding a probability factor per zone.
|
||||||
--
|
--
|
||||||
-- I advise however, that, when you first use the DETECTION derived classes, that you don't use these filters.
|
-- I advise however, that, when you first use the DETECTION derived classes, that you don't use these filters.
|
||||||
-- Only when you experience unrealistic behaviour in your missions, these filters could be applied.
|
-- Only when you experience unrealistic behavior in your missions, these filters could be applied.
|
||||||
--
|
|
||||||
--
|
--
|
||||||
-- ### Distance visual detection probability
|
-- ### Distance visual detection probability
|
||||||
--
|
--
|
||||||
@@ -170,9 +167,9 @@ do -- DETECTION_BASE
|
|||||||
--
|
--
|
||||||
-- Note however, that the more zones are defined to be "cloudy" within a detection, the more performance it will take
|
-- Note however, that the more zones are defined to be "cloudy" within a detection, the more performance it will take
|
||||||
-- from the DETECTION_BASE to calculate the presence of the detected unit within each zone.
|
-- from the DETECTION_BASE to calculate the presence of the detected unit within each zone.
|
||||||
-- Expecially for ZONE_POLYGON, try to limit the amount of nodes of the polygon!
|
-- Especially for ZONE_POLYGON, try to limit the amount of nodes of the polygon!
|
||||||
--
|
--
|
||||||
-- Typically, this kind of filter would be applied for very specific areas were a detection needs to be very realisting for
|
-- Typically, this kind of filter would be applied for very specific areas where a detection needs to be very realistic for
|
||||||
-- AI not to detect so easily targets within a forrest or village rich area.
|
-- AI not to detect so easily targets within a forrest or village rich area.
|
||||||
--
|
--
|
||||||
-- ## Accept / Reject detected units
|
-- ## Accept / Reject detected units
|
||||||
@@ -217,7 +214,7 @@ do -- DETECTION_BASE
|
|||||||
-- -- Start the Detection.
|
-- -- Start the Detection.
|
||||||
-- Detection:Start()
|
-- Detection:Start()
|
||||||
--
|
--
|
||||||
-- ### Detection rejectance if within zone(s).
|
-- ### Detection rejection if within zone(s).
|
||||||
--
|
--
|
||||||
-- Specific ZONE_BASE object(s) can be given as a parameter, which will reject detection if the unit is within the specified ZONE_BASE object(s).
|
-- Specific ZONE_BASE object(s) can be given as a parameter, which will reject detection if the unit is within the specified ZONE_BASE object(s).
|
||||||
-- Use the method @{Functional.Detection#DETECTION_BASE.SetRejectZones}() will reject detected units if they are within the specified zones.
|
-- Use the method @{Functional.Detection#DETECTION_BASE.SetRejectZones}() will reject detected units if they are within the specified zones.
|
||||||
@@ -287,11 +284,10 @@ do -- DETECTION_BASE
|
|||||||
-- @field #boolean LastPos
|
-- @field #boolean LastPos
|
||||||
-- @field #number LastVelocity
|
-- @field #number LastVelocity
|
||||||
|
|
||||||
|
|
||||||
--- @type DETECTION_BASE.DetectedItems
|
--- @type DETECTION_BASE.DetectedItems
|
||||||
-- @list <#DETECTION_BASE.DetectedItem>
|
-- @list <#DETECTION_BASE.DetectedItem>
|
||||||
|
|
||||||
--- Detected item data structrue.
|
--- Detected item data structure.
|
||||||
-- @type DETECTION_BASE.DetectedItem
|
-- @type DETECTION_BASE.DetectedItem
|
||||||
-- @field #boolean IsDetected Indicates if the DetectedItem has been detected or not.
|
-- @field #boolean IsDetected Indicates if the DetectedItem has been detected or not.
|
||||||
-- @field Core.Set#SET_UNIT Set The Set of Units in the detected area.
|
-- @field Core.Set#SET_UNIT Set The Set of Units in the detected area.
|
||||||
@@ -302,7 +298,7 @@ do -- DETECTION_BASE
|
|||||||
-- @field #boolean FriendliesNearBy Indicates if there are friendlies within the detected area.
|
-- @field #boolean FriendliesNearBy Indicates if there are friendlies within the detected area.
|
||||||
-- @field Wrapper.Unit#UNIT NearestFAC The nearest FAC near the Area.
|
-- @field Wrapper.Unit#UNIT NearestFAC The nearest FAC near the Area.
|
||||||
-- @field Core.Point#COORDINATE Coordinate The last known coordinate of the DetectedItem.
|
-- @field Core.Point#COORDINATE Coordinate The last known coordinate of the DetectedItem.
|
||||||
-- @field Core.Point#COORDINATE InterceptCoord Intercept coordiante.
|
-- @field Core.Point#COORDINATE InterceptCoord Intercept coordinate.
|
||||||
-- @field #number DistanceRecce Distance in meters of the Recce.
|
-- @field #number DistanceRecce Distance in meters of the Recce.
|
||||||
-- @field #number Index Detected item key. Could also be a string.
|
-- @field #number Index Detected item key. Could also be a string.
|
||||||
-- @field #string ItemID ItemPrefix .. "." .. self.DetectedItemMax.
|
-- @field #string ItemID ItemPrefix .. "." .. self.DetectedItemMax.
|
||||||
@@ -310,7 +306,7 @@ do -- DETECTION_BASE
|
|||||||
-- @field #table PlayersNearBy Table of nearby players.
|
-- @field #table PlayersNearBy Table of nearby players.
|
||||||
-- @field #table FriendliesDistance Table of distances to friendly units.
|
-- @field #table FriendliesDistance Table of distances to friendly units.
|
||||||
-- @field #string TypeName Type name of the detected unit.
|
-- @field #string TypeName Type name of the detected unit.
|
||||||
-- @field #string CategoryName Catetory name of the detected unit.
|
-- @field #string CategoryName Category name of the detected unit.
|
||||||
-- @field #string Name Name of the detected object.
|
-- @field #string Name Name of the detected object.
|
||||||
-- @field #boolean IsVisible If true, detected object is visible.
|
-- @field #boolean IsVisible If true, detected object is visible.
|
||||||
-- @field #number LastTime Last time the detected item was seen.
|
-- @field #number LastTime Last time the detected item was seen.
|
||||||
@@ -441,7 +437,6 @@ do -- DETECTION_BASE
|
|||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #number Delay The delay in seconds.
|
-- @param #number Delay The delay in seconds.
|
||||||
|
|
||||||
|
|
||||||
self:AddTransition( "Detecting", "Detected", "Detecting" )
|
self:AddTransition( "Detecting", "Detected", "Detecting" )
|
||||||
|
|
||||||
--- OnBefore Transition Handler for Event Detected.
|
--- OnBefore Transition Handler for Event Detected.
|
||||||
@@ -566,12 +561,10 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
local DetectionInterval = self.DetectionCount / (self.RefreshTimeInterval - 1)
|
local DetectionInterval = self.DetectionCount / (self.RefreshTimeInterval - 1)
|
||||||
|
|
||||||
self:ForEachAliveRecce(
|
self:ForEachAliveRecce( function( DetectionGroup )
|
||||||
function( DetectionGroup )
|
|
||||||
self:__Detection( DetectDelay, DetectionGroup, DetectionTimeStamp ) -- Process each detection asynchronously.
|
self:__Detection( DetectDelay, DetectionGroup, DetectionTimeStamp ) -- Process each detection asynchronously.
|
||||||
DetectDelay = DetectDelay + DetectionInterval
|
DetectDelay = DetectDelay + DetectionInterval
|
||||||
end
|
end )
|
||||||
)
|
|
||||||
|
|
||||||
self:__Detect( -self.RefreshTimeInterval )
|
self:__Detect( -self.RefreshTimeInterval )
|
||||||
|
|
||||||
@@ -594,12 +587,11 @@ do -- DETECTION_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #DETECTION_BASE self
|
--- @param #DETECTION_BASE self
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @param Wrapper.Group#GROUP DetectionGroup The Group detecting.
|
-- @param Wrapper.Group#GROUP Detection The Group detecting.
|
||||||
-- @param #number DetectionTimeStamp Time stamp of detection event.
|
-- @param #number DetectionTimeStamp Time stamp of detection event.
|
||||||
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
|
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
|
||||||
|
|
||||||
@@ -670,13 +662,12 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
local DetectedObjectVec3 = DetectedObject:getPoint()
|
local DetectedObjectVec3 = DetectedObject:getPoint()
|
||||||
local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z }
|
local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z }
|
||||||
local DetectionGroupVec3 = Detection:GetVec3()
|
local DetectionGroupVec3 = Detection:GetVec3() or {x=0,y=0,z=0}
|
||||||
local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z }
|
local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z }
|
||||||
|
|
||||||
local Distance = ((DetectedObjectVec3.x - DetectionGroupVec3.x) ^ 2 +
|
local Distance = ((DetectedObjectVec3.x - DetectionGroupVec3.x) ^ 2 +
|
||||||
(DetectedObjectVec3.y - DetectionGroupVec3.y) ^ 2 +
|
(DetectedObjectVec3.y - DetectionGroupVec3.y) ^ 2 +
|
||||||
( DetectedObjectVec3.z - DetectionGroupVec3.z )^2
|
(DetectedObjectVec3.z - DetectionGroupVec3.z) ^ 2) ^ 0.5 / 1000
|
||||||
) ^ 0.5 / 1000
|
|
||||||
|
|
||||||
local DetectedUnitCategory = DetectedObject:getDesc().category
|
local DetectedUnitCategory = DetectedObject:getDesc().category
|
||||||
|
|
||||||
@@ -714,7 +705,7 @@ do -- DETECTION_BASE
|
|||||||
if self.RejectZones then
|
if self.RejectZones then
|
||||||
for RejectZoneID, RejectZone in pairs( self.RejectZones ) do
|
for RejectZoneID, RejectZone in pairs( self.RejectZones ) do
|
||||||
local RejectZone = RejectZone -- Core.Zone#ZONE_BASE
|
local RejectZone = RejectZone -- Core.Zone#ZONE_BASE
|
||||||
if RejectZone:IsPointVec2InZone( DetectedObjectVec2 ) == true then
|
if RejectZone:IsVec2InZone( DetectedObjectVec2 ) == true then
|
||||||
DetectionAccepted = false
|
DetectionAccepted = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -759,7 +750,7 @@ do -- DETECTION_BASE
|
|||||||
local ZoneProbability = ZoneData[2] -- #number
|
local ZoneProbability = ZoneData[2] -- #number
|
||||||
ZoneProbability = ZoneProbability * 30 / 300
|
ZoneProbability = ZoneProbability * 30 / 300
|
||||||
|
|
||||||
if ZoneObject:IsPointVec2InZone( DetectedObjectVec2 ) == true then
|
if ZoneObject:IsVec2InZone( DetectedObjectVec2 ) == true then
|
||||||
local Probability = math.random() -- Selects a number between 0 and 1
|
local Probability = math.random() -- Selects a number between 0 and 1
|
||||||
-- self:T( { Probability, ZoneProbability } )
|
-- self:T( { Probability, ZoneProbability } )
|
||||||
if Probability > ZoneProbability then
|
if Probability > ZoneProbability then
|
||||||
@@ -854,10 +845,8 @@ do -- DETECTION_BASE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- DetectionItems Creation
|
do -- DetectionItems Creation
|
||||||
@@ -906,7 +895,6 @@ do -- DETECTION_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- Initialization methods
|
do -- Initialization methods
|
||||||
@@ -1151,7 +1139,6 @@ do -- DETECTION_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Upon a **visual** detection, the higher the unit is during the detecting process, the more likely the detected unit is to be detected properly.
|
--- Upon a **visual** detection, the higher the unit is during the detecting process, the more likely the detected unit is to be detected properly.
|
||||||
-- A detection at a 90% alpha angle is the most optimal, a detection at 10% is less and a detection at 0% is less likely to be correct.
|
-- A detection at a 90% alpha angle is the most optimal, a detection at 10% is less and a detection at 0% is less likely to be correct.
|
||||||
--
|
--
|
||||||
@@ -1184,7 +1171,6 @@ do -- DETECTION_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do -- Change processing
|
do -- Change processing
|
||||||
@@ -1221,7 +1207,6 @@ do -- DETECTION_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Add a change to the detected zone.
|
--- Add a change to the detected zone.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
||||||
@@ -1315,7 +1300,7 @@ do -- DETECTION_BASE
|
|||||||
return DetectedItem.FriendliesNearIntercept
|
return DetectedItem.FriendliesNearIntercept
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the distance used to identify friendlies near the deteted item ...
|
--- Returns the distance used to identify friendlies near the detected item ...
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The detected item.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The detected item.
|
||||||
-- @return #table A table of distances to friendlies.
|
-- @return #table A table of distances to friendlies.
|
||||||
@@ -1327,7 +1312,7 @@ do -- DETECTION_BASE
|
|||||||
--- Returns if there are friendlies nearby the FAC units ...
|
--- Returns if there are friendlies nearby the FAC units ...
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
||||||
-- @return #boolean trhe if there are friendlies nearby
|
-- @return #boolean true if there are friendlies nearby
|
||||||
function DETECTION_BASE:IsPlayersNearBy( DetectedItem )
|
function DETECTION_BASE:IsPlayersNearBy( DetectedItem )
|
||||||
|
|
||||||
return DetectedItem.PlayersNearBy ~= nil
|
return DetectedItem.PlayersNearBy ~= nil
|
||||||
@@ -1366,7 +1351,6 @@ do -- DETECTION_BASE
|
|||||||
point = InterceptCoord:GetVec3(),
|
point = InterceptCoord:GetVec3(),
|
||||||
radius = self.FriendliesRange,
|
radius = self.FriendliesRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- @param DCS#Unit FoundDCSUnit
|
--- @param DCS#Unit FoundDCSUnit
|
||||||
@@ -1465,8 +1449,7 @@ do -- DETECTION_BASE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end )
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self:F( { Friendlies = DetectedItem.FriendliesNearBy, Players = DetectedItem.PlayersNearBy } )
|
self:F( { Friendlies = DetectedItem.FriendliesNearBy, Players = DetectedItem.PlayersNearBy } )
|
||||||
@@ -1542,7 +1525,6 @@ do -- DETECTION_BASE
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Gets a detected unit type name, taking into account the detection results.
|
--- Gets a detected unit type name, taking into account the detection results.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param Wrapper.Unit#UNIT DetectedUnit
|
-- @param Wrapper.Unit#UNIT DetectedUnit
|
||||||
@@ -1570,7 +1552,6 @@ do -- DETECTION_BASE
|
|||||||
return "Undetected:" .. DetectedUnit:GetName()
|
return "Undetected:" .. DetectedUnit:GetName()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Adds a new DetectedItem to the DetectedItems list.
|
--- Adds a new DetectedItem to the DetectedItems list.
|
||||||
-- The DetectedItem is a table and contains a SET_UNIT in the field Set.
|
-- The DetectedItem is a table and contains a SET_UNIT in the field Set.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
@@ -1584,7 +1565,6 @@ do -- DETECTION_BASE
|
|||||||
self.DetectedItemCount = self.DetectedItemCount + 1
|
self.DetectedItemCount = self.DetectedItemCount + 1
|
||||||
self.DetectedItemMax = self.DetectedItemMax + 1
|
self.DetectedItemMax = self.DetectedItemMax + 1
|
||||||
|
|
||||||
|
|
||||||
DetectedItemKey = DetectedItemKey or self.DetectedItemMax
|
DetectedItemKey = DetectedItemKey or self.DetectedItemMax
|
||||||
self.DetectedItems[DetectedItemKey] = DetectedItem
|
self.DetectedItems[DetectedItemKey] = DetectedItem
|
||||||
self.DetectedItemsByIndex[DetectedItemKey] = DetectedItem
|
self.DetectedItemsByIndex[DetectedItemKey] = DetectedItem
|
||||||
@@ -1636,7 +1616,6 @@ do -- DETECTION_BASE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the DetectedItems by Key.
|
--- Get the DetectedItems by Key.
|
||||||
-- This will return the DetectedItems collection, indexed by the Key, which can be any object that acts as the key of the detection.
|
-- This will return the DetectedItems collection, indexed by the Key, which can be any object that acts as the key of the detection.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
@@ -1657,7 +1636,7 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
--- Get the amount of SETs with detected objects.
|
--- Get the amount of SETs with detected objects.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @return #number The amount of detected items. Note that the amount of detected items can differ with the reality, because detections are not real-time but doen in intervals!
|
-- @return #number The amount of detected items. Note that the amount of detected items can differ with the reality, because detections are not real-time but done in intervals!
|
||||||
function DETECTION_BASE:GetDetectedItemsCount()
|
function DETECTION_BASE:GetDetectedItemsCount()
|
||||||
|
|
||||||
local DetectedCount = self.DetectedItemCount
|
local DetectedCount = self.DetectedItemCount
|
||||||
@@ -1719,7 +1698,7 @@ do -- DETECTION_BASE
|
|||||||
return ""
|
return ""
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the @{Core.Set#SET_UNIT} of a detecttion area using a given numeric index.
|
--- Get the @{Core.Set#SET_UNIT} of a detection area using a given numeric index.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
||||||
-- @return Core.Set#SET_UNIT DetectedSet
|
-- @return Core.Set#SET_UNIT DetectedSet
|
||||||
@@ -1766,7 +1745,6 @@ do -- DETECTION_BASE
|
|||||||
return DetectedItem.IsDetected
|
return DetectedItem.IsDetected
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
do -- Zones
|
do -- Zones
|
||||||
|
|
||||||
--- Get the @{Core.Zone#ZONE_UNIT} of a detection area using a given numeric index.
|
--- Get the @{Core.Zone#ZONE_UNIT} of a detection area using a given numeric index.
|
||||||
@@ -1800,7 +1778,6 @@ do -- DETECTION_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Unlock the detected items when created and unlock all existing detected items.
|
--- Unlock the detected items when created and unlock all existing detected items.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @return #DETECTION_BASE
|
-- @return #DETECTION_BASE
|
||||||
@@ -1824,7 +1801,6 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Lock a detected item.
|
--- Lock a detected item.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
||||||
@@ -1847,9 +1823,6 @@ do -- DETECTION_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Set the detected item coordinate.
|
--- Set the detected item coordinate.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem to set the coordinate at.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem to set the coordinate at.
|
||||||
@@ -1869,7 +1842,6 @@ do -- DETECTION_BASE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the detected item coordinate.
|
--- Get the detected item coordinate.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem to set the coordinate at.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem to set the coordinate at.
|
||||||
@@ -1911,8 +1883,6 @@ do -- DETECTION_BASE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Get the detected item coordinate.
|
--- Get the detected item coordinate.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
||||||
@@ -1928,7 +1898,6 @@ do -- DETECTION_BASE
|
|||||||
return nil, ""
|
return nil, ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Report summary of a detected item using a given numeric index.
|
--- Report summary of a detected item using a given numeric index.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
||||||
@@ -1940,7 +1909,7 @@ do -- DETECTION_BASE
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Report detailed of a detectedion result.
|
--- Report detailed of a detection result.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
||||||
-- @return #string
|
-- @return #string
|
||||||
@@ -1987,8 +1956,6 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Schedule the DETECTION construction.
|
--- Schedule the DETECTION construction.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param #number DelayTime The delay in seconds to wait the reporting.
|
-- @param #number DelayTime The delay in seconds to wait the reporting.
|
||||||
@@ -2078,7 +2045,6 @@ do -- DETECTION_UNITS
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create the DetectedItems list from the DetectedObjects table.
|
--- Create the DetectedItems list from the DetectedObjects table.
|
||||||
-- For each DetectedItem, a one field array is created containing the Unit detected.
|
-- For each DetectedItem, a one field array is created containing the Unit detected.
|
||||||
-- @param #DETECTION_UNITS self
|
-- @param #DETECTION_UNITS self
|
||||||
@@ -2130,7 +2096,6 @@ do -- DETECTION_UNITS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Now we need to loop through the unidentified detected units and add these... These are all new items.
|
-- Now we need to loop through the unidentified detected units and add these... These are all new items.
|
||||||
for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do
|
for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do
|
||||||
|
|
||||||
@@ -2181,7 +2146,6 @@ do -- DETECTION_UNITS
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Report summary of a DetectedItem using a given numeric index.
|
--- Report summary of a DetectedItem using a given numeric index.
|
||||||
-- @param #DETECTION_UNITS self
|
-- @param #DETECTION_UNITS self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
||||||
@@ -2238,7 +2202,6 @@ do -- DETECTION_UNITS
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Report detailed of a detection result.
|
--- Report detailed of a detection result.
|
||||||
-- @param #DETECTION_UNITS self
|
-- @param #DETECTION_UNITS self
|
||||||
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
||||||
@@ -2332,7 +2295,6 @@ do -- DETECTION_TYPES
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create the DetectedItems list from the DetectedObjects table.
|
--- Create the DetectedItems list from the DetectedObjects table.
|
||||||
-- For each DetectedItem, a one field array is created containing the Unit detected.
|
-- For each DetectedItem, a one field array is created containing the Unit detected.
|
||||||
-- @param #DETECTION_TYPES self
|
-- @param #DETECTION_TYPES self
|
||||||
@@ -2371,7 +2333,6 @@ do -- DETECTION_TYPES
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Now we need to loop through the unidentified detected units and add these... These are all new items.
|
-- Now we need to loop through the unidentified detected units and add these... These are all new items.
|
||||||
for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do
|
for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do
|
||||||
|
|
||||||
@@ -2395,8 +2356,6 @@ do -- DETECTION_TYPES
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Check if there are any friendlies nearby.
|
-- Check if there are any friendlies nearby.
|
||||||
for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do
|
for DetectedItemID, DetectedItemData in pairs( self.DetectedItems ) do
|
||||||
|
|
||||||
@@ -2413,8 +2372,6 @@ do -- DETECTION_TYPES
|
|||||||
self:NearestRecce( DetectedItem )
|
self:NearestRecce( DetectedItem )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Report summary of a DetectedItem using a given numeric index.
|
--- Report summary of a DetectedItem using a given numeric index.
|
||||||
@@ -2469,7 +2426,6 @@ do -- DETECTION_TYPES
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
do -- DETECTION_AREAS
|
do -- DETECTION_AREAS
|
||||||
|
|
||||||
--- @type DETECTION_AREAS
|
--- @type DETECTION_AREAS
|
||||||
@@ -2484,14 +2440,14 @@ do -- DETECTION_AREAS
|
|||||||
--
|
--
|
||||||
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
|
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
|
||||||
--
|
--
|
||||||
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DECTECTION_BASE} and
|
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DETECTION_BASE} and
|
||||||
-- the methods to manage the DetectedItems[].Zone(s) is implemented in @{Functional.Detection#DETECTION_AREAS}.
|
-- the methods to manage the DetectedItems[].Zone(s) are implemented in @{Functional.Detection#DETECTION_AREAS}.
|
||||||
--
|
--
|
||||||
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
||||||
--
|
--
|
||||||
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZones}().
|
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZones}().
|
||||||
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZoneCount}().
|
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneCount}().
|
||||||
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_BASE.GetDetectionZone}() with a given index.
|
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneByID}() with a given index.
|
||||||
--
|
--
|
||||||
-- ## 4.4) Flare or Smoke detected units
|
-- ## 4.4) Flare or Smoke detected units
|
||||||
--
|
--
|
||||||
@@ -2513,7 +2469,6 @@ do -- DETECTION_AREAS
|
|||||||
DetectionZoneRange = nil,
|
DetectionZoneRange = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--- DETECTION_AREAS constructor.
|
--- DETECTION_AREAS constructor.
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
||||||
@@ -2535,6 +2490,48 @@ do -- DETECTION_AREAS
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Retrieve set of detected zones.
|
||||||
|
-- @param #DETECTION_AREAS self
|
||||||
|
-- @return Core.Set#SET_ZONE The @{Set} of ZONE_UNIT objects detected.
|
||||||
|
function DETECTION_AREAS:GetDetectionZones()
|
||||||
|
local zoneset = SET_ZONE:New()
|
||||||
|
for _ID,_Item in pairs (self.DetectedItems) do
|
||||||
|
local item = _Item -- #DETECTION_BASE.DetectedItem
|
||||||
|
if item.Zone then
|
||||||
|
zoneset:AddZone(item.Zone)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return zoneset
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Retrieve a specific zone by its ID (number)
|
||||||
|
-- @param #DETECTION_AREAS self
|
||||||
|
-- @param #number ID
|
||||||
|
-- @return Core.Zone#ZONE_UNIT The zone or nil if it does not exist
|
||||||
|
function DETECTION_AREAS:GetDetectionZoneByID(ID)
|
||||||
|
local zone = nil
|
||||||
|
for _ID,_Item in pairs (self.DetectedItems) do
|
||||||
|
local item = _Item -- #DETECTION_BASE.DetectedItem
|
||||||
|
if item.ID == ID then
|
||||||
|
zone = item.Zone
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return zone
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Retrieve number of detected zones.
|
||||||
|
-- @param #DETECTION_AREAS self
|
||||||
|
-- @return #number The number of zones.
|
||||||
|
function DETECTION_AREAS:GetDetectionZoneCount()
|
||||||
|
local zoneset = 0
|
||||||
|
for _ID,_Item in pairs (self.DetectedItems) do
|
||||||
|
if _Item.Zone then
|
||||||
|
zoneset = zoneset + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return zoneset
|
||||||
|
end
|
||||||
|
|
||||||
--- Report summary of a detected item using a given numeric index.
|
--- Report summary of a detected item using a given numeric index.
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
@@ -2593,7 +2590,6 @@ do -- DETECTION_AREAS
|
|||||||
DetectedItemCoordText = DetectedItemCoordinate:ToStringA2G( AttackGroup, Settings )
|
DetectedItemCoordText = DetectedItemCoordinate:ToStringA2G( AttackGroup, Settings )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
|
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
|
||||||
local DetectedItemsCount = DetectedSet:Count()
|
local DetectedItemsCount = DetectedSet:Count()
|
||||||
local DetectedItemsTypes = DetectedSet:GetTypeNames()
|
local DetectedItemsTypes = DetectedSet:GetTypeNames()
|
||||||
@@ -2630,7 +2626,6 @@ do -- DETECTION_AREAS
|
|||||||
return ReportText
|
return ReportText
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Calculate the optimal intercept point of the DetectedItem.
|
--- Calculate the optimal intercept point of the DetectedItem.
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem
|
||||||
@@ -2655,8 +2650,6 @@ do -- DETECTION_AREAS
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Smoke the detected units
|
--- Smoke the detected units
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
-- @return #DETECTION_AREAS self
|
-- @return #DETECTION_AREAS self
|
||||||
@@ -2760,13 +2753,11 @@ do -- DETECTION_AREAS
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Make a DetectionSet table. This function will be overridden in the derived classes.
|
||||||
--- Make a DetectionSet table. This function will be overridden in the derived clsses.
|
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
-- @return #DETECTION_AREAS self
|
-- @return #DETECTION_AREAS self
|
||||||
function DETECTION_AREAS:CreateDetectionItems()
|
function DETECTION_AREAS:CreateDetectionItems()
|
||||||
|
|
||||||
|
|
||||||
self:F( "Checking Detected Items for new Detected Units ..." )
|
self:F( "Checking Detected Items for new Detected Units ..." )
|
||||||
-- self:F( { DetectedObjects = self.DetectedObjects } )
|
-- self:F( { DetectedObjects = self.DetectedObjects } )
|
||||||
|
|
||||||
@@ -2794,8 +2785,6 @@ do -- DETECTION_AREAS
|
|||||||
-- self:IdentifyDetectedObject( DetectedZoneObject )
|
-- self:IdentifyDetectedObject( DetectedZoneObject )
|
||||||
AreaExists = true
|
AreaExists = true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
else
|
else
|
||||||
-- The center object of the detected area has not been detected. Find an other unit of the set to become the center of the area.
|
-- The center object of the detected area has not been detected. Find an other unit of the set to become the center of the area.
|
||||||
-- First remove the center unit from the set.
|
-- First remove the center unit from the set.
|
||||||
@@ -2882,11 +2871,9 @@ do -- DETECTION_AREAS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- We iterated through the existing detection areas and:
|
-- We iterated through the existing detection areas and:
|
||||||
-- - We checked which units are still detected in each detection area. Those units were flagged as Identified.
|
-- - We checked which units are still detected in each detection area. Those units were flagged as Identified.
|
||||||
-- - We recentered the detection area to new center units where it was needed.
|
-- - We re-centered the detection area to new center units where it was needed.
|
||||||
--
|
--
|
||||||
-- Now we need to loop through the unidentified detected units and see where they belong:
|
-- Now we need to loop through the unidentified detected units and see where they belong:
|
||||||
-- - They can be added to a new detection area and become the new center unit.
|
-- - They can be added to a new detection area and become the new center unit.
|
||||||
@@ -2961,15 +2948,13 @@ do -- DETECTION_AREAS
|
|||||||
self:SetDetectedItemThreatLevel( DetectedItem ) -- Calculate A2G threat level
|
self:SetDetectedItemThreatLevel( DetectedItem ) -- Calculate A2G threat level
|
||||||
self:NearestRecce( DetectedItem )
|
self:NearestRecce( DetectedItem )
|
||||||
|
|
||||||
|
|
||||||
if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then
|
if DETECTION_AREAS._SmokeDetectedUnits or self._SmokeDetectedUnits then
|
||||||
DetectedZone.ZoneUNIT:SmokeRed()
|
DetectedZone.ZoneUNIT:SmokeRed()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- DetectedSet:Flush( self )
|
-- DetectedSet:Flush( self )
|
||||||
|
|
||||||
DetectedSet:ForEachUnit(
|
DetectedSet:ForEachUnit( --- @param Wrapper.Unit#UNIT DetectedUnit
|
||||||
--- @param Wrapper.Unit#UNIT DetectedUnit
|
|
||||||
function( DetectedUnit )
|
function( DetectedUnit )
|
||||||
if DetectedUnit:IsAlive() then
|
if DetectedUnit:IsAlive() then
|
||||||
-- self:T( "Detected Set #" .. DetectedItem.ID .. ":" .. DetectedUnit:GetName() )
|
-- self:T( "Detected Set #" .. DetectedItem.ID .. ":" .. DetectedUnit:GetName() )
|
||||||
@@ -2980,8 +2965,7 @@ do -- DETECTION_AREAS
|
|||||||
DetectedUnit:SmokeGreen()
|
DetectedUnit:SmokeGreen()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end )
|
||||||
)
|
|
||||||
if DETECTION_AREAS._FlareDetectedZones or self._FlareDetectedZones then
|
if DETECTION_AREAS._FlareDetectedZones or self._FlareDetectedZones then
|
||||||
DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0, 90 ) )
|
DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0, 90 ) )
|
||||||
end
|
end
|
||||||
@@ -2999,4 +2983,3 @@ do -- DETECTION_AREAS
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -949,11 +949,14 @@ function PSEUDOATC:LocalAirports(GID, UID)
|
|||||||
for _,airbase in pairs(airports) do
|
for _,airbase in pairs(airports) do
|
||||||
|
|
||||||
local name=airbase:getName()
|
local name=airbase:getName()
|
||||||
local q=AIRBASE:FindByName(name):GetCoordinate()
|
local a=AIRBASE:FindByName(name)
|
||||||
|
if a then
|
||||||
|
local q=a:GetCoordinate()
|
||||||
local d=q:Get2DDistance(pos)
|
local d=q:Get2DDistance(pos)
|
||||||
|
|
||||||
-- Add to table.
|
-- Add to table.
|
||||||
table.insert(self.group[GID].player[UID].airports, {distance=d, name=name})
|
table.insert(self.group[GID].player[UID].airports, {distance=d, name=name})
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
-- @field #string category Category of aircarft: "plane" or "heli".
|
-- @field #string category Category of aircarft: "plane" or "heli".
|
||||||
-- @field #number groupsize Number of aircraft in group.
|
-- @field #number groupsize Number of aircraft in group.
|
||||||
-- @field #string friendly Possible departure/destination airport: all=blue+red+neutral, same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red.
|
-- @field #string friendly Possible departure/destination airport: all=blue+red+neutral, same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red.
|
||||||
-- @field #table ctable Table with the valid coalitons from choice self.friendly.
|
-- @field #table ctable Table with the valid coalitions from choice self.friendly.
|
||||||
-- @field #table aircraft Table which holds the basic aircraft properties (speed, range, ...).
|
-- @field #table aircraft Table which holds the basic aircraft properties (speed, range, ...).
|
||||||
-- @field #number Vcruisemax Max cruise speed in m/s (250 m/s = 900 km/h = 486 kt) set by user.
|
-- @field #number Vcruisemax Max cruise speed in m/s (250 m/s = 900 km/h = 486 kt) set by user.
|
||||||
-- @field #number Vclimb Default climb rate in ft/min.
|
-- @field #number Vclimb Default climb rate in ft/min.
|
||||||
@@ -348,7 +348,7 @@ RAT={
|
|||||||
category = nil, -- Category of aircarft: "plane" or "heli".
|
category = nil, -- Category of aircarft: "plane" or "heli".
|
||||||
groupsize=nil, -- Number of aircraft in the group.
|
groupsize=nil, -- Number of aircraft in the group.
|
||||||
friendly = "same", -- Possible departure/destination airport: same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red, neutral.
|
friendly = "same", -- Possible departure/destination airport: same=spawn+neutral, spawnonly=spawn, blue=blue+neutral, blueonly=blue, red=red+neutral, redonly=red, neutral.
|
||||||
ctable = {}, -- Table with the valid coalitons from choice self.friendly.
|
ctable = {}, -- Table with the valid coalitions from choice self.friendly.
|
||||||
aircraft = {}, -- Table which holds the basic aircraft properties (speed, range, ...).
|
aircraft = {}, -- Table which holds the basic aircraft properties (speed, range, ...).
|
||||||
Vcruisemax=nil, -- Max cruise speed in set by user.
|
Vcruisemax=nil, -- Max cruise speed in set by user.
|
||||||
Vclimb=1500, -- Default climb rate in ft/min.
|
Vclimb=1500, -- Default climb rate in ft/min.
|
||||||
@@ -657,7 +657,7 @@ end
|
|||||||
-- @param #RAT self
|
-- @param #RAT self
|
||||||
-- @param #number naircraft (Optional) Number of aircraft to spawn. Default is one aircraft.
|
-- @param #number naircraft (Optional) Number of aircraft to spawn. Default is one aircraft.
|
||||||
-- @return #boolean True if spawning was successful or nil if nothing was spawned.
|
-- @return #boolean True if spawning was successful or nil if nothing was spawned.
|
||||||
-- @usage yak:Spawn(5) will spawn five aircraft. By default aircraft will spawn at neutral and red airports if the template group is part of the red coaliton.
|
-- @usage yak:Spawn(5) will spawn five aircraft. By default aircraft will spawn at neutral and red airports if the template group is part of the red coalition.
|
||||||
function RAT:Spawn(naircraft)
|
function RAT:Spawn(naircraft)
|
||||||
|
|
||||||
-- Make sure that this function is only been called once per RAT object.
|
-- Make sure that this function is only been called once per RAT object.
|
||||||
@@ -1289,7 +1289,7 @@ end
|
|||||||
|
|
||||||
--- Include all airports which lie in a zone as possible destinations.
|
--- Include all airports which lie in a zone as possible destinations.
|
||||||
-- @param #RAT self
|
-- @param #RAT self
|
||||||
-- @param Core.Zone#ZONE zone Zone in which the departure airports lie. Has to be a MOOSE zone.
|
-- @param Core.Zone#ZONE zone Zone in which the destination airports lie. Has to be a MOOSE zone.
|
||||||
-- @return #RAT RAT self object.
|
-- @return #RAT RAT self object.
|
||||||
function RAT:SetDestinationsFromZone(zone)
|
function RAT:SetDestinationsFromZone(zone)
|
||||||
self:F2(zone)
|
self:F2(zone)
|
||||||
@@ -1305,7 +1305,7 @@ end
|
|||||||
|
|
||||||
--- Include all airports which lie in a zone as possible destinations.
|
--- Include all airports which lie in a zone as possible destinations.
|
||||||
-- @param #RAT self
|
-- @param #RAT self
|
||||||
-- @param Core.Zone#ZONE zone Zone in which the destination airports lie. Has to be a MOOSE zone.
|
-- @param Core.Zone#ZONE zone Zone in which the departure airports lie. Has to be a MOOSE zone.
|
||||||
-- @return #RAT RAT self object.
|
-- @return #RAT RAT self object.
|
||||||
function RAT:SetDeparturesFromZone(zone)
|
function RAT:SetDeparturesFromZone(zone)
|
||||||
self:F2(zone)
|
self:F2(zone)
|
||||||
|
|||||||
@@ -91,13 +91,16 @@
|
|||||||
-- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated.
|
-- @field #boolean trackmissiles If true (default), all missile types are tracked and impact point to closest bombing target is evaluated.
|
||||||
-- @field #boolean defaultsmokebomb If true, initialize player settings to smoke bomb.
|
-- @field #boolean defaultsmokebomb If true, initialize player settings to smoke bomb.
|
||||||
-- @field #boolean autosave If true, automatically save results every X seconds.
|
-- @field #boolean autosave If true, automatically save results every X seconds.
|
||||||
-- @field #number instructorfreq Frequency on which the range control transmits.
|
-- @field #number instructorfreq Frequency on which the range control transmitts.
|
||||||
-- @field Sound.RadioQueue#RADIOQUEUE instructor Instructor radio queue.
|
-- @field Sound.RadioQueue#RADIOQUEUE instructor Instructor radio queue.
|
||||||
-- @field #number rangecontrolfreq Frequency on which the range control transmits.
|
-- @field #number rangecontrolfreq Frequency on which the range control transmitts.
|
||||||
-- @field Sound.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue.
|
-- @field Sound.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue.
|
||||||
-- @field #string rangecontrolrelayname Name of relay unit.
|
-- @field #string rangecontrolrelayname Name of relay unit.
|
||||||
-- @field #string instructorrelayname Name of relay unit.
|
-- @field #string instructorrelayname Name of relay unit.
|
||||||
-- @field #string soundpath Path inside miz file where the sound files are located. Default is "Range Soundfiles/".
|
-- @field #string soundpath Path inside miz file where the sound files are located. Default is "Range Soundfiles/".
|
||||||
|
-- @field #boolean targetsheet If true, players can save their target sheets. Rangeboss will not work if targetsheets do not save.
|
||||||
|
-- @field #string targetpath Path where to save the target sheets.
|
||||||
|
-- @field #string targetprefix File prefix for target sheet files.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
||||||
@@ -121,7 +124,7 @@
|
|||||||
--
|
--
|
||||||
-- Due to a DCS bug, it is not possible to directly monitor when a player enters a plane. So in a mission with client slots, it is vital that
|
-- Due to a DCS bug, it is not possible to directly monitor when a player enters a plane. So in a mission with client slots, it is vital that
|
||||||
-- a player first enters as spectator or hits ESC twice and **after that** jumps into the slot of his aircraft!
|
-- a player first enters as spectator or hits ESC twice and **after that** jumps into the slot of his aircraft!
|
||||||
-- If that is not done, the script is not started correctly. This can be checked by looking at the radio menus. If the mission was entered correctly,
|
-- If that is not done, the script is not started correctly. This can be checked by looking at the radio menues. If the mission was entered correctly,
|
||||||
-- there should be an "On the Range" menu items in the "F10. Other..." menu.
|
-- there should be an "On the Range" menu items in the "F10. Other..." menu.
|
||||||
--
|
--
|
||||||
-- # Strafe Pits
|
-- # Strafe Pits
|
||||||
@@ -151,7 +154,7 @@
|
|||||||
--
|
--
|
||||||
-- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Static} objects defined in the mission editor.
|
-- * The first parameter *targetnames* defines the target or targets. This can be a single item or a Table with the name(s) of @{Wrapper.Unit} or @{Static} objects defined in the mission editor.
|
||||||
-- * The (optional) parameter *goodhitrange* specifies the radius in metres around the target within which a bomb/rocket hit is considered to be "good".
|
-- * The (optional) parameter *goodhitrange* specifies the radius in metres around the target within which a bomb/rocket hit is considered to be "good".
|
||||||
-- * If final (optional) parameter *randommove* can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone.
|
-- * If final (optional) parameter "*randommove*" can be enabled to create moving targets. If this parameter is set to true, the units of this bombing target will randomly move within the range zone.
|
||||||
-- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired.
|
-- Note that there might be quirks since DCS units can get stuck in buildings etc. So it might be safer to manually define a route for the units in the mission editor if moving targets are desired.
|
||||||
--
|
--
|
||||||
-- ## Adding Groups
|
-- ## Adding Groups
|
||||||
@@ -231,6 +234,16 @@
|
|||||||
--
|
--
|
||||||
-- Strafing results are currently **not** saved.
|
-- Strafing results are currently **not** saved.
|
||||||
--
|
--
|
||||||
|
-- # FSM Events
|
||||||
|
--
|
||||||
|
-- This class creates additional events that can be used by mission designers for custom reactions
|
||||||
|
--
|
||||||
|
-- * `EnterRange` when a player enters a range zone. See @{#RANGE.OnAfterEnterRange}
|
||||||
|
-- * `ExitRange` when a player leaves a range zone. See @{#RANGE.OnAfterExitRange}
|
||||||
|
-- * `Impact` on impact of a player's weapon on a bombing target. See @{#RANGE.OnAfterImpact}
|
||||||
|
-- * `RollingIn` when a player rolls in on a strafing target. See @{#RANGE.OnAfterRollingIn}
|
||||||
|
-- * `StrafeResult` when a player finishes a strafing run. See @{#RANGE.OnAfterStrafeResult}
|
||||||
|
--
|
||||||
-- # Examples
|
-- # Examples
|
||||||
--
|
--
|
||||||
-- ## Goldwater Range
|
-- ## Goldwater Range
|
||||||
@@ -260,11 +273,12 @@
|
|||||||
-- -- Add bombing targets. A good hit is if the bomb falls less then 50 m from the target.
|
-- -- Add bombing targets. A good hit is if the bomb falls less then 50 m from the target.
|
||||||
-- GoldwaterRange:AddBombingTargets(bombtargets, 50)
|
-- GoldwaterRange:AddBombingTargets(bombtargets, 50)
|
||||||
--
|
--
|
||||||
-- -- Start Range.
|
-- -- Start range.
|
||||||
-- GoldwaterRange:Start()
|
-- GoldwaterRange:Start()
|
||||||
--
|
--
|
||||||
-- The [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is (implicitly) used in this example.
|
-- The [476th - Air Weapons Range Objects mod](http://www.476vfightergroup.com/downloads.php?do=file&id=287) is (implicitly) used in this example.
|
||||||
--
|
--
|
||||||
|
--
|
||||||
-- # Debugging
|
-- # Debugging
|
||||||
--
|
--
|
||||||
-- In case you have problems, it is always a good idea to have a look at your DCS log file. You find it in your "Saved Games" folder, so for example in
|
-- In case you have problems, it is always a good idea to have a look at your DCS log file. You find it in your "Saved Games" folder, so for example in
|
||||||
@@ -330,22 +344,25 @@ RANGE = {
|
|||||||
rangecontrolfreq = nil,
|
rangecontrolfreq = nil,
|
||||||
rangecontrol = nil,
|
rangecontrol = nil,
|
||||||
soundpath = "Range Soundfiles/",
|
soundpath = "Range Soundfiles/",
|
||||||
|
targetsheet = nil,
|
||||||
|
targetpath = nil,
|
||||||
|
targetprefix = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Default range parameters.
|
--- Default range parameters.
|
||||||
-- @list Defaults
|
-- @list Defaults
|
||||||
RANGE.Defaults = {
|
RANGE.Defaults = {
|
||||||
goodhitrange = 25, -- meters
|
goodhitrange = 25,
|
||||||
strafemaxalt = 914, -- meters AGL
|
strafemaxalt = 914,
|
||||||
dtBombtrack = 0.005, -- seconds
|
dtBombtrack = 0.005,
|
||||||
Tmsg = 30, -- seconds
|
Tmsg = 30,
|
||||||
ndisplayresult = 10,
|
ndisplayresult = 10,
|
||||||
rangeradius = 5000, -- meters
|
rangeradius = 5000,
|
||||||
TdelaySmoke = 3.0, -- seconds
|
TdelaySmoke = 3.0,
|
||||||
boxlength = 3000, -- meters
|
boxlength = 3000,
|
||||||
boxwidth = 300, -- meters
|
boxwidth = 300,
|
||||||
goodpass = 20, -- targethits per pass
|
goodpass = 20,
|
||||||
foulline = 610, -- meters
|
foulline = 610
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Target type, i.e. unit, static, or coordinate.
|
--- Target type, i.e. unit, static, or coordinate.
|
||||||
@@ -356,7 +373,7 @@ RANGE.Defaults = {
|
|||||||
RANGE.TargetType = {
|
RANGE.TargetType = {
|
||||||
UNIT = "Unit",
|
UNIT = "Unit",
|
||||||
STATIC = "Static",
|
STATIC = "Static",
|
||||||
COORD = "Coordinate",
|
COORD = "Coordinate"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Player settings.
|
--- Player settings.
|
||||||
@@ -393,6 +410,14 @@ RANGE.TargetType = {
|
|||||||
-- @field #number smokepoints Number of smoke points.
|
-- @field #number smokepoints Number of smoke points.
|
||||||
-- @field #number heading Heading of pit.
|
-- @field #number heading Heading of pit.
|
||||||
|
|
||||||
|
--- Strafe status for player.
|
||||||
|
-- @type RANGE.StrafeStatus
|
||||||
|
-- @field #number hits Number of hits on target.
|
||||||
|
-- @field #number time Number of times.
|
||||||
|
-- @field #number ammo Amount of ammo.
|
||||||
|
-- @field #boolean pastfoulline If `true`, player passed foul line. Invalid pass.
|
||||||
|
-- @field #RANGE.StrafeTarget zone Strafe target.
|
||||||
|
|
||||||
--- Bomb target result.
|
--- Bomb target result.
|
||||||
-- @type RANGE.BombResult
|
-- @type RANGE.BombResult
|
||||||
-- @field #string name Name of closest target.
|
-- @field #string name Name of closest target.
|
||||||
@@ -405,6 +430,13 @@ RANGE.TargetType = {
|
|||||||
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
||||||
-- @field #string date OS date.
|
-- @field #string date OS date.
|
||||||
|
|
||||||
|
--- Strafe result.
|
||||||
|
-- @type RANGE.StrafeResult
|
||||||
|
-- @field #string player Player name.
|
||||||
|
-- @field #string airframe Aircraft type of player.
|
||||||
|
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
||||||
|
-- @field #string date OS date.
|
||||||
|
|
||||||
--- Sound file data.
|
--- Sound file data.
|
||||||
-- @type RANGE.Soundfile
|
-- @type RANGE.Soundfile
|
||||||
-- @field #string filename Name of the file
|
-- @field #string filename Name of the file
|
||||||
@@ -517,7 +549,7 @@ RANGE.MenuF10Root = nil
|
|||||||
|
|
||||||
--- Range script version.
|
--- Range script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RANGE.version = "2.3.0"
|
RANGE.version = "2.4.0"
|
||||||
|
|
||||||
-- TODO list:
|
-- TODO list:
|
||||||
-- TODO: Verbosity level for messages.
|
-- TODO: Verbosity level for messages.
|
||||||
@@ -568,6 +600,8 @@ function RANGE:New( rangename )
|
|||||||
self:AddTransition("Stopped", "Start", "Running") -- Start RANGE script.
|
self:AddTransition("Stopped", "Start", "Running") -- Start RANGE script.
|
||||||
self:AddTransition("*", "Status", "*") -- Status of RANGE script.
|
self:AddTransition("*", "Status", "*") -- Status of RANGE script.
|
||||||
self:AddTransition("*", "Impact", "*") -- Impact of bomb/rocket/missile.
|
self:AddTransition("*", "Impact", "*") -- Impact of bomb/rocket/missile.
|
||||||
|
self:AddTransition("*", "RollingIn", "*") -- Player rolling in on strafe target.
|
||||||
|
self:AddTransition("*", "StrafeResult", "*") -- Strafe result of player.
|
||||||
self:AddTransition("*", "EnterRange", "*") -- Player enters the range.
|
self:AddTransition("*", "EnterRange", "*") -- Player enters the range.
|
||||||
self:AddTransition("*", "ExitRange", "*") -- Player leaves the range.
|
self:AddTransition("*", "ExitRange", "*") -- Player leaves the range.
|
||||||
self:AddTransition("*", "Save", "*") -- Save player results.
|
self:AddTransition("*", "Save", "*") -- Save player results.
|
||||||
@@ -625,6 +659,37 @@ function RANGE:New( rangename )
|
|||||||
-- @param #RANGE.BombResult result Data of the bombing run.
|
-- @param #RANGE.BombResult result Data of the bombing run.
|
||||||
-- @param #RANGE.PlayerData player Data of player settings etc.
|
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "RollingIn".
|
||||||
|
-- @function [parent=#RANGE] RollingIn
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||||
|
-- @param #RANGE.StrafeTarget target Strafe target.
|
||||||
|
|
||||||
|
--- On after "RollingIn" event user function. Called when a player rolls in to a strafe taret.
|
||||||
|
-- @function [parent=#RANGE] OnAfterRollingIn
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||||
|
-- @param #RANGE.StrafeTarget target Strafe target.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "StrafeResult".
|
||||||
|
-- @function [parent=#RANGE] StrafeResult
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||||
|
-- @param #RANGE.StrafeResult result Data of the strafing run.
|
||||||
|
|
||||||
|
--- On after "StrafeResult" event user function. Called when a player finished a strafing run.
|
||||||
|
-- @function [parent=#RANGE] OnAfterStrafeResult
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #RANGE.PlayerData player Data of player settings etc.
|
||||||
|
-- @param #RANGE.StrafeResult result Data of the strafing run.
|
||||||
|
|
||||||
--- Triggers the FSM event "EnterRange".
|
--- Triggers the FSM event "EnterRange".
|
||||||
-- @function [parent=#RANGE] EnterRange
|
-- @function [parent=#RANGE] EnterRange
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
@@ -869,6 +934,22 @@ function RANGE:SetAutosaveOff()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Enable saving of player's target sheets and specify an optional directory path.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string path (Optional) Path where to save the target sheets.
|
||||||
|
-- @param #string prefix (Optional) Prefix for target sheet files. File name will be saved as *prefix_aircrafttype-0001.csv*, *prefix_aircrafttype-0002.csv*, etc.
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:SetTargetSheet( path, prefix )
|
||||||
|
if io then
|
||||||
|
self.targetsheet = true
|
||||||
|
self.targetpath = path
|
||||||
|
self.targetprefix = prefix
|
||||||
|
else
|
||||||
|
self:E( self.lid .. "ERROR: io is not desanitized. Cannot save target sheet." )
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set messages to examiner. The examiner will receive messages from all clients.
|
--- Set messages to examiner. The examiner will receive messages from all clients.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string examinergroupname Name of the group of the examiner.
|
-- @param #string examinergroupname Name of the group of the examiner.
|
||||||
@@ -900,10 +981,10 @@ end
|
|||||||
|
|
||||||
--- Set player setting whether bomb impact points are smoked or not.
|
--- Set player setting whether bomb impact points are smoked or not.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #boolean switch (Optional) If true, impact points of bombs will be smoked. Default is true.
|
-- @param #boolean switch If true nor nil default is to smoke impact points of bombs.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
function RANGE:SetDefaultPlayerSmokeBomb( switch )
|
function RANGE:SetDefaultPlayerSmokeBomb( switch )
|
||||||
if switch == nil or switch == true then
|
if switch == true or switch == nil then
|
||||||
self.defaultsmokebomb = true
|
self.defaultsmokebomb = true
|
||||||
else
|
else
|
||||||
self.defaultsmokebomb = false
|
self.defaultsmokebomb = false
|
||||||
@@ -1183,7 +1264,7 @@ function RANGE:AddStrafePit( targetnames, boxlength, boxwidth, heading, inverseh
|
|||||||
if heading < 0 then
|
if heading < 0 then
|
||||||
heading = heading + 360
|
heading = heading + 360
|
||||||
end
|
end
|
||||||
if heading >= 360 then
|
if heading > 360 then
|
||||||
heading = heading - 360
|
heading = heading - 360
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1246,7 +1327,7 @@ end
|
|||||||
-- @param #number boxlength (Optional) Length of the approach box in meters. Default is 3000 m.
|
-- @param #number boxlength (Optional) Length of the approach box in meters. Default is 3000 m.
|
||||||
-- @param #number boxwidth (Optional) Width of the approach box in meters. Default is 300 m.
|
-- @param #number boxwidth (Optional) Width of the approach box in meters. Default is 300 m.
|
||||||
-- @param #number heading (Optional) Approach heading in Degrees. Default is heading of the unit as defined in the mission editor.
|
-- @param #number heading (Optional) Approach heading in Degrees. Default is heading of the unit as defined in the mission editor.
|
||||||
-- @param #boolean inverseheading (Optional) Use inverse heading (heading --> heading - 180 Degrees). Default is false.
|
-- @param #boolean inverseheading (Optional) Take inverse heading (heading --> heading - 180 Degrees). Default is false.
|
||||||
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
-- @param #number goodpass (Optional) Number of hits for a "good" strafing pass. Default is 20.
|
||||||
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
-- @param #number foulline (Optional) Foul line distance. Hits from closer than this distance are not counted. Default 610 m = 2000 ft. Set to 0 for no foul line.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
@@ -1281,8 +1362,8 @@ end
|
|||||||
--- Add bombing target(s) to range.
|
--- Add bombing target(s) to range.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #table targetnames Single or multiple (Table) names of unit or static objects serving as bomb targets.
|
-- @param #table targetnames Single or multiple (Table) names of unit or static objects serving as bomb targets.
|
||||||
-- @param #number goodhitrange (Optional) Max hit distance from target unit in meters which is considered as a good hit. Default is 25 m.
|
-- @param #number goodhitrange (Optional) Max distance from target unit (in meters) which is considered as a good hit. Default is 25 m.
|
||||||
-- @param #boolean randommove (Optional) If true, unit will move randomly within the range. Default is false.
|
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
function RANGE:AddBombingTargets( targetnames, goodhitrange, randommove )
|
function RANGE:AddBombingTargets( targetnames, goodhitrange, randommove )
|
||||||
self:F( { targetnames = targetnames, goodhitrange = goodhitrange, randommove = randommove } )
|
self:F( { targetnames = targetnames, goodhitrange = goodhitrange, randommove = randommove } )
|
||||||
@@ -1320,8 +1401,8 @@ end
|
|||||||
--- Add a unit or static object as bombing target.
|
--- Add a unit or static object as bombing target.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE unit Positionable (unit or static) of the strafe target.
|
-- @param Wrapper.Positionable#POSITIONABLE unit Positionable (unit or static) of the strafe target.
|
||||||
-- @param #number goodhitrange (Optional) Max hit distance from target unit in meters which is considered as a good hit. Default is 25 m.
|
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
||||||
-- @param #boolean randommove (Optional) If true, unit will move randomly within the range. Default is false.
|
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
function RANGE:AddBombingTargetUnit( unit, goodhitrange, randommove )
|
function RANGE:AddBombingTargetUnit( unit, goodhitrange, randommove )
|
||||||
self:F( { unit = unit, goodhitrange = goodhitrange, randommove = randommove } )
|
self:F( { unit = unit, goodhitrange = goodhitrange, randommove = randommove } )
|
||||||
@@ -1374,25 +1455,12 @@ function RANGE:AddBombingTargetUnit( unit, goodhitrange, randommove )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a coordinate of a bombing target.
|
--- Add a coordinate of a bombing target. This
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Core.Point#COORDINATE coord The coordinate.
|
-- @param Core.Point#COORDINATE coord The coordinate.
|
||||||
-- @param #string name (Optional) Name of target. Default is "Bomb Target".
|
-- @param #string name Name of target.
|
||||||
-- @param #number goodhitrange (Optional) Max hit distance from target unit in meters which is considered as a good hit. Default is 25 m.
|
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
-- @usage
|
|
||||||
--
|
|
||||||
-- -- Setup a Range
|
|
||||||
-- RangeOne = RANGE:New( "Range One" )
|
|
||||||
-- -- Find the STATIC target object as setup in the ME.
|
|
||||||
-- RangeOneBombTarget = STATIC:FindByName( "RangeOneBombTarget" )
|
|
||||||
-- -- Add the coordinate of the STATIC target object as a bomb target (thus keeping the bomb function active, even if the STATIC target is destroyed).
|
|
||||||
-- RangeOne:AddBombingTargetCoordinate( RangeOneBombTarget:GetCoordinate(), "RangeOneBombTarget", 50)
|
|
||||||
-- -- Or, add the coordinate of the STATIC target object as a bomb target using default values (name will be "Bomb Target", goodhitrange will be 25 m).
|
|
||||||
-- RangeOne:AddBombingTargetCoordinate( RangeOneBombTarget:GetCoordinate() )
|
|
||||||
-- -- Start Range.
|
|
||||||
-- RangeOne:Start()
|
|
||||||
--
|
|
||||||
function RANGE:AddBombingTargetCoordinate( coord, name, goodhitrange )
|
function RANGE:AddBombingTargetCoordinate( coord, name, goodhitrange )
|
||||||
|
|
||||||
local target = {} -- #RANGE.BombTarget
|
local target = {} -- #RANGE.BombTarget
|
||||||
@@ -1413,8 +1481,8 @@ end
|
|||||||
--- Add all units of a group as bombing targets.
|
--- Add all units of a group as bombing targets.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Wrapper.Group#GROUP group Group of bombing targets.
|
-- @param Wrapper.Group#GROUP group Group of bombing targets.
|
||||||
-- @param #number goodhitrange (Optional) Max hit distance from target unit in meters which is considered as a good hit. Default is 25 m.
|
-- @param #number goodhitrange Max distance from unit which is considered as a good hit.
|
||||||
-- @param #boolean randommove (Optional) If true, unit will move randomly within the range. Default is false.
|
-- @param #boolean randommove If true, unit will move randomly within the range. Default is false.
|
||||||
-- @return #RANGE self
|
-- @return #RANGE self
|
||||||
function RANGE:AddBombingTargetGroup( group, goodhitrange, randommove )
|
function RANGE:AddBombingTargetGroup( group, goodhitrange, randommove )
|
||||||
self:F( { group = group, goodhitrange = goodhitrange, randommove = randommove } )
|
self:F( { group = group, goodhitrange = goodhitrange, randommove = randommove } )
|
||||||
@@ -1433,22 +1501,11 @@ function RANGE:AddBombingTargetGroup( group, goodhitrange, randommove )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the foul line distance between strafe pit target and a foul line distance marker object.
|
--- Measures the foule line distance between two unit or static objects.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string namepit Name of the strafe pit target object.
|
-- @param #string namepit Name of the strafe pit target object.
|
||||||
-- @param #string namefoulline Name of the foul line distance marker object.
|
-- @param #string namefoulline Name of the fould line distance marker object.
|
||||||
-- @return #number Foul line distance in meters.
|
-- @return #number Foul line distance in meters.
|
||||||
-- @usage
|
|
||||||
--
|
|
||||||
-- -- Setup a Range
|
|
||||||
-- RangeOne = RANGE:New( "Range One" )
|
|
||||||
-- -- Get distance between strafe target objext and foul line distance marker object.
|
|
||||||
-- RangeOneFoulDistance = RangeOne:GetFoullineDistance( "RangeOneStrafeTarget" , "RangeOneFoulLineObject" )
|
|
||||||
-- -- Add a strafe pit using the measured foul line distance. Where nil is used, strafe pit default values will be used - adjust as required.
|
|
||||||
-- RangeOne:AddStrafePit( "RangeOneStrafeTarget", nil, nil, nil, nil, nil, RangeOneFoulDistance )
|
|
||||||
-- -- Start Range.
|
|
||||||
-- RangeOne:Start()
|
|
||||||
--
|
|
||||||
function RANGE:GetFoullineDistance( namepit, namefoulline )
|
function RANGE:GetFoullineDistance( namepit, namefoulline )
|
||||||
self:F( { namepit = namepit, namefoulline = namefoulline } )
|
self:F( { namepit = namepit, namefoulline = namefoulline } )
|
||||||
|
|
||||||
@@ -1573,6 +1630,7 @@ function RANGE:OnEventBirth( EventData )
|
|||||||
self:T3( self.id .. "BIRTH: player = " .. tostring( _playername ) )
|
self:T3( self.id .. "BIRTH: player = " .. tostring( _playername ) )
|
||||||
|
|
||||||
if _unit and _playername then
|
if _unit and _playername then
|
||||||
|
|
||||||
local _uid = _unit:GetID()
|
local _uid = _unit:GetID()
|
||||||
local _group = _unit:GetGroup()
|
local _group = _unit:GetGroup()
|
||||||
local _gid = _group:GetID()
|
local _gid = _group:GetID()
|
||||||
@@ -1586,7 +1644,6 @@ function RANGE:OnEventBirth( EventData )
|
|||||||
self.strafeStatus[_uid] = nil
|
self.strafeStatus[_uid] = nil
|
||||||
|
|
||||||
-- Add Menu commands after a delay of 0.1 seconds.
|
-- Add Menu commands after a delay of 0.1 seconds.
|
||||||
-- SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
|
|
||||||
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
|
self:ScheduleOnce( 0.1, self._AddF10Commands, self, _unitName )
|
||||||
|
|
||||||
-- By default, some bomb impact points and do not flare each hit on target.
|
-- By default, some bomb impact points and do not flare each hit on target.
|
||||||
@@ -1605,13 +1662,12 @@ function RANGE:OnEventBirth( EventData )
|
|||||||
|
|
||||||
-- Start check in zone timer.
|
-- Start check in zone timer.
|
||||||
if self.planes[_uid] ~= true then
|
if self.planes[_uid] ~= true then
|
||||||
-- SCHEDULER:New(nil, self._CheckInZone, {self, EventData.IniUnitName}, 1, 1)
|
|
||||||
self.timerCheckZone = TIMER:New( self._CheckInZone, self, EventData.IniUnitName ):Start( 1, 1 )
|
self.timerCheckZone = TIMER:New( self._CheckInZone, self, EventData.IniUnitName ):Start( 1, 1 )
|
||||||
self.planes[_uid] = true
|
self.planes[_uid] = true
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Range event handler for event hit.
|
--- Range event handler for event hit.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
@@ -1639,7 +1695,7 @@ function RANGE:OnEventHit( EventData )
|
|||||||
local targetname = EventData.TgtUnitName
|
local targetname = EventData.TgtUnitName
|
||||||
|
|
||||||
-- Current strafe target of player.
|
-- Current strafe target of player.
|
||||||
local _currentTarget = self.strafeStatus[_unitID]
|
local _currentTarget = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
|
||||||
|
|
||||||
-- Player has rolled in on a strafing target.
|
-- Player has rolled in on a strafing target.
|
||||||
if _currentTarget and target:IsAlive() then
|
if _currentTarget and target:IsAlive() then
|
||||||
@@ -1672,6 +1728,7 @@ function RANGE:OnEventHit( EventData )
|
|||||||
self:_DisplayMessageToGroup( _unit, text )
|
self:_DisplayMessageToGroup( _unit, text )
|
||||||
self:T2( self.id .. text )
|
self:T2( self.id .. text )
|
||||||
_currentTarget.pastfoulline = true
|
_currentTarget.pastfoulline = true
|
||||||
|
invalidStrafe = true -- Rangeboss Edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1701,7 +1758,6 @@ function RANGE:OnEventHit( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
|
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
|
||||||
@@ -1762,6 +1818,7 @@ function RANGE:OnEventShot( EventData )
|
|||||||
|
|
||||||
-- Only track if distance player to range is < 25 km. Also check that a player shot. No need to track AI weapons.
|
-- Only track if distance player to range is < 25 km. Also check that a player shot. No need to track AI weapons.
|
||||||
if _track and dPR <= self.BombtrackThreshold and _unit and _playername then
|
if _track and dPR <= self.BombtrackThreshold and _unit and _playername then
|
||||||
|
|
||||||
-- Player data.
|
-- Player data.
|
||||||
local playerData = self.PlayerSettings[_playername] -- #RANGE.PlayerData
|
local playerData = self.PlayerSettings[_playername] -- #RANGE.PlayerData
|
||||||
|
|
||||||
@@ -1843,7 +1900,9 @@ function RANGE:OnEventShot( EventData )
|
|||||||
_distance = _temp
|
_distance = _temp
|
||||||
_closetTarget = _bombtarget
|
_closetTarget = _bombtarget
|
||||||
_closeCoord = targetcoord
|
_closeCoord = targetcoord
|
||||||
if _distance <= 0.5 * _bombtarget.goodhitrange then
|
if _distance <= 1.53 then -- Rangeboss Edit
|
||||||
|
_hitquality = "SHACK" -- Rangeboss Edit
|
||||||
|
elseif _distance <= 0.5 * _bombtarget.goodhitrange then -- Rangeboss Edit
|
||||||
_hitquality = "EXCELLENT"
|
_hitquality = "EXCELLENT"
|
||||||
elseif _distance <= _bombtarget.goodhitrange then
|
elseif _distance <= _bombtarget.goodhitrange then
|
||||||
_hitquality = "GOOD"
|
_hitquality = "GOOD"
|
||||||
@@ -1876,6 +1935,10 @@ function RANGE:OnEventShot( EventData )
|
|||||||
result.player = playerData.playername
|
result.player = playerData.playername
|
||||||
result.time = timer.getAbsTime()
|
result.time = timer.getAbsTime()
|
||||||
result.airframe = playerData.airframe
|
result.airframe = playerData.airframe
|
||||||
|
result.roundsFired = 0 -- Rangeboss Edit
|
||||||
|
result.roundsHit = 0 -- Rangeboss Edit
|
||||||
|
result.roundsQuality = "N/A" -- Rangeboss Edit
|
||||||
|
result.rangename = self.rangename
|
||||||
|
|
||||||
-- Add to table.
|
-- Add to table.
|
||||||
table.insert( _results, result )
|
table.insert( _results, result )
|
||||||
@@ -2012,11 +2075,16 @@ end
|
|||||||
-- @param #RANGE.PlayerData player Player data table.
|
-- @param #RANGE.PlayerData player Player data table.
|
||||||
function RANGE:onafterImpact( From, Event, To, result, player )
|
function RANGE:onafterImpact( From, Event, To, result, player )
|
||||||
|
|
||||||
-- Send message to player.
|
|
||||||
local text = string.format( "%s, impact %03d° for %d m (%d ft)", player.playername, result.radial, result.distance, UTILS.MetersToFeet( result.distance ) )
|
|
||||||
-- Only display target name if there is more than one bomb target.
|
-- Only display target name if there is more than one bomb target.
|
||||||
|
local targetname = nil
|
||||||
if #self.bombingTargets > 1 then
|
if #self.bombingTargets > 1 then
|
||||||
text = text .. string.format( " from bulls of target %s.", result.name )
|
local targetname = result.name
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Send message to player.
|
||||||
|
local text = string.format( "%s, impact %03d° for %d ft", player.playername, result.radial, UTILS.MetersToFeet( result.distance ) )
|
||||||
|
if targetname then
|
||||||
|
text = text .. string.format( " from bulls of target %s." )
|
||||||
else
|
else
|
||||||
text = text .. "."
|
text = text .. "."
|
||||||
end
|
end
|
||||||
@@ -2120,7 +2188,7 @@ function RANGE:onafterSave( From, Event, To )
|
|||||||
_savefile( filename, scores )
|
_savefile( filename, scores )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function called before load event. Checks that io and lfs are desanitized.
|
--- Function called before save event. Checks that io and lfs are desanitized.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
@@ -2211,6 +2279,73 @@ function RANGE:onafterLoad( From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Save target sheet.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string _playername Player name.
|
||||||
|
-- @param #RANGE.StrafeResult result Results table.
|
||||||
|
function RANGE:_SaveTargetSheet( _playername, result ) -- RangeBoss Specific Function
|
||||||
|
|
||||||
|
--- Function that saves data to file
|
||||||
|
local function _savefile( filename, data )
|
||||||
|
local f = io.open( filename, "wb" )
|
||||||
|
if f then
|
||||||
|
f:write( data )
|
||||||
|
f:close()
|
||||||
|
else
|
||||||
|
env.info( "RANGEBOSS EDIT - could not save target sheet to file" )
|
||||||
|
-- self:E(self.lid..string.format("ERROR: could not save target sheet to file %s.\nFile may contain invalid characters.", tostring(filename)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set path or default.
|
||||||
|
local path = self.targetpath
|
||||||
|
if lfs then
|
||||||
|
path = path or lfs.writedir() .. [[Logs\]]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create unused file name.
|
||||||
|
local filename = nil
|
||||||
|
for i = 1, 9999 do
|
||||||
|
|
||||||
|
-- Create file name
|
||||||
|
if self.targetprefix then
|
||||||
|
filename = string.format( "%s_%s-%04d.csv", self.targetprefix, result.airframe, i )
|
||||||
|
else
|
||||||
|
local name = UTILS.ReplaceIllegalCharacters( _playername, "_" )
|
||||||
|
filename = string.format( "RANGERESULTS-%s_Targetsheet-%s-%04d.csv", self.rangename, name, i )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set path.
|
||||||
|
if path ~= nil then
|
||||||
|
filename = path .. "\\" .. filename
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if file exists.
|
||||||
|
local _exists = UTILS.FileExists( filename )
|
||||||
|
if not _exists then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Header line
|
||||||
|
local data = "Name,Target,Rounds Fired,Rounds Hit,Rounds Quality,Airframe,Mission Time,OS Time\n"
|
||||||
|
|
||||||
|
local target = result.name
|
||||||
|
local airframe = result.airframe
|
||||||
|
local roundsFired = result.roundsFired
|
||||||
|
local roundsHit = result.roundsHit
|
||||||
|
local strafeResult = result.roundsQuality
|
||||||
|
local time = UTILS.SecondsToClock( result.time )
|
||||||
|
local date = "n/a"
|
||||||
|
if os then
|
||||||
|
date = os.date()
|
||||||
|
end
|
||||||
|
data = data .. string.format( "%s,%s,%d,%d,%s,%s,%s,%s", _playername, target, roundsFired, roundsHit, strafeResult, airframe, time, date )
|
||||||
|
|
||||||
|
-- Save file.
|
||||||
|
_savefile( filename, data )
|
||||||
|
end
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Display Messages
|
-- Display Messages
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -2246,7 +2381,7 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
|
|||||||
|
|
||||||
-- Sort results table wrt number of hits.
|
-- Sort results table wrt number of hits.
|
||||||
local _sort = function( a, b )
|
local _sort = function( a, b )
|
||||||
return a.hits > b.hits
|
return a.roundsHit > b.roundsHit
|
||||||
end
|
end
|
||||||
table.sort( _results, _sort )
|
table.sort( _results, _sort )
|
||||||
|
|
||||||
@@ -2256,13 +2391,14 @@ function RANGE:_DisplayMyStrafePitResults( _unitName )
|
|||||||
|
|
||||||
-- Loop over results
|
-- Loop over results
|
||||||
for _, _result in pairs( _results ) do
|
for _, _result in pairs( _results ) do
|
||||||
|
local result=_result --#RANGE.StrafeResult
|
||||||
|
|
||||||
-- Message text.
|
-- Message text.
|
||||||
_message = _message .. string.format( "\n[%d] Hits %d - %s - %s", _count, _result.hits, _result.zone.name, _result.text )
|
_message = _message .. string.format( "\n[%d] Hits %d - %s - %s", _count, result.roundsHit, result.name, result.roundsQuality )
|
||||||
|
|
||||||
-- Best result.
|
-- Best result.
|
||||||
if _bestMsg == "" then
|
if _bestMsg == "" then
|
||||||
_bestMsg = string.format( "Hits %d - %s - %s", _result.hits, _result.zone.name, _result.text )
|
_bestMsg = string.format( "Hits %d - %s - %s", result.roundsHit, result.name, result.roundsQuality)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 10 runs
|
-- 10 runs
|
||||||
@@ -2307,15 +2443,15 @@ function RANGE:_DisplayStrafePitResults( _unitName )
|
|||||||
-- Get the best result of the player.
|
-- Get the best result of the player.
|
||||||
local _best = nil
|
local _best = nil
|
||||||
for _, _result in pairs( _results ) do
|
for _, _result in pairs( _results ) do
|
||||||
if _best == nil or _result.hits > _best.hits then
|
if _best == nil or _result.roundsHit > _best.roundsHit then
|
||||||
_best = _result
|
_best = _result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add best result to table.
|
-- Add best result to table.
|
||||||
if _best ~= nil then
|
if _best ~= nil then
|
||||||
local text = string.format( "%s: Hits %i - %s - %s", _playerName, _best.hits, _best.zone.name, _best.text )
|
local text = string.format( "%s: Hits %i - %s - %s", _playerName, _best.roundsHit, _best.name, _best.roundsQuality )
|
||||||
table.insert( _playerResults, { msg = text, hits = _best.hits } )
|
table.insert( _playerResults, { msg = text, hits = _best.roundsHit } )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -2489,7 +2625,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
|
|||||||
local range = coord:Get2DDistance( position )
|
local range = coord:Get2DDistance( position )
|
||||||
|
|
||||||
-- Bearing string.
|
-- Bearing string.
|
||||||
local Bs = string.format( "%03d°", angle )
|
local Bs = string.format( '%03d°', angle )
|
||||||
|
|
||||||
local texthit
|
local texthit
|
||||||
if self.PlayerSettings[playername].flaredirecthits then
|
if self.PlayerSettings[playername].flaredirecthits then
|
||||||
@@ -2531,6 +2667,26 @@ function RANGE:_DisplayRangeInfo( _unitname )
|
|||||||
text = text .. string.format( "Max strafing alt AGL: %s\n", tstrafemaxalt )
|
text = text .. string.format( "Max strafing alt AGL: %s\n", tstrafemaxalt )
|
||||||
text = text .. string.format( "# of strafe targets: %d\n", self.nstrafetargets )
|
text = text .. string.format( "# of strafe targets: %d\n", self.nstrafetargets )
|
||||||
text = text .. string.format( "# of bomb targets: %d\n", self.nbombtargets )
|
text = text .. string.format( "# of bomb targets: %d\n", self.nbombtargets )
|
||||||
|
if self.instructor then
|
||||||
|
local alive = "N/A"
|
||||||
|
if self.instructorrelayname then
|
||||||
|
local relay = UNIT:FindByName( self.instructorrelayname )
|
||||||
|
if relay then
|
||||||
|
alive = tostring( relay:IsAlive() )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
text = text .. string.format( "Instructor %.3f MHz (Relay=%s)\n", self.instructorfreq, alive )
|
||||||
|
end
|
||||||
|
if self.rangecontrol then
|
||||||
|
local alive = "N/A"
|
||||||
|
if self.rangecontrolrelayname then
|
||||||
|
local relay = UNIT:FindByName( self.rangecontrolrelayname )
|
||||||
|
if relay then
|
||||||
|
alive = tostring( relay:IsAlive() )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
text = text .. string.format( "Control %.3f MHz (Relay=%s)\n", self.rangecontrolfreq, alive )
|
||||||
|
end
|
||||||
text = text .. texthit
|
text = text .. texthit
|
||||||
text = text .. textbomb
|
text = text .. textbomb
|
||||||
text = text .. textdelay
|
text = text .. textdelay
|
||||||
@@ -2583,7 +2739,7 @@ function RANGE:_DisplayBombTargets( _unitname )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:_DisplayMessageToGroup( _unit, _text, 60, true, true )
|
self:_DisplayMessageToGroup( _unit, _text, 120, true, true )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2656,7 +2812,7 @@ function RANGE:_DisplayRangeWeather( _unitname )
|
|||||||
-- Get Beaufort wind scale.
|
-- Get Beaufort wind scale.
|
||||||
local Bn, Bd = UTILS.BeaufortScale( Ws )
|
local Bn, Bd = UTILS.BeaufortScale( Ws )
|
||||||
|
|
||||||
local WD = string.format( "%03d°", Wd )
|
local WD = string.format( '%03d°', Wd )
|
||||||
local Ts = string.format( "%d°C", T )
|
local Ts = string.format( "%d°C", T )
|
||||||
|
|
||||||
local hPa2inHg = 0.0295299830714
|
local hPa2inHg = 0.0295299830714
|
||||||
@@ -2744,9 +2900,13 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
|
|
||||||
-- Get player unit and name.
|
-- Get player unit and name.
|
||||||
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
|
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
|
||||||
|
local unitheading = 0 -- RangeBoss
|
||||||
|
|
||||||
if _unit and _playername then
|
if _unit and _playername then
|
||||||
|
|
||||||
|
-- Player data.
|
||||||
|
local playerData=self.PlayerSettings[_playername] -- #RANGE.PlayerData
|
||||||
|
|
||||||
--- Function to check if unit is in zone and facing in the right direction and is below the max alt.
|
--- Function to check if unit is in zone and facing in the right direction and is below the max alt.
|
||||||
local function checkme( targetheading, _zone )
|
local function checkme( targetheading, _zone )
|
||||||
local zone = _zone -- Core.Zone#ZONE
|
local zone = _zone -- Core.Zone#ZONE
|
||||||
@@ -2777,7 +2937,7 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
local _unitID = _unit:GetID()
|
local _unitID = _unit:GetID()
|
||||||
|
|
||||||
-- Currently strafing? (strafeStatus is nil if not)
|
-- Currently strafing? (strafeStatus is nil if not)
|
||||||
local _currentStrafeRun = self.strafeStatus[_unitID]
|
local _currentStrafeRun = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
|
||||||
|
|
||||||
if _currentStrafeRun then -- player has already registered for a strafing run.
|
if _currentStrafeRun then -- player has already registered for a strafing run.
|
||||||
|
|
||||||
@@ -2789,7 +2949,6 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
|
|
||||||
-- Check if player is in strafe zone and below max alt.
|
-- Check if player is in strafe zone and below max alt.
|
||||||
if unitinzone then
|
if unitinzone then
|
||||||
|
|
||||||
-- Still in zone, keep counting hits. Increase counter.
|
-- Still in zone, keep counting hits. Increase counter.
|
||||||
_currentStrafeRun.time = _currentStrafeRun.time + 1
|
_currentStrafeRun.time = _currentStrafeRun.time + 1
|
||||||
|
|
||||||
@@ -2819,9 +2978,11 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
local _ammo = self:_GetAmmo( _unitName )
|
local _ammo = self:_GetAmmo( _unitName )
|
||||||
|
|
||||||
-- Result.
|
-- Result.
|
||||||
local _result = self.strafeStatus[_unitID]
|
local _result = self.strafeStatus[_unitID] --#RANGE.StrafeStatus
|
||||||
|
|
||||||
local _sound = nil -- #RANGE.Soundfile
|
local _sound = nil -- #RANGE.Soundfile
|
||||||
|
|
||||||
|
--[[ --RangeBoss commented out in order to implement strafe quality based on accuracy percentage, not the number of rounds on target
|
||||||
-- Judge this pass. Text is displayed on summary.
|
-- Judge this pass. Text is displayed on summary.
|
||||||
if _result.hits >= _result.zone.goodPass*2 then
|
if _result.hits >= _result.zone.goodPass*2 then
|
||||||
_result.text = "EXCELLENT PASS"
|
_result.text = "EXCELLENT PASS"
|
||||||
@@ -2836,6 +2997,7 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
_result.text = "POOR PASS"
|
_result.text = "POOR PASS"
|
||||||
_sound=RANGE.Sound.RCPoorPass
|
_sound=RANGE.Sound.RCPoorPass
|
||||||
end
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
-- Calculate accuracy of run. Number of hits wrt number of rounds fired.
|
-- Calculate accuracy of run. Number of hits wrt number of rounds fired.
|
||||||
local shots = _result.ammo - _ammo
|
local shots = _result.ammo - _ammo
|
||||||
@@ -2847,16 +3009,61 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Results text and sound message.
|
||||||
|
local resulttext=""
|
||||||
|
if _result.pastfoulline == true then --
|
||||||
|
resulttext = "* INVALID - PASSED FOUL LINE *"
|
||||||
|
_sound = RANGE.Sound.RCPoorPass --
|
||||||
|
else
|
||||||
|
if accur >= 90 then
|
||||||
|
resulttext = "DEADEYE PASS"
|
||||||
|
_sound = RANGE.Sound.RCExcellentPass
|
||||||
|
elseif accur >= 75 then
|
||||||
|
resulttext = "EXCELLENT PASS"
|
||||||
|
_sound = RANGE.Sound.RCExcellentPass
|
||||||
|
elseif accur >= 50 then
|
||||||
|
resulttext = "GOOD PASS"
|
||||||
|
_sound = RANGE.Sound.RCGoodPass
|
||||||
|
elseif accur >= 25 then
|
||||||
|
resulttext = "INEFFECTIVE PASS"
|
||||||
|
_sound = RANGE.Sound.RCIneffectivePass
|
||||||
|
else
|
||||||
|
resulttext = "POOR PASS"
|
||||||
|
_sound = RANGE.Sound.RCPoorPass
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Message text.
|
-- Message text.
|
||||||
local _text = string.format( "%s, hits on target %s: %d", self:_myname( _unitName ), _result.zone.name, _result.hits )
|
local _text = string.format( "%s, hits on target %s: %d", self:_myname( _unitName ), _result.zone.name, _result.hits )
|
||||||
if shots and accur then
|
if shots and accur then
|
||||||
_text = _text .. string.format( "\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur )
|
_text = _text .. string.format( "\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur )
|
||||||
end
|
end
|
||||||
_text = _text .. string.format( "\n%s", _result.text )
|
_text = _text .. string.format( "\n%s", resulttext )
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup( _unit, _text )
|
self:_DisplayMessageToGroup( _unit, _text )
|
||||||
|
|
||||||
|
-- Strafe result.
|
||||||
|
local result = {} -- #RANGE.StrafeResult
|
||||||
|
result.player=_playername
|
||||||
|
result.name=_result.zone.name or "unknown"
|
||||||
|
result.time = timer.getAbsTime()
|
||||||
|
result.roundsFired = shots
|
||||||
|
result.roundsHit = _result.hits
|
||||||
|
result.roundsQuality = resulttext
|
||||||
|
result.strafeAccuracy = accur
|
||||||
|
result.rangename = self.rangename
|
||||||
|
result.airframe=playerData.airframe
|
||||||
|
result.invalid = _result.pastfoulline
|
||||||
|
|
||||||
|
-- Griger Results.
|
||||||
|
self:StrafeResult(playerData, result)
|
||||||
|
|
||||||
|
-- Save trap sheet.
|
||||||
|
if playerData and playerData.targeton and self.targetsheet then
|
||||||
|
self:_SaveTargetSheet( _playername, result )
|
||||||
|
end
|
||||||
|
|
||||||
-- Voice over.
|
-- Voice over.
|
||||||
if self.rangecontrol then
|
if self.rangecontrol then
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCHitsOnTarget.filename, RANGE.Sound.RCHitsOnTarget.duration, self.soundpath )
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCHitsOnTarget.filename, RANGE.Sound.RCHitsOnTarget.duration, self.soundpath )
|
||||||
@@ -2876,7 +3083,7 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
|
|
||||||
-- Save stats so the player can retrieve them.
|
-- Save stats so the player can retrieve them.
|
||||||
local _stats = self.strafePlayerResults[_playername] or {}
|
local _stats = self.strafePlayerResults[_playername] or {}
|
||||||
table.insert( _stats, _result )
|
table.insert( _stats, result )
|
||||||
self.strafePlayerResults[_playername] = _stats
|
self.strafePlayerResults[_playername] = _stats
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2886,12 +3093,13 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
|
|
||||||
-- Check to see if we're in any of the strafing zones (first time).
|
-- Check to see if we're in any of the strafing zones (first time).
|
||||||
for _, _targetZone in pairs( self.strafeTargets ) do
|
for _, _targetZone in pairs( self.strafeTargets ) do
|
||||||
|
local target=_targetZone --#RANGE.StrafeTarget
|
||||||
|
|
||||||
-- Get the current approach zone and check if player is inside.
|
-- Get the current approach zone and check if player is inside.
|
||||||
local zone = _targetZone.polygon -- Core.Zone#ZONE_POLYGON_BASE
|
local zone = target.polygon -- Core.Zone#ZONE_POLYGON_BASE
|
||||||
|
|
||||||
-- Check if unit in zone and facing the right direction.
|
-- Check if unit in zone and facing the right direction.
|
||||||
local unitinzone = checkme( _targetZone.heading, zone )
|
local unitinzone = checkme( target.heading, zone )
|
||||||
|
|
||||||
-- Player is inside zone.
|
-- Player is inside zone.
|
||||||
if unitinzone then
|
if unitinzone then
|
||||||
@@ -2900,10 +3108,10 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
local _ammo = self:_GetAmmo( _unitName )
|
local _ammo = self:_GetAmmo( _unitName )
|
||||||
|
|
||||||
-- Init strafe status for this player.
|
-- Init strafe status for this player.
|
||||||
self.strafeStatus[_unitID] = { hits = 0, zone = _targetZone, time = 1, ammo = _ammo, pastfoulline = false }
|
self.strafeStatus[_unitID] = { hits = 0, zone = target, time = 1, ammo = _ammo, pastfoulline = false }
|
||||||
|
|
||||||
-- Rolling in!
|
-- Rolling in!
|
||||||
local _msg = string.format( "%s, rolling in on strafe pit %s.", self:_myname( _unitName ), _targetZone.name )
|
local _msg = string.format( "%s, rolling in on strafe pit %s.", self:_myname( _unitName ), target.name )
|
||||||
|
|
||||||
if self.rangecontrol then
|
if self.rangecontrol then
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath )
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath )
|
||||||
@@ -2912,6 +3120,9 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup( _unit, _msg, 10, true )
|
self:_DisplayMessageToGroup( _unit, _msg, 10, true )
|
||||||
|
|
||||||
|
-- Trigger event that player is rolling in.
|
||||||
|
self:RollingIn(playerData, target)
|
||||||
|
|
||||||
-- We found our player. Skip remaining checks.
|
-- We found our player. Skip remaining checks.
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -2959,7 +3170,8 @@ function RANGE:_AddF10Commands( _unitName )
|
|||||||
-- MISSION LEVEL --
|
-- MISSION LEVEL --
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
_rangePath = missionCommands.addSubMenuForGroup( _gid, self.rangename, RANGE.MenuF10Root )
|
-- _rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10Root)
|
||||||
|
_rangePath = MENU_GROUP:New( group, "On the Range" )
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -2969,54 +3181,57 @@ function RANGE:_AddF10Commands( _unitName )
|
|||||||
|
|
||||||
-- Main F10 menu: F10/On the Range/<Range Name>/
|
-- Main F10 menu: F10/On the Range/<Range Name>/
|
||||||
if RANGE.MenuF10[_gid] == nil then
|
if RANGE.MenuF10[_gid] == nil then
|
||||||
RANGE.MenuF10[_gid] = missionCommands.addSubMenuForGroup( _gid, "On the Range" )
|
-- RANGE.MenuF10[_gid]=missionCommands.addSubMenuForGroup(_gid, "On the Range")
|
||||||
|
RANGE.MenuF10[_gid] = MENU_GROUP:New( group, "On the Range" )
|
||||||
end
|
end
|
||||||
_rangePath = missionCommands.addSubMenuForGroup( _gid, self.rangename, RANGE.MenuF10[_gid] )
|
-- _rangePath = missionCommands.addSubMenuForGroup(_gid, self.rangename, RANGE.MenuF10[_gid])
|
||||||
|
_rangePath = MENU_GROUP:New( group, self.rangename, RANGE.MenuF10[_gid] )
|
||||||
end
|
end
|
||||||
|
|
||||||
local _statsPath = missionCommands.addSubMenuForGroup( _gid, "Statistics", _rangePath )
|
local _statsPath = MENU_GROUP:New( group, "Statistics", _rangePath )
|
||||||
local _markPath = missionCommands.addSubMenuForGroup( _gid, "Mark Targets", _rangePath )
|
local _markPath = MENU_GROUP:New( group, "Mark Targets", _rangePath )
|
||||||
local _settingsPath = missionCommands.addSubMenuForGroup( _gid, "My Settings", _rangePath )
|
local _settingsPath = MENU_GROUP:New( group, "My Settings", _rangePath )
|
||||||
local _infoPath = missionCommands.addSubMenuForGroup( _gid, "Range Info", _rangePath )
|
local _infoPath = MENU_GROUP:New( group, "Range Info", _rangePath )
|
||||||
|
|
||||||
-- F10/On the Range/<Range Name>/My Settings/
|
-- F10/On the Range/<Range Name>/My Settings/
|
||||||
local _mysmokePath = missionCommands.addSubMenuForGroup( _gid, "Smoke Color", _settingsPath )
|
local _mysmokePath = MENU_GROUP:New( group, "Smoke Color", _settingsPath )
|
||||||
local _myflarePath = missionCommands.addSubMenuForGroup( _gid, "Flare Color", _settingsPath )
|
local _myflarePath = MENU_GROUP:New( group, "Flare Color", _settingsPath )
|
||||||
|
|
||||||
-- F10/On the Range/<Range Name>/Mark Targets/
|
-- F10/On the Range/<Range Name>/Mark Targets/
|
||||||
missionCommands.addCommandForGroup( _gid, "Mark On Map", _markPath, self._MarkTargetsOnMap, self, _unitName )
|
local _MoMap = MENU_GROUP_COMMAND:New( group, "Mark On Map", _markPath, self._MarkTargetsOnMap, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Illuminate Range", _markPath, self._IlluminateBombTargets, self, _unitName )
|
local _IllRng = MENU_GROUP_COMMAND:New( group, "Illuminate Range", _markPath, self._IlluminateBombTargets, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Smoke Strafe Pits", _markPath, self._SmokeStrafeTargetBoxes, self, _unitName )
|
local _SSpit = MENU_GROUP_COMMAND:New( group, "Smoke Strafe Pits", _markPath, self._SmokeStrafeTargetBoxes, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Smoke Strafe Tgts", _markPath, self._SmokeStrafeTargets, self, _unitName )
|
local _SStgts = MENU_GROUP_COMMAND:New( group, "Smoke Strafe Tgts", _markPath, self._SmokeStrafeTargets, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Smoke Bomb Tgts", _markPath, self._SmokeBombTargets, self, _unitName )
|
local _SBtgts = MENU_GROUP_COMMAND:New( group, "Smoke Bomb Tgts", _markPath, self._SmokeBombTargets, self, _unitName )
|
||||||
-- F10/On the Range/<Range Name>/Stats/
|
-- F10/On the Range/<Range Name>/Stats/
|
||||||
missionCommands.addCommandForGroup( _gid, "All Strafe Results", _statsPath, self._DisplayStrafePitResults, self, _unitName )
|
local _AllSR = MENU_GROUP_COMMAND:New( group, "All Strafe Results", _statsPath, self._DisplayStrafePitResults, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "All Bombing Results", _statsPath, self._DisplayBombingResults, self, _unitName )
|
local _AllBR = MENU_GROUP_COMMAND:New( group, "All Bombing Results", _statsPath, self._DisplayBombingResults, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "My Strafe Results", _statsPath, self._DisplayMyStrafePitResults, self, _unitName )
|
local _MySR = MENU_GROUP_COMMAND:New( group, "My Strafe Results", _statsPath, self._DisplayMyStrafePitResults, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "My Bomb Results", _statsPath, self._DisplayMyBombingResults, self, _unitName )
|
local _MyBR = MENU_GROUP_COMMAND:New( group, "My Bomb Results", _statsPath, self._DisplayMyBombingResults, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Reset All Stats", _statsPath, self._ResetRangeStats, self, _unitName )
|
local _ResetST = MENU_GROUP_COMMAND:New( group, "Reset All Stats", _statsPath, self._ResetRangeStats, self, _unitName )
|
||||||
-- F10/On the Range/<Range Name>/My Settings/Smoke Color/
|
-- F10/On the Range/<Range Name>/My Settings/Smoke Color/
|
||||||
missionCommands.addCommandForGroup( _gid, "Blue Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Blue )
|
local _BlueSM = MENU_GROUP_COMMAND:New( group, "Blue Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Blue )
|
||||||
missionCommands.addCommandForGroup( _gid, "Green Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Green )
|
local _GrSM = MENU_GROUP_COMMAND:New( group, "Green Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Green )
|
||||||
missionCommands.addCommandForGroup( _gid, "Orange Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Orange )
|
local _OrSM = MENU_GROUP_COMMAND:New( group, "Orange Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Orange )
|
||||||
missionCommands.addCommandForGroup( _gid, "Red Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Red )
|
local _ReSM = MENU_GROUP_COMMAND:New( group, "Red Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.Red )
|
||||||
missionCommands.addCommandForGroup( _gid, "White Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.White )
|
local _WhSm = MENU_GROUP_COMMAND:New( group, "White Smoke", _mysmokePath, self._playersmokecolor, self, _unitName, SMOKECOLOR.White )
|
||||||
-- F10/On the Range/<Range Name>/My Settings/Flare Color/
|
-- F10/On the Range/<Range Name>/My Settings/Flare Color/
|
||||||
missionCommands.addCommandForGroup( _gid, "Green Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Green )
|
local _GrFl = MENU_GROUP_COMMAND:New( group, "Green Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Green )
|
||||||
missionCommands.addCommandForGroup( _gid, "Red Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Red )
|
local _ReFl = MENU_GROUP_COMMAND:New( group, "Red Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Red )
|
||||||
missionCommands.addCommandForGroup( _gid, "White Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.White )
|
local _WhFl = MENU_GROUP_COMMAND:New( group, "White Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.White )
|
||||||
missionCommands.addCommandForGroup( _gid, "Yellow Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Yellow )
|
local _YeFl = MENU_GROUP_COMMAND:New( group, "Yellow Flares", _myflarePath, self._playerflarecolor, self, _unitName, FLARECOLOR.Yellow )
|
||||||
-- F10/On the Range/<Range Name>/My Settings/
|
-- F10/On the Range/<Range Name>/My Settings/
|
||||||
missionCommands.addCommandForGroup( _gid, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName )
|
local _SmDe = MENU_GROUP_COMMAND:New( group, "Smoke Delay On/Off", _settingsPath, self._SmokeBombDelayOnOff, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName )
|
local _SmIm = MENU_GROUP_COMMAND:New( group, "Smoke Impact On/Off", _settingsPath, self._SmokeBombImpactOnOff, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName )
|
local _FlHi = MENU_GROUP_COMMAND:New( group, "Flare Hits On/Off", _settingsPath, self._FlareDirectHitsOnOff, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "All Messages On/Off", _settingsPath, self._MessagesToPlayerOnOff, self, _unitName )
|
local _AlMeA = MENU_GROUP_COMMAND:New( group, "All Messages On/Off", _settingsPath, self._MessagesToPlayerOnOff, self, _unitName )
|
||||||
|
local _TrpSh = MENU_GROUP_COMMAND:New( group, "Targetsheet On/Off", _settingsPath, self._TargetsheetOnOff, self, _unitName )
|
||||||
|
|
||||||
-- F10/On the Range/<Range Name>/Range Information
|
-- F10/On the Range/<Range Name>/Range Information
|
||||||
missionCommands.addCommandForGroup( _gid, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName )
|
local _WeIn = MENU_GROUP_COMMAND:New( group, "General Info", _infoPath, self._DisplayRangeInfo, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName )
|
local _WeRe = MENU_GROUP_COMMAND:New( group, "Weather Report", _infoPath, self._DisplayRangeWeather, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Bombing Targets", _infoPath, self._DisplayBombTargets, self, _unitName )
|
local _BoTgtgs = MENU_GROUP_COMMAND:New( group, "Bombing Targets", _infoPath, self._DisplayBombTargets, self, _unitName )
|
||||||
missionCommands.addCommandForGroup( _gid, "Strafe Pits", _infoPath, self._DisplayStrafePits, self, _unitName )
|
local _StrPits = MENU_GROUP_COMMAND:New( group, "Strafe Pits", _infoPath, self._DisplayStrafePits, self, _unitName ):Refresh()
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E( self.id .. "Could not find group or group ID in AddF10Menu() function. Unit name: " .. _unitName )
|
self:E( self.id .. "Could not find group or group ID in AddF10Menu() function. Unit name: " .. _unitName )
|
||||||
@@ -3031,7 +3246,7 @@ end
|
|||||||
-- Helper Functions
|
-- Helper Functions
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- Get the coordinate of a Bomb target.
|
--- Get the number of shells a unit currently has.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #RANGE.BombTarget target Bomb target data.
|
-- @param #RANGE.BombTarget target Bomb target data.
|
||||||
-- @return Core.Point#COORDINATE Target coordinate.
|
-- @return Core.Point#COORDINATE Target coordinate.
|
||||||
@@ -3292,7 +3507,7 @@ function RANGE:_SmokeBombImpactOnOff( unitname )
|
|||||||
self.PlayerSettings[playername].smokebombimpact = false
|
self.PlayerSettings[playername].smokebombimpact = false
|
||||||
text = string.format( "%s, %s, smoking impact points of bombs is now OFF.", self.rangename, playername )
|
text = string.format( "%s, %s, smoking impact points of bombs is now OFF.", self.rangename, playername )
|
||||||
else
|
else
|
||||||
self.PlayerSettigs[playername].smokebombimpact = true
|
self.PlayerSettings[playername].smokebombimpact = true
|
||||||
text = string.format( "%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername )
|
text = string.format( "%s, %s, smoking impact points of bombs is now ON.", self.rangename, playername )
|
||||||
end
|
end
|
||||||
self:_DisplayMessageToGroup( unit, text, 5, false, true )
|
self:_DisplayMessageToGroup( unit, text, 5, false, true )
|
||||||
@@ -3313,7 +3528,7 @@ function RANGE:_SmokeBombDelayOnOff( unitname )
|
|||||||
self.PlayerSettings[playername].delaysmoke = false
|
self.PlayerSettings[playername].delaysmoke = false
|
||||||
text = string.format( "%s, %s, delayed smoke of bombs is now OFF.", self.rangename, playername )
|
text = string.format( "%s, %s, delayed smoke of bombs is now OFF.", self.rangename, playername )
|
||||||
else
|
else
|
||||||
self.PlayerSettigs[playername].delaysmoke = true
|
self.PlayerSettings[playername].delaysmoke = true
|
||||||
text = string.format( "%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername )
|
text = string.format( "%s, %s, delayed smoke of bombs is now ON.", self.rangename, playername )
|
||||||
end
|
end
|
||||||
self:_DisplayMessageToGroup( unit, text, 5, false, true )
|
self:_DisplayMessageToGroup( unit, text, 5, false, true )
|
||||||
@@ -3341,6 +3556,49 @@ function RANGE:_MessagesToPlayerOnOff( unitname )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Targetsheet saves if player on or off.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string _unitname Name of the player unit.
|
||||||
|
function RANGE:_TargetsheetOnOff( _unitname )
|
||||||
|
self:F2( _unitname )
|
||||||
|
|
||||||
|
-- Get player unit and player name.
|
||||||
|
local unit, playername = self:_GetPlayerUnitAndName( _unitname )
|
||||||
|
|
||||||
|
-- Check if we have a player.
|
||||||
|
if unit and playername then
|
||||||
|
|
||||||
|
-- Player data.
|
||||||
|
local playerData = self.PlayerSettings[playername] -- #RANGE.PlayerData
|
||||||
|
|
||||||
|
if playerData then
|
||||||
|
|
||||||
|
-- Check if option is enabled at all.
|
||||||
|
local text = ""
|
||||||
|
if self.targetsheet then
|
||||||
|
|
||||||
|
-- Invert current setting.
|
||||||
|
playerData.targeton = not playerData.targeton
|
||||||
|
|
||||||
|
-- Inform player.
|
||||||
|
if playerData and playerData.targeton == true then
|
||||||
|
text = string.format( "roger, your targetsheets are now SAVED." )
|
||||||
|
else
|
||||||
|
text = string.format( "affirm, your targetsheets are NOT SAVED." )
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
text = "negative, target sheet data recorder is broken on this range."
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Message to player.
|
||||||
|
-- self:MessageToPlayer(playerData, text, nil, playerData.name, 5)
|
||||||
|
self:_DisplayMessageToGroup( unit, text, 5, false, false )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Toggle status of flaring direct hits of range targets.
|
--- Toggle status of flaring direct hits of range targets.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string unitname Name of the player unit.
|
-- @param #string unitname Name of the player unit.
|
||||||
@@ -3507,7 +3765,7 @@ end
|
|||||||
--- Checks if a static object with a certain name exists. It also added it to the MOOSE data base, if it is not already in there.
|
--- Checks if a static object with a certain name exists. It also added it to the MOOSE data base, if it is not already in there.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string name Name of the potential static object.
|
-- @param #string name Name of the potential static object.
|
||||||
-- @return #boolean Returns true if a static with this name exists. Returns false if a unit with this name exists. Returns nil if neither unit or static exist.
|
-- @return #boolean Returns true if a static with this name exists. Retruns false if a unit with this name exists. Returns nil if neither unit or static exist.
|
||||||
function RANGE:_CheckStatic( name )
|
function RANGE:_CheckStatic( name )
|
||||||
self:F2( name )
|
self:F2( name )
|
||||||
|
|
||||||
@@ -3601,11 +3859,9 @@ function RANGE:_myname( unitname )
|
|||||||
|
|
||||||
local unit = UNIT:FindByName( unitname )
|
local unit = UNIT:FindByName( unitname )
|
||||||
local pname = unit:GetPlayerName()
|
local pname = unit:GetPlayerName()
|
||||||
|
|
||||||
-- TODO: Either remove these leftovers, or implement them.
|
|
||||||
-- local csign = unit:GetCallsign()
|
-- local csign = unit:GetCallsign()
|
||||||
-- return string.format("%s (%s)", csign, pname)
|
|
||||||
|
|
||||||
|
-- return string.format("%s (%s)", csign, pname)
|
||||||
return string.format( "%s", pname )
|
return string.format( "%s", pname )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
--
|
--
|
||||||
-- * Upload scoring to a database or a BI tool to publish the scoring results to the player community.
|
-- * Upload scoring to a database or a BI tool to publish the scoring results to the player community.
|
||||||
-- * Upload scoring in an (online) Excel like tool, using pivot tables and pivot charts to show mission results.
|
-- * Upload scoring in an (online) Excel like tool, using pivot tables and pivot charts to show mission results.
|
||||||
-- * Share scoring amoung players after the mission to discuss mission results.
|
-- * Share scoring among players after the mission to discuss mission results.
|
||||||
--
|
--
|
||||||
-- Scores can be **reported**. **Menu options** are automatically added to **each player group** when a player joins a client slot or a CA unit.
|
-- Scores can be **reported**. **Menu options** are automatically added to **each player group** when a player joins a client slot or a CA unit.
|
||||||
-- Use the radio menu F10 to consult the scores while running the mission.
|
-- Use the radio menu F10 to consult the scores while running the mission.
|
||||||
@@ -88,7 +88,6 @@
|
|||||||
-- @module Functional.Scoring
|
-- @module Functional.Scoring
|
||||||
-- @image Scoring.JPG
|
-- @image Scoring.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type SCORING
|
--- @type SCORING
|
||||||
-- @field Players A collection of the current players that have joined the game.
|
-- @field Players A collection of the current players that have joined the game.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
@@ -99,7 +98,6 @@
|
|||||||
--
|
--
|
||||||
-- local Scoring = SCORING:New( "Scoring File" )
|
-- local Scoring = SCORING:New( "Scoring File" )
|
||||||
--
|
--
|
||||||
--
|
|
||||||
-- # Set the destroy score or penalty scale:
|
-- # Set the destroy score or penalty scale:
|
||||||
--
|
--
|
||||||
-- Score scales can be set for scores granted when enemies or friendlies are destroyed.
|
-- Score scales can be set for scores granted when enemies or friendlies are destroyed.
|
||||||
@@ -147,11 +145,11 @@
|
|||||||
--
|
--
|
||||||
-- # (Decommissioned) Configure fratricide level.
|
-- # (Decommissioned) Configure fratricide level.
|
||||||
--
|
--
|
||||||
-- **This functionality is decomissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**.
|
-- **This functionality is decommissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**.
|
||||||
--
|
--
|
||||||
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
|
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
|
||||||
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
|
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
|
||||||
-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score.
|
-- By default, the fratricide level is the default penalty multiplier * 2 for the penalty score.
|
||||||
--
|
--
|
||||||
-- # Penalty score when a player changes the coalition.
|
-- # Penalty score when a player changes the coalition.
|
||||||
--
|
--
|
||||||
@@ -190,8 +188,8 @@
|
|||||||
--
|
--
|
||||||
-- --Sanitize Mission Scripting environment
|
-- --Sanitize Mission Scripting environment
|
||||||
-- --This makes unavailable some unsecure functions.
|
-- --This makes unavailable some unsecure functions.
|
||||||
-- --Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
|
-- --Mission downloaded from server to client may contain potentially harmful lua code that may use these functions.
|
||||||
-- --You can remove the code below and make availble these functions at your own risk.
|
-- --You can remove the code below and make available these functions at your own risk.
|
||||||
--
|
--
|
||||||
-- The MOOSE designer cannot take any responsibility of any damage inflicted as a result of the de-sanitization.
|
-- The MOOSE designer cannot take any responsibility of any damage inflicted as a result of the de-sanitization.
|
||||||
-- That being said, I hope that the SCORING class provides you with a great add-on to score your squad mates achievements.
|
-- That being said, I hope that the SCORING class provides you with a great add-on to score your squad mates achievements.
|
||||||
@@ -229,14 +227,12 @@ SCORING = {
|
|||||||
Players = {},
|
Players = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
local _SCORINGCoalition =
|
local _SCORINGCoalition = {
|
||||||
{
|
|
||||||
[1] = "Red",
|
[1] = "Red",
|
||||||
[2] = "Blue",
|
[2] = "Blue",
|
||||||
}
|
}
|
||||||
|
|
||||||
local _SCORINGCategory =
|
local _SCORINGCategory = {
|
||||||
{
|
|
||||||
[Unit.Category.AIRPLANE] = "Plane",
|
[Unit.Category.AIRPLANE] = "Plane",
|
||||||
[Unit.Category.HELICOPTER] = "Helicopter",
|
[Unit.Category.HELICOPTER] = "Helicopter",
|
||||||
[Unit.Category.GROUND_UNIT] = "Vehicle",
|
[Unit.Category.GROUND_UNIT] = "Vehicle",
|
||||||
@@ -264,7 +260,6 @@ function SCORING:New( GameName )
|
|||||||
error( "A game name must be given to register the scoring results" )
|
error( "A game name must be given to register the scoring results" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Additional Object scores
|
-- Additional Object scores
|
||||||
self.ScoringObjects = {}
|
self.ScoringObjects = {}
|
||||||
|
|
||||||
@@ -284,9 +279,11 @@ function SCORING:New( GameName )
|
|||||||
|
|
||||||
-- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked).
|
-- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked).
|
||||||
self:SetFratricide( self.ScaleDestroyPenalty * 3 )
|
self:SetFratricide( self.ScaleDestroyPenalty * 3 )
|
||||||
|
self.penaltyonfratricide = true
|
||||||
|
|
||||||
-- Default penalty when a player changes coalition.
|
-- Default penalty when a player changes coalition.
|
||||||
self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty )
|
self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty )
|
||||||
|
self.penaltyoncoalitionchange = true
|
||||||
|
|
||||||
self:SetDisplayMessagePrefix()
|
self:SetDisplayMessagePrefix()
|
||||||
|
|
||||||
@@ -301,15 +298,12 @@ function SCORING:New( GameName )
|
|||||||
-- During mission startup, especially for single player,
|
-- During mission startup, especially for single player,
|
||||||
-- iterate the database for the player that has joined, and add him to the scoring, and set the menu.
|
-- iterate the database for the player that has joined, and add him to the scoring, and set the menu.
|
||||||
-- But this can only be started one second after the mission has started, so i need to schedule this ...
|
-- But this can only be started one second after the mission has started, so i need to schedule this ...
|
||||||
self.ScoringPlayerScan = BASE:ScheduleOnce( 1,
|
self.ScoringPlayerScan = BASE:ScheduleOnce( 1, function()
|
||||||
function()
|
|
||||||
for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do
|
for PlayerName, PlayerUnit in pairs( _DATABASE:GetPlayerUnits() ) do
|
||||||
self:_AddPlayerFromUnit( PlayerUnit )
|
self:_AddPlayerFromUnit( PlayerUnit )
|
||||||
self:SetScoringMenu( PlayerUnit:GetGroup() )
|
self:SetScoringMenu( PlayerUnit:GetGroup() )
|
||||||
end
|
end
|
||||||
end
|
end )
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
-- Create the CSV file.
|
-- Create the CSV file.
|
||||||
self:OpenCSV( GameName )
|
self:OpenCSV( GameName )
|
||||||
@@ -327,7 +321,6 @@ function SCORING:SetDisplayMessagePrefix( DisplayMessagePrefix )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the scale for scoring valid destroys (enemy destroys).
|
--- Set the scale for scoring valid destroys (enemy destroys).
|
||||||
-- A default calculated score is a value between 1 and 10.
|
-- A default calculated score is a value between 1 and 10.
|
||||||
-- The scale magnifies the scores given to the players.
|
-- The scale magnifies the scores given to the players.
|
||||||
@@ -409,7 +402,6 @@ function SCORING:RemoveStaticScore( ScoreStatic )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Specify a special additional score for a @{Wrapper.Group}.
|
--- Specify a special additional score for a @{Wrapper.Group}.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Group#GROUP ScoreGroup The @{Wrapper.Group} for which each @{Wrapper.Unit} a Score is given.
|
-- @param Wrapper.Group#GROUP ScoreGroup The @{Wrapper.Group} for which each @{Wrapper.Unit} a Score is given.
|
||||||
@@ -462,7 +454,6 @@ function SCORING:RemoveZoneScore( ScoreZone )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Configure to send messages after a target has been hit.
|
--- Configure to send messages after a target has been hit.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #boolean OnOff If true is given, the messages are sent.
|
-- @param #boolean OnOff If true is given, the messages are sent.
|
||||||
@@ -569,10 +560,9 @@ function SCORING:IfMessagesToCoalition()
|
|||||||
return self.MessagesAudience == 2
|
return self.MessagesAudience == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
|
--- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
|
||||||
-- Use this method to define the level when a player gets kicked.
|
-- Use this method to define the level when a player gets kicked.
|
||||||
-- By default, the fratricide level is the default penalty mutiplier * 2 for the penalty score.
|
-- By default, the fratricide level is the default penalty multiplier * 2 for the penalty score.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #number Fratricide The amount of maximum penalty that may be inflicted by a friendly player before he gets kicked.
|
-- @param #number Fratricide The amount of maximum penalty that may be inflicted by a friendly player before he gets kicked.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
@@ -582,6 +572,23 @@ function SCORING:SetFratricide( Fratricide )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Decide if fratricide is leading to penalties (true) or not (false)
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param #boolean OnOff Switch for Fratricide
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:SwitchFratricide( OnOff )
|
||||||
|
self.penaltyonfratricide = OnOff
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Decide if a change of coalition is leading to penalties (true) or not (false)
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param #boolean OnOff Switch for Coalition Changes.
|
||||||
|
-- @return #SCORING
|
||||||
|
function SCORING:SwitchTreason( OnOff )
|
||||||
|
self.penaltyoncoalitionchange = OnOff
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- When a player changes the coalition, he can receive a penalty score.
|
--- When a player changes the coalition, he can receive a penalty score.
|
||||||
-- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition.
|
-- Use the method @{#SCORING.SetCoalitionChangePenalty}() to define the penalty when a player changes coalition.
|
||||||
@@ -595,7 +602,6 @@ function SCORING:SetCoalitionChangePenalty( CoalitionChangePenalty )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Sets the scoring menu.
|
--- Sets the scoring menu.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
@@ -608,7 +614,6 @@ function SCORING:SetScoringMenu( ScoringGroup )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Add a new player entering a Unit.
|
--- Add a new player entering a Unit.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Unit#UNIT UnitData
|
-- @param Wrapper.Unit#UNIT UnitData
|
||||||
@@ -647,15 +652,15 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
if not self.Players[PlayerName].UnitCoalition then
|
if not self.Players[PlayerName].UnitCoalition then
|
||||||
self.Players[PlayerName].UnitCoalition = UnitCoalition
|
self.Players[PlayerName].UnitCoalition = UnitCoalition
|
||||||
else
|
else
|
||||||
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then
|
-- TODO: switch for coalition changes, make penalty alterable
|
||||||
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50
|
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition and self.penaltyoncoalitionchange then
|
||||||
|
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + self.CoalitionChangePenalty or 50
|
||||||
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). " ..
|
||||||
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.",
|
self.CoalitionChangePenalty .. "Penalty points added.",
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
):ToAll()
|
:ToAll()
|
||||||
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
|
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -1 * self.CoalitionChangePenalty, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
||||||
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -667,29 +672,25 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
|
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
|
||||||
self.Players[PlayerName].ThreatType = UnitThreatType
|
self.Players[PlayerName].ThreatType = UnitThreatType
|
||||||
|
|
||||||
-- TODO: DCS bug concerning Units with skill level client don't get destroyed in multi player. This logic is deactivated until this bug gets fixed.
|
-- TODO: make fratricide switchable
|
||||||
--[[
|
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 and self.penaltyonfratricide then
|
||||||
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then
|
|
||||||
if self.Players[PlayerName].PenaltyWarning < 1 then
|
if self.Players[PlayerName].PenaltyWarning < 1 then
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
):ToAll()
|
:ToAll()
|
||||||
self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1
|
self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.Players[PlayerName].Penalty > self.Fratricide then
|
if self.Players[PlayerName].Penalty > self.Fratricide and self.penaltyonfratricide then
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!",
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!",
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
):ToAll()
|
:ToAll()
|
||||||
UnitData:GetGroup():Destroy()
|
UnitData:GetGroup():Destroy()
|
||||||
end
|
end
|
||||||
--]]
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Add a goal score for a player.
|
--- Add a goal score for a player.
|
||||||
-- The method takes the Player name for which the Goal score needs to be set.
|
-- The method takes the Player name for which the Goal score needs to be set.
|
||||||
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
||||||
@@ -712,14 +713,14 @@ function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score )
|
|||||||
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
||||||
PlayerData.Score = PlayerData.Score + Score
|
PlayerData.Score = PlayerData.Score + Score
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll()
|
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
|
||||||
|
MESSAGE.Type.Information )
|
||||||
|
:ToAll()
|
||||||
|
|
||||||
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
|
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Add a goal score for a player.
|
--- Add a goal score for a player.
|
||||||
-- The method takes the PlayerUnit for which the Goal score needs to be set.
|
-- The method takes the PlayerUnit for which the Goal score needs to be set.
|
||||||
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
||||||
@@ -744,13 +745,14 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
|
|||||||
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
||||||
PlayerData.Score = PlayerData.Score + Score
|
PlayerData.Score = PlayerData.Score + Score
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll()
|
MESSAGE:NewType( self.DisplayMessagePrefix .. Text,
|
||||||
|
MESSAGE.Type.Information )
|
||||||
|
:ToAll()
|
||||||
|
|
||||||
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() )
|
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Registers Scores the players completing a Mission Task.
|
--- Registers Scores the players completing a Mission Task.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Tasking.Mission#MISSION Mission
|
-- @param Tasking.Mission#MISSION Mission
|
||||||
@@ -780,7 +782,9 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
|
|||||||
PlayerData.Score = self.Players[PlayerName].Score + Score
|
PlayerData.Score = self.Players[PlayerName].Score + Score
|
||||||
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll()
|
MESSAGE:NewType( self.DisplayMessagePrefix .. Mission:GetText() .. " : " .. Text .. " Score: " .. Score,
|
||||||
|
MESSAGE.Type.Information )
|
||||||
|
:ToAll()
|
||||||
|
|
||||||
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
|
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
|
||||||
end
|
end
|
||||||
@@ -841,17 +845,15 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
|
|||||||
PlayerData.Score = PlayerData.Score + Score
|
PlayerData.Score = PlayerData.Score + Score
|
||||||
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
|
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in " .. Mission:GetText() .. ". " .. Score .. " mission score!",
|
||||||
Score .. " mission score!",
|
MESSAGE.Type.Information )
|
||||||
MESSAGE.Type.Information ):ToAll()
|
:ToAll()
|
||||||
|
|
||||||
self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Handles the OnPlayerEnterUnit event for the scoring.
|
--- Handles the OnPlayerEnterUnit event for the scoring.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
@@ -891,7 +893,6 @@ function SCORING:OnEventPlayerLeaveUnit( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Handles the OnHit event for the scoring.
|
--- Handles the OnHit event for the scoring.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Core.Event#EVENTDATA Event
|
-- @param Core.Event#EVENTDATA Event
|
||||||
@@ -949,7 +950,6 @@ function SCORING:_EventOnHit( Event )
|
|||||||
self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType, InitUnitCoalition, InitUnitCategory, InitUnitType } )
|
self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType, InitUnitCoalition, InitUnitCategory, InitUnitType } )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if Event.TgtDCSUnit then
|
if Event.TgtDCSUnit then
|
||||||
|
|
||||||
TargetUnit = Event.TgtDCSUnit
|
TargetUnit = Event.TgtDCSUnit
|
||||||
@@ -1023,21 +1023,15 @@ function SCORING:_EventOnHit( Event )
|
|||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
|
||||||
|
|
||||||
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " ..
|
|
||||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
|
||||||
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update
|
MESSAGE.Type.Update )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " ..
|
|
||||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
|
||||||
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update
|
MESSAGE.Type.Update )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
end
|
end
|
||||||
@@ -1047,33 +1041,26 @@ function SCORING:_EventOnHit( Event )
|
|||||||
PlayerHit.Score = PlayerHit.Score + 1
|
PlayerHit.Score = PlayerHit.Score + 1
|
||||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||||
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " ..
|
|
||||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
|
||||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update
|
MESSAGE.Type.Update )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " ..
|
|
||||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
|
||||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update
|
MESSAGE.Type.Update )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
end
|
end
|
||||||
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
end
|
end
|
||||||
else -- A scenery object was hit.
|
else -- A scenery object was hit.
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
|
MESSAGE.Type.Update )
|
||||||
MESSAGE.Type.Update
|
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( InitPlayerName, "", "HIT_SCORE", 1, 0, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType )
|
self:ScoreCSV( InitPlayerName, "", "HIT_SCORE", 1, 0, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1125,40 +1112,35 @@ function SCORING:_EventOnHit( Event )
|
|||||||
if InitCoalition then -- A coalition object was hit, probably a static.
|
if InitCoalition then -- A coalition object was hit, probably a static.
|
||||||
if InitCoalition == TargetCoalition then
|
if InitCoalition == TargetCoalition then
|
||||||
-- TODO: Penalty according scale
|
-- TODO: Penalty according scale
|
||||||
Player.Penalty = Player.Penalty + 10
|
Player.Penalty = Player.Penalty + 10 -- * self.ScaleDestroyPenalty
|
||||||
PlayerHit.Penalty = PlayerHit.Penalty + 10
|
PlayerHit.Penalty = PlayerHit.Penalty + 10 -- * self.ScaleDestroyPenalty
|
||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
|
||||||
|
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
|
|
||||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
|
||||||
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update
|
MESSAGE.Type.Update )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
else
|
else
|
||||||
Player.Score = Player.Score + 1
|
Player.Score = Player.Score + 1
|
||||||
PlayerHit.Score = PlayerHit.Score + 1
|
PlayerHit.Score = PlayerHit.Score + 1
|
||||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " ..
|
|
||||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
|
||||||
"Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty,
|
"Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Update
|
MESSAGE.Type.Update )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
end
|
end
|
||||||
else -- A scenery object was hit.
|
else -- A scenery object was hit.
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
|
MESSAGE.Type.Update )
|
||||||
MESSAGE.Type.Update
|
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, "", "HIT_SCORE", 1, 0, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, "", "Scenery", TargetUnitType )
|
self:ScoreCSV( Event.WeaponPlayerName, "", "HIT_SCORE", 1, 0, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, "", "Scenery", TargetUnitType )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1252,27 +1234,21 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
|
TargetDestroy.PenaltyDestroy = TargetDestroy.PenaltyDestroy + 1
|
||||||
|
|
||||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " ..
|
|
||||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
|
||||||
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " ..
|
|
||||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
|
||||||
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
end
|
end
|
||||||
|
|
||||||
Destroyed = true
|
|
||||||
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_PENALTY", 1, ThreatPenalty, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_PENALTY", 1, ThreatPenalty, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
|
Destroyed = true
|
||||||
else
|
else
|
||||||
|
|
||||||
local ThreatLevelTarget = TargetThreatLevel
|
local ThreatLevelTarget = TargetThreatLevel
|
||||||
@@ -1286,39 +1262,33 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
TargetDestroy.Score = TargetDestroy.Score + ThreatScore
|
TargetDestroy.Score = TargetDestroy.Score + ThreatScore
|
||||||
TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1
|
TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1
|
||||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " ..
|
|
||||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
|
||||||
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
else
|
else
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " ..
|
|
||||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
|
||||||
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||||
end
|
end
|
||||||
Destroyed = true
|
|
||||||
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, ThreatScore, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, ThreatScore, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
|
Destroyed = true
|
||||||
|
|
||||||
local UnitName = TargetUnit:GetName()
|
local UnitName = TargetUnit:GetName()
|
||||||
local Score = self.ScoringObjects[UnitName]
|
local Score = self.ScoringObjects[UnitName]
|
||||||
if Score then
|
if Score then
|
||||||
Player.Score = Player.Score + Score
|
Player.Score = Player.Score + Score
|
||||||
TargetDestroy.Score = TargetDestroy.Score + Score
|
TargetDestroy.Score = TargetDestroy.Score + Score
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " ..
|
|
||||||
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty,
|
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty,
|
||||||
MESSAGE.Type.Information
|
MESSAGE.Type.Information )
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
Destroyed = true
|
Destroyed = true
|
||||||
end
|
end
|
||||||
@@ -1331,13 +1301,12 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
||||||
Player.Score = Player.Score + Score
|
Player.Score = Player.Score + Score
|
||||||
TargetDestroy.Score = TargetDestroy.Score + Score
|
TargetDestroy.Score = TargetDestroy.Score + Score
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty,
|
||||||
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " ..
|
|
||||||
"Total: " .. Player.Score - Player.Penalty,
|
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information )
|
||||||
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
|
||||||
|
|
||||||
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
Destroyed = true
|
Destroyed = true
|
||||||
end
|
end
|
||||||
@@ -1353,16 +1322,14 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
if ScoreZone:IsVec2InZone( TargetUnit:GetVec2() ) then
|
||||||
Player.Score = Player.Score + Score
|
Player.Score = Player.Score + Score
|
||||||
TargetDestroy.Score = TargetDestroy.Score + Score
|
TargetDestroy.Score = TargetDestroy.Score + Score
|
||||||
MESSAGE
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
||||||
:NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " .. "Total: " .. Player.Score - Player.Penalty,
|
||||||
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " ..
|
MESSAGE.Type.Information )
|
||||||
"Total: " .. Player.Score - Player.Penalty,
|
|
||||||
MESSAGE.Type.Information
|
|
||||||
)
|
|
||||||
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
|
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
|
||||||
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
|
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
|
||||||
Destroyed = true
|
|
||||||
self:ScoreCSV( PlayerName, "", "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType )
|
self:ScoreCSV( PlayerName, "", "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, "", "Scenery", TargetUnitType )
|
||||||
|
Destroyed = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1378,7 +1345,6 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Produce detailed report of player hit scores.
|
--- Produce detailed report of player hit scores.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #string PlayerName The name of the player.
|
-- @param #string PlayerName The name of the player.
|
||||||
@@ -1431,7 +1397,6 @@ function SCORING:ReportDetailedPlayerHits( PlayerName )
|
|||||||
return ScoreMessage, PlayerScore, PlayerPenalty
|
return ScoreMessage, PlayerScore, PlayerPenalty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Produce detailed report of player destroy scores.
|
--- Produce detailed report of player destroy scores.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #string PlayerName The name of the player.
|
-- @param #string PlayerName The name of the player.
|
||||||
@@ -1597,7 +1562,6 @@ function SCORING:ReportDetailedPlayerMissions( PlayerName )
|
|||||||
return ScoreMessage, PlayerScore, PlayerPenalty
|
return ScoreMessage, PlayerScore, PlayerPenalty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Report Group Score Summary
|
--- Report Group Score Summary
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Group#GROUP PlayerGroup The player group.
|
-- @param Wrapper.Group#GROUP PlayerGroup The player group.
|
||||||
@@ -1637,8 +1601,7 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup )
|
|||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
||||||
|
|
||||||
PlayerMessage =
|
PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
||||||
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
|
||||||
PlayerName,
|
PlayerName,
|
||||||
PlayerScore - PlayerPenalty,
|
PlayerScore - PlayerPenalty,
|
||||||
PlayerScore,
|
PlayerScore,
|
||||||
@@ -1687,10 +1650,9 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
|
|||||||
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
||||||
|
|
||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
||||||
|
|
||||||
PlayerMessage =
|
PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s",
|
||||||
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s",
|
|
||||||
PlayerName,
|
PlayerName,
|
||||||
PlayerScore - PlayerPenalty,
|
PlayerScore - PlayerPenalty,
|
||||||
PlayerScore,
|
PlayerScore,
|
||||||
@@ -1743,10 +1705,9 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
|
|||||||
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
self:F( { ReportMissions, ScoreMissions, PenaltyMissions } )
|
||||||
|
|
||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + ScoreGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
||||||
|
|
||||||
PlayerMessage =
|
PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
||||||
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
|
||||||
PlayerName,
|
PlayerName,
|
||||||
PlayerScore - PlayerPenalty,
|
PlayerScore - PlayerPenalty,
|
||||||
PlayerScore,
|
PlayerScore,
|
||||||
@@ -1758,7 +1719,6 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function SCORING:SecondsToClock( sSeconds )
|
function SCORING:SecondsToClock( sSeconds )
|
||||||
local nSeconds = sSeconds
|
local nSeconds = sSeconds
|
||||||
if nSeconds == 0 then
|
if nSeconds == 0 then
|
||||||
@@ -1793,7 +1753,7 @@ function SCORING:OpenCSV( ScoringCSV )
|
|||||||
error( "Error: Cannot open CSV file in " .. lfs.writedir() )
|
error( "Error: Cannot open CSV file in " .. lfs.writedir() )
|
||||||
end
|
end
|
||||||
|
|
||||||
self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoaltion","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' )
|
self.CSVFile:write( '"GameName","RunTime","Time","PlayerName","TargetPlayerName","ScoreType","PlayerUnitCoalition","PlayerUnitCategory","PlayerUnitType","PlayerUnitName","TargetUnitCoalition","TargetUnitCategory","TargetUnitType","TargetUnitName","Times","Score"\n' )
|
||||||
|
|
||||||
self.RunTime = os.date( "%y-%m-%d_%H-%M-%S" )
|
self.RunTime = os.date( "%y-%m-%d_%H-%M-%S" )
|
||||||
else
|
else
|
||||||
@@ -1805,7 +1765,6 @@ function SCORING:OpenCSV( ScoringCSV )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Registers a score for a player.
|
--- Registers a score for a player.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param #string PlayerName The name of the player.
|
-- @param #string PlayerName The name of the player.
|
||||||
@@ -1888,7 +1847,6 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function SCORING:CloseCSV()
|
function SCORING:CloseCSV()
|
||||||
if lfs and io and os then
|
if lfs and io and os then
|
||||||
self.CSVFile:close()
|
self.CSVFile:close()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
--
|
--
|
||||||
-- ### Authors: **FlightControl**, **applevangelist**
|
-- ### Authors: **FlightControl**, **applevangelist**
|
||||||
--
|
--
|
||||||
-- Last Update: Nov 2021
|
-- Last Update: Feb 2022
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -59,6 +59,7 @@ SEAD = {
|
|||||||
Padding = 10,
|
Padding = 10,
|
||||||
CallBack = nil,
|
CallBack = nil,
|
||||||
UseCallBack = false,
|
UseCallBack = false,
|
||||||
|
debug = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Missile enumerators
|
--- Missile enumerators
|
||||||
@@ -76,6 +77,8 @@ SEAD = {
|
|||||||
["X_25"] = "X_25",
|
["X_25"] = "X_25",
|
||||||
["X_31"] = "X_31",
|
["X_31"] = "X_31",
|
||||||
["Kh25"] = "Kh25",
|
["Kh25"] = "Kh25",
|
||||||
|
["BGM_109"] = "BGM_109",
|
||||||
|
["AGM_154"] = "AGM_154",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Missile enumerators - from DCS ME and Wikipedia
|
--- Missile enumerators - from DCS ME and Wikipedia
|
||||||
@@ -85,7 +88,7 @@ SEAD = {
|
|||||||
["AGM_88"] = { 150, 3},
|
["AGM_88"] = { 150, 3},
|
||||||
["AGM_45"] = { 12, 2},
|
["AGM_45"] = { 12, 2},
|
||||||
["AGM_122"] = { 16.5, 2.3},
|
["AGM_122"] = { 16.5, 2.3},
|
||||||
["AGM_84"] = { 280, 0.85},
|
["AGM_84"] = { 280, 0.8},
|
||||||
["ALARM"] = { 45, 2},
|
["ALARM"] = { 45, 2},
|
||||||
["LD-10"] = { 60, 4},
|
["LD-10"] = { 60, 4},
|
||||||
["X_58"] = { 70, 4},
|
["X_58"] = { 70, 4},
|
||||||
@@ -93,6 +96,8 @@ SEAD = {
|
|||||||
["X_25"] = { 25, 0.76},
|
["X_25"] = { 25, 0.76},
|
||||||
["X_31"] = {150, 3},
|
["X_31"] = {150, 3},
|
||||||
["Kh25"] = {25, 0.8},
|
["Kh25"] = {25, 0.8},
|
||||||
|
["BGM_109"] = {460, 0.705}, --in-game ~465kn
|
||||||
|
["AGM_154"] = {130, 0.61},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
||||||
@@ -108,8 +113,8 @@ SEAD = {
|
|||||||
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
|
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
|
||||||
function SEAD:New( SEADGroupPrefixes, Padding )
|
function SEAD:New( SEADGroupPrefixes, Padding )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, FSM:New() )
|
||||||
self:F( SEADGroupPrefixes )
|
self:T( SEADGroupPrefixes )
|
||||||
|
|
||||||
if type( SEADGroupPrefixes ) == 'table' then
|
if type( SEADGroupPrefixes ) == 'table' then
|
||||||
for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do
|
for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do
|
||||||
@@ -122,14 +127,21 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
|||||||
local padding = Padding or 10
|
local padding = Padding or 10
|
||||||
if padding < 10 then padding = 10 end
|
if padding < 10 then padding = 10 end
|
||||||
self.Padding = padding
|
self.Padding = padding
|
||||||
self.UseEmissionsOnOff = false
|
self.UseEmissionsOnOff = true
|
||||||
|
|
||||||
|
self.debug = false
|
||||||
|
|
||||||
self.CallBack = nil
|
self.CallBack = nil
|
||||||
self.UseCallBack = false
|
self.UseCallBack = false
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
|
self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
|
||||||
|
|
||||||
self:I("*** SEAD - Started Version 0.3.3")
|
-- Start State.
|
||||||
|
self:SetStartState("Running")
|
||||||
|
self:AddTransition("*", "ManageEvasion", "*")
|
||||||
|
self:AddTransition("*", "CalculateHitZone", "*")
|
||||||
|
|
||||||
|
self:I("*** SEAD - Started Version 0.4.3")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -213,7 +225,7 @@ function SEAD:_CheckHarms(WeaponName)
|
|||||||
local hit = false
|
local hit = false
|
||||||
local name = ""
|
local name = ""
|
||||||
for _,_name in pairs (SEAD.Harms) do
|
for _,_name in pairs (SEAD.Harms) do
|
||||||
if string.find(WeaponName,_name,1) then
|
if string.find(WeaponName,_name,1,true) then
|
||||||
hit = true
|
hit = true
|
||||||
name = _name
|
name = _name
|
||||||
break
|
break
|
||||||
@@ -249,47 +261,94 @@ function SEAD:_GetDistance(_point1, _point2)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
--- (Internal) Calculate hit zone of an AGM-88
|
||||||
-- @param #SEAD self
|
-- @param #SEAD self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param #table SEADWeapon DCS.Weapon object
|
||||||
|
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||||
|
-- @param #number height Height when the missile was fired
|
||||||
|
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||||
|
-- @param #string SEADWeaponName Weapon Name
|
||||||
-- @return #SEAD self
|
-- @return #SEAD self
|
||||||
function SEAD:HandleEventShot( EventData )
|
function SEAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup,SEADWeaponName)
|
||||||
self:T( { EventData.id } )
|
self:T("**** Calculating hit zone for " .. (SEADWeaponName or "None"))
|
||||||
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
if SEADWeapon and SEADWeapon:isExist() then
|
||||||
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
--local pos = SEADWeapon:getPoint()
|
||||||
local SEADUnit = EventData.IniDCSUnit
|
|
||||||
local SEADUnitName = EventData.IniDCSUnitName
|
|
||||||
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
|
||||||
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
|
||||||
|
|
||||||
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
-- postion and height
|
||||||
--self:T({ SEADWeapon })
|
local position = SEADWeapon:getPosition()
|
||||||
|
local mheight = height
|
||||||
|
-- heading
|
||||||
|
local wph = math.atan2(position.x.z, position.x.x)
|
||||||
|
if wph < 0 then
|
||||||
|
wph=wph+2*math.pi
|
||||||
|
end
|
||||||
|
wph=math.deg(wph)
|
||||||
|
|
||||||
if self:_CheckHarms(SEADWeaponName) then
|
-- velocity
|
||||||
self:T( '*** SEAD - Weapon Match' )
|
local wpndata = SEAD.HarmData["AGM_88"]
|
||||||
local _targetskill = "Random"
|
if string.find(SEADWeaponName,"154",1) then
|
||||||
|
wpndata = SEAD.HarmData["AGM_154"]
|
||||||
|
end
|
||||||
|
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||||
|
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||||
|
local c2 = (mveloc^2) / 9.81
|
||||||
|
local Ropt = c2 * math.sqrt(c1+1)
|
||||||
|
if height <= 5000 then
|
||||||
|
Ropt = Ropt * 0.72
|
||||||
|
elseif height <= 7500 then
|
||||||
|
Ropt = Ropt * 0.82
|
||||||
|
elseif height <= 10000 then
|
||||||
|
Ropt = Ropt * 0.87
|
||||||
|
elseif height <= 12500 then
|
||||||
|
Ropt = Ropt * 0.98
|
||||||
|
end
|
||||||
|
|
||||||
|
-- look at a couple of zones across the trajectory
|
||||||
|
for n=1,3 do
|
||||||
|
local dist = Ropt - ((n-1)*20000)
|
||||||
|
local predpos= pos0:Translate(dist,wph)
|
||||||
|
if predpos then
|
||||||
|
|
||||||
|
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||||
|
|
||||||
|
if self.debug then
|
||||||
|
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||||
|
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
|
||||||
|
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||||
|
--if tgtcoord and tgtcoord.ClassName == "COORDINATE" then
|
||||||
|
--local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local tgtgrp = seadset:GetRandom()
|
||||||
|
local _targetgroup = nil
|
||||||
local _targetgroupname = "none"
|
local _targetgroupname = "none"
|
||||||
local _target = EventData.Weapon:getTarget() -- Identify target
|
local _targetskill = "Random"
|
||||||
local _targetUnit = UNIT:Find(_target) -- Wrapper.Unit#UNIT
|
if tgtgrp and tgtgrp:IsAlive() then
|
||||||
local _targetgroup = nil -- Wrapper.Group#GROUP
|
_targetgroup = tgtgrp
|
||||||
if _targetUnit and _targetUnit:IsAlive() then
|
_targetgroupname = tgtgrp:GetName() -- group name
|
||||||
_targetgroup = _targetUnit:GetGroup()
|
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||||
_targetgroupname = _targetgroup:GetName() -- group name
|
self:T("*** Found Target = ".. _targetgroupname)
|
||||||
local _targetUnitName = _targetUnit:GetName()
|
self:ManageEvasion(_targetskill,_targetgroup,pos0,"AGM_88",SEADGroup, 20)
|
||||||
_targetUnit:GetSkill()
|
|
||||||
_targetskill = _targetUnit:GetSkill()
|
|
||||||
end
|
end
|
||||||
-- see if we are shot at
|
--end
|
||||||
local SEADGroupFound = false
|
|
||||||
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
|
|
||||||
self:T( _targetgroupname, SEADGroupPrefix )
|
|
||||||
if string.find( _targetgroupname, SEADGroupPrefix, 1, true ) then
|
|
||||||
SEADGroupFound = true
|
|
||||||
self:T( '*** SEAD - Group Match Found' )
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if SEADGroupFound == true then -- yes we are being attacked
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Handle Evasion
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param #string _targetskill
|
||||||
|
-- @param Wrapper.Group#GROUP _targetgroup
|
||||||
|
-- @param Core.Point#COORDINATE SEADPlanePos
|
||||||
|
-- @param #string SEADWeaponName
|
||||||
|
-- @param Wrapper.Group#GROUP SEADGroup Attacker Group
|
||||||
|
-- @param #number timeoffset Offset for tti calc
|
||||||
|
-- @return #SEAD self
|
||||||
|
function SEAD:onafterManageEvasion(From,Event,To,_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup,timeoffset)
|
||||||
|
local timeoffset = timeoffset or 0
|
||||||
if _targetskill == "Random" then -- when skill is random, choose a skill
|
if _targetskill == "Random" then -- when skill is random, choose a skill
|
||||||
local Skills = { "Average", "Good", "High", "Excellent" }
|
local Skills = { "Average", "Good", "High", "Excellent" }
|
||||||
_targetskill = Skills[ math.random(1,4) ]
|
_targetskill = Skills[ math.random(1,4) ]
|
||||||
@@ -313,7 +372,7 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
wpnspeed = math.floor(mach * 340.29)
|
wpnspeed = math.floor(mach * 340.29)
|
||||||
end
|
end
|
||||||
-- time to impact
|
-- time to impact
|
||||||
local _tti = math.floor(_distance / wpnspeed) -- estimated impact time
|
local _tti = math.floor(_distance / wpnspeed) - timeoffset -- estimated impact time
|
||||||
if _distance > 0 then
|
if _distance > 0 then
|
||||||
_distance = math.floor(_distance / 1000) -- km
|
_distance = math.floor(_distance / 1000) -- km
|
||||||
else
|
else
|
||||||
@@ -329,6 +388,7 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
self:T(string.format("*** SEAD - %s Radar Off & Relocating",args[2]))
|
self:T(string.format("*** SEAD - %s Radar Off & Relocating",args[2]))
|
||||||
local grp = args[1] -- Wrapper.Group#GROUP
|
local grp = args[1] -- Wrapper.Group#GROUP
|
||||||
local name = args[2] -- #string Group Name
|
local name = args[2] -- #string Group Name
|
||||||
|
local attacker = args[3] -- Wrapper.Group#GROUP
|
||||||
if self.UseEmissionsOnOff then
|
if self.UseEmissionsOnOff then
|
||||||
grp:EnableEmission(false)
|
grp:EnableEmission(false)
|
||||||
end
|
end
|
||||||
@@ -336,7 +396,7 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
|
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
|
||||||
if self.UseCallBack then
|
if self.UseCallBack then
|
||||||
local object = self.CallBack
|
local object = self.CallBack
|
||||||
object:SeadSuppressionStart(grp,name)
|
object:SeadSuppressionStart(grp,name,attacker)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -347,7 +407,7 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
if self.UseEmissionsOnOff then
|
if self.UseEmissionsOnOff then
|
||||||
grp:EnableEmission(true)
|
grp:EnableEmission(true)
|
||||||
end
|
end
|
||||||
grp:OptionAlarmStateAuto()
|
grp:OptionAlarmStateRed()
|
||||||
grp:OptionEngageRange(self.EngagementRange)
|
grp:OptionEngageRange(self.EngagementRange)
|
||||||
self.SuppressedGroups[name] = false
|
self.SuppressedGroups[name] = false
|
||||||
if self.UseCallBack then
|
if self.UseCallBack then
|
||||||
@@ -359,26 +419,100 @@ function SEAD:HandleEventShot( EventData )
|
|||||||
-- randomize switch-on time
|
-- randomize switch-on time
|
||||||
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
|
local delay = math.random(self.TargetSkill[_targetskill].DelayOn[1], self.TargetSkill[_targetskill].DelayOn[2])
|
||||||
if delay > _tti then delay = delay / 2 end -- speed up
|
if delay > _tti then delay = delay / 2 end -- speed up
|
||||||
if _tti > (3*delay) then delay = (_tti / 2) * 0.9 end -- shot from afar
|
if _tti > 600 then delay = _tti - 90 end -- shot from afar, 600 is default shorad ontime
|
||||||
|
|
||||||
local SuppressionStartTime = timer.getTime() + delay
|
local SuppressionStartTime = timer.getTime() + delay
|
||||||
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
|
local SuppressionEndTime = timer.getTime() + _tti + self.Padding
|
||||||
|
local _targetgroupname = _targetgroup:GetName()
|
||||||
if not self.SuppressedGroups[_targetgroupname] then
|
if not self.SuppressedGroups[_targetgroupname] then
|
||||||
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
|
self:T(string.format("*** SEAD - %s | Parameters TTI %ds | Switch-Off in %ds",_targetgroupname,_tti,delay))
|
||||||
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname},SuppressionStartTime)
|
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname, SEADGroup},SuppressionStartTime)
|
||||||
timer.scheduleFunction(SuppressionStop,{_targetgroup,_targetgroupname},SuppressionEndTime)
|
timer.scheduleFunction(SuppressionStop,{_targetgroup,_targetgroupname},SuppressionEndTime)
|
||||||
self.SuppressedGroups[_targetgroupname] = true
|
self.SuppressedGroups[_targetgroupname] = true
|
||||||
if self.UseCallBack then
|
if self.UseCallBack then
|
||||||
local object = self.CallBack
|
local object = self.CallBack
|
||||||
object:SeadSuppressionPlanned(_targetgroup,_targetgroupname,SuppressionStartTime,SuppressionEndTime)
|
object:SeadSuppressionPlanned(_targetgroup,_targetgroupname,SuppressionStartTime,SuppressionEndTime, SEADGroup)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
||||||
|
-- @param #SEAD self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
-- @return #SEAD self
|
||||||
|
function SEAD:HandleEventShot( EventData )
|
||||||
|
self:T( { EventData.id } )
|
||||||
|
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
||||||
|
local SEADGroup = EventData.IniGroup -- Wrapper.Group#GROUP
|
||||||
|
local SEADPlanePos = SEADPlane:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
local SEADUnit = EventData.IniDCSUnit
|
||||||
|
local SEADUnitName = EventData.IniDCSUnitName
|
||||||
|
local SEADWeapon = EventData.Weapon -- Identify the weapon fired
|
||||||
|
local SEADWeaponName = EventData.WeaponName -- return weapon type
|
||||||
|
|
||||||
|
self:T( "*** SEAD - Missile Launched = " .. SEADWeaponName)
|
||||||
|
--self:T({ SEADWeapon })
|
||||||
|
|
||||||
|
if self:_CheckHarms(SEADWeaponName) then
|
||||||
|
self:T( '*** SEAD - Weapon Match' )
|
||||||
|
local _targetskill = "Random"
|
||||||
|
local _targetgroupname = "none"
|
||||||
|
local _target = EventData.Weapon:getTarget() -- Identify target
|
||||||
|
if not _target or self.debug then -- AGM-88 or 154 w/o target data
|
||||||
|
self:E("***** SEAD - No target data for " .. (SEADWeaponName or "None"))
|
||||||
|
if string.find(SEADWeaponName,"AGM_88",1,true) or string.find(SEADWeaponName,"AGM_154",1,true) then
|
||||||
|
self:I("**** Tracking AGM-88/154 with no target data.")
|
||||||
|
local pos0 = SEADPlane:GetCoordinate()
|
||||||
|
local fheight = SEADPlane:GetHeight()
|
||||||
|
self:__CalculateHitZone(20,SEADWeapon,pos0,fheight,SEADGroup,SEADWeaponName)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
local targetcat = _target:getCategory() -- Identify category
|
||||||
|
local _targetUnit = nil -- Wrapper.Unit#UNIT
|
||||||
|
local _targetgroup = nil -- Wrapper.Group#GROUP
|
||||||
|
self:T(string.format("*** Targetcat = %d",targetcat))
|
||||||
|
if targetcat == Object.Category.UNIT then -- UNIT
|
||||||
|
self:T("*** Target Category UNIT")
|
||||||
|
_targetUnit = UNIT:Find(_target) -- Wrapper.Unit#UNIT
|
||||||
|
if _targetUnit and _targetUnit:IsAlive() then
|
||||||
|
_targetgroup = _targetUnit:GetGroup()
|
||||||
|
_targetgroupname = _targetgroup:GetName() -- group name
|
||||||
|
local _targetUnitName = _targetUnit:GetName()
|
||||||
|
_targetUnit:GetSkill()
|
||||||
|
_targetskill = _targetUnit:GetSkill()
|
||||||
|
end
|
||||||
|
elseif targetcat == Object.Category.STATIC then
|
||||||
|
self:T("*** Target Category STATIC")
|
||||||
|
local seadset = SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterOnce()
|
||||||
|
local targetpoint = _target:getPoint() or {x=0,y=0,z=0}
|
||||||
|
local tgtcoord = COORDINATE:NewFromVec3(targetpoint)
|
||||||
|
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
if tgtgrp and tgtgrp:IsAlive() then
|
||||||
|
_targetgroup = tgtgrp
|
||||||
|
_targetgroupname = tgtgrp:GetName() -- group name
|
||||||
|
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||||
|
self:T("*** Found Target = ".. _targetgroupname)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- see if we are shot at
|
||||||
|
local SEADGroupFound = false
|
||||||
|
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
|
||||||
|
self:T("Target = ".. _targetgroupname .. " | Prefix = " .. SEADGroupPrefix )
|
||||||
|
if string.find( _targetgroupname, SEADGroupPrefix,1,true ) then
|
||||||
|
SEADGroupFound = true
|
||||||
|
self:T( '*** SEAD - Group Match Found' )
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if SEADGroupFound == true then -- yes we are being attacked
|
||||||
|
self:ManageEvasion(_targetskill,_targetgroup,SEADPlanePos,SEADWeaponName,SEADGroup)
|
||||||
|
end
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
-- @field #boolean Report If true, send status messages to coalition.
|
-- @field #boolean Report If true, send status messages to coalition.
|
||||||
-- @field Wrapper.Static#STATIC warehouse The phyical warehouse structure.
|
-- @field Wrapper.Static#STATIC warehouse The phyical warehouse structure.
|
||||||
-- @field #string alias Alias of the warehouse. Name its called when sending messages.
|
-- @field #string alias Alias of the warehouse. Name its called when sending messages.
|
||||||
-- @field Core.Zone#ZONE zone Zone around the warehouse. If this zone is captured, the warehouse and all its assets goes to the capturing coaliton.
|
-- @field Core.Zone#ZONE zone Zone around the warehouse. If this zone is captured, the warehouse and all its assets goes to the capturing coalition.
|
||||||
-- @field Wrapper.Airbase#AIRBASE airbase Airbase the warehouse belongs to.
|
-- @field Wrapper.Airbase#AIRBASE airbase Airbase the warehouse belongs to.
|
||||||
-- @field #string airbasename Name of the airbase associated to the warehouse.
|
-- @field #string airbasename Name of the airbase associated to the warehouse.
|
||||||
-- @field Core.Point#COORDINATE road Closest point to warehouse on road.
|
-- @field Core.Point#COORDINATE road Closest point to warehouse on road.
|
||||||
@@ -764,7 +764,7 @@
|
|||||||
-- warehouseBatumi:Load("D:\\My Warehouse Data\\")
|
-- warehouseBatumi:Load("D:\\My Warehouse Data\\")
|
||||||
-- warehouseBatumi:Start()
|
-- warehouseBatumi:Start()
|
||||||
--
|
--
|
||||||
-- This sequence loads all assets from file. If a warehouse was captured in the last mission, it also respawns the static warehouse structure with the right coaliton.
|
-- This sequence loads all assets from file. If a warehouse was captured in the last mission, it also respawns the static warehouse structure with the right coalition.
|
||||||
-- However, it due to DCS limitations it is not possible to set the airbase coalition. This has to be done manually in the mission editor. Or alternatively, one could
|
-- However, it due to DCS limitations it is not possible to set the airbase coalition. This has to be done manually in the mission editor. Or alternatively, one could
|
||||||
-- spawn some ground units via a self request and let them capture the airbase.
|
-- spawn some ground units via a self request and let them capture the airbase.
|
||||||
--
|
--
|
||||||
@@ -1811,7 +1811,7 @@ WAREHOUSE.version="1.0.2"
|
|||||||
-- DONE: Add shipping lanes between warehouses.
|
-- DONE: Add shipping lanes between warehouses.
|
||||||
-- DONE: Handle cases with immobile units <== should be handled by dispatcher classes.
|
-- DONE: Handle cases with immobile units <== should be handled by dispatcher classes.
|
||||||
-- DONE: Handle cases for aircraft carriers and other ships. Place warehouse on carrier possible? On others probably not - exclude them?
|
-- DONE: Handle cases for aircraft carriers and other ships. Place warehouse on carrier possible? On others probably not - exclude them?
|
||||||
-- DONE: Add general message function for sending to coaliton or debug.
|
-- DONE: Add general message function for sending to coalition or debug.
|
||||||
-- DONE: Fine tune event handlers.
|
-- DONE: Fine tune event handlers.
|
||||||
-- DONE: Improve generalized attributes.
|
-- DONE: Improve generalized attributes.
|
||||||
-- DONE: If warehouse is destroyed, all asssets are gone.
|
-- DONE: If warehouse is destroyed, all asssets are gone.
|
||||||
@@ -3155,7 +3155,7 @@ end
|
|||||||
-- @param MinAssets (Optional) Minimum number of assets the warehouse should have. Default 0.
|
-- @param MinAssets (Optional) Minimum number of assets the warehouse should have. Default 0.
|
||||||
-- @param #string Descriptor (Optional) Descriptor describing the selected assets which should be in stock. See @{#WAREHOUSE.Descriptor} for possible values.
|
-- @param #string Descriptor (Optional) Descriptor describing the selected assets which should be in stock. See @{#WAREHOUSE.Descriptor} for possible values.
|
||||||
-- @param DescriptorValue (Optional) Descriptor value selecting the type of assets which should be in stock.
|
-- @param DescriptorValue (Optional) Descriptor value selecting the type of assets which should be in stock.
|
||||||
-- @param DCS#Coalition.side Coalition (Optional) Coalition side of the warehouse. Default is the same coaliton as the present warehouse. Set to false for any coalition.
|
-- @param DCS#Coalition.side Coalition (Optional) Coalition side of the warehouse. Default is the same coalition as the present warehouse. Set to false for any coalition.
|
||||||
-- @param Core.Point#COORDINATE RefCoordinate (Optional) Coordinate to which the closest warehouse is searched. Default is the warehouse calling this function.
|
-- @param Core.Point#COORDINATE RefCoordinate (Optional) Coordinate to which the closest warehouse is searched. Default is the warehouse calling this function.
|
||||||
-- @return #WAREHOUSE The the nearest warehouse object. Or nil if no warehouse is found.
|
-- @return #WAREHOUSE The the nearest warehouse object. Or nil if no warehouse is found.
|
||||||
-- @return #number The distance to the nearest warehouse in meters. Or nil if no warehouse is found.
|
-- @return #number The distance to the nearest warehouse in meters. Or nil if no warehouse is found.
|
||||||
@@ -3267,7 +3267,7 @@ function WAREHOUSE:onafterStart(From, Event, To)
|
|||||||
|
|
||||||
-- Short info.
|
-- Short info.
|
||||||
local text=string.format("Starting warehouse %s alias %s:\n",self.warehouse:GetName(), self.alias)
|
local text=string.format("Starting warehouse %s alias %s:\n",self.warehouse:GetName(), self.alias)
|
||||||
text=text..string.format("Coaliton = %s\n", self:GetCoalitionName())
|
text=text..string.format("Coalition = %s\n", self:GetCoalitionName())
|
||||||
text=text..string.format("Country = %s\n", self:GetCountryName())
|
text=text..string.format("Country = %s\n", self:GetCountryName())
|
||||||
text=text..string.format("Airbase = %s (category=%d)\n", self:GetAirbaseName(), self:GetAirbaseCategory())
|
text=text..string.format("Airbase = %s (category=%d)\n", self:GetAirbaseName(), self:GetAirbaseCategory())
|
||||||
env.info(text)
|
env.info(text)
|
||||||
@@ -8460,7 +8460,7 @@ function WAREHOUSE:_GetStockAssetsText(messagetoall)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Create or update mark text at warehouse, which is displayed in F10 map showing how many assets of each type are in stock.
|
--- Create or update mark text at warehouse, which is displayed in F10 map showing how many assets of each type are in stock.
|
||||||
-- Only the coaliton of the warehouse owner is able to see it.
|
-- Only the coalition of the warehouse owner is able to see it.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @return #string Text about warehouse stock
|
-- @return #string Text about warehouse stock
|
||||||
function WAREHOUSE:_UpdateWarehouseMarkText()
|
function WAREHOUSE:_UpdateWarehouseMarkText()
|
||||||
|
|||||||
@@ -804,7 +804,7 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
return IsEmpty
|
return IsEmpty
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if zone is "Guarded", i.e. only one (the defending) coaliton is present inside the zone.
|
--- Check if zone is "Guarded", i.e. only one (the defending) coalition is present inside the zone.
|
||||||
-- @param #ZONE_CAPTURE_COALITION self
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
-- @return #boolean self:IsAllInZoneOfCoalition( self.Coalition )
|
-- @return #boolean self:IsAllInZoneOfCoalition( self.Coalition )
|
||||||
function ZONE_CAPTURE_COALITION:IsGuarded()
|
function ZONE_CAPTURE_COALITION:IsGuarded()
|
||||||
@@ -826,7 +826,7 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
return IsCaptured
|
return IsCaptured
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if zone is "Attacked", i.e. another coaliton entered the zone.
|
--- Check if zone is "Attacked", i.e. another coalition entered the zone.
|
||||||
-- @param #ZONE_CAPTURE_COALITION self
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
-- @return #boolean self:IsSomeInZoneOfCoalition( self.Coalition )
|
-- @return #boolean self:IsSomeInZoneOfCoalition( self.Coalition )
|
||||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||||
@@ -906,7 +906,6 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
-- Misc Functions
|
-- Misc Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
--- Update Mark on F10 map.
|
--- Update Mark on F10 map.
|
||||||
-- @param #ZONE_CAPTURE_COALITION self
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
function ZONE_CAPTURE_COALITION:Mark()
|
function ZONE_CAPTURE_COALITION:Mark()
|
||||||
@@ -925,7 +924,7 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
Coord:RemoveMark(self.MarkBlue)
|
Coord:RemoveMark(self.MarkBlue)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create new marks for each coaliton.
|
-- Create new marks for each coalition.
|
||||||
if self.Coalition == coalition.side.BLUE then
|
if self.Coalition == coalition.side.BLUE then
|
||||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ do -- ZoneGoal
|
|||||||
-- @field #table ObjectCategories Table of object categories that are able to hold a zone. Default is UNITS and STATICS.
|
-- @field #table ObjectCategories Table of object categories that are able to hold a zone. Default is UNITS and STATICS.
|
||||||
-- @extends Functional.ZoneGoal#ZONE_GOAL
|
-- @extends Functional.ZoneGoal#ZONE_GOAL
|
||||||
|
|
||||||
|
|
||||||
--- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
|
--- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
|
||||||
-- Derived classes implement the ways how the achievements can be realized.
|
-- Derived classes implement the ways how the achievements can be realized.
|
||||||
--
|
--
|
||||||
@@ -44,7 +43,7 @@ do -- ZoneGoal
|
|||||||
ZONE_GOAL_COALITION = {
|
ZONE_GOAL_COALITION = {
|
||||||
ClassName = "ZONE_GOAL_COALITION",
|
ClassName = "ZONE_GOAL_COALITION",
|
||||||
Coalition = nil,
|
Coalition = nil,
|
||||||
PreviousCoaliton = nil,
|
PreviousCoalition = nil,
|
||||||
UnitCategories = nil,
|
UnitCategories = nil,
|
||||||
ObjectCategories = nil,
|
ObjectCategories = nil,
|
||||||
}
|
}
|
||||||
@@ -61,7 +60,7 @@ do -- ZoneGoal
|
|||||||
function ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories )
|
function ZONE_GOAL_COALITION:New( Zone, Coalition, UnitCategories )
|
||||||
|
|
||||||
if not Zone then
|
if not Zone then
|
||||||
BASE:E("ERROR: No Zone specified in ZONE_GOAL_COALITON!")
|
BASE:E( "ERROR: No Zone specified in ZONE_GOAL_COALITION!" )
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -79,7 +78,6 @@ do -- ZoneGoal
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the owning coalition of the zone.
|
--- Set the owning coalition of the zone.
|
||||||
-- @param #ZONE_GOAL_COALITION self
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The coalition ID, e.g. *coalition.side.RED*.
|
-- @param DCSCoalition.DCSCoalition#coalition Coalition The coalition ID, e.g. *coalition.side.RED*.
|
||||||
@@ -127,14 +125,13 @@ do -- ZoneGoal
|
|||||||
return self.Coalition
|
return self.Coalition
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the previous coaliton, i.e. the one owning the zone before the current one.
|
--- Get the previous coalition, i.e. the one owning the zone before the current one.
|
||||||
-- @param #ZONE_GOAL_COALITION self
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||||
function ZONE_GOAL_COALITION:GetPreviousCoalition()
|
function ZONE_GOAL_COALITION:GetPreviousCoalition()
|
||||||
return self.PreviousCoalition
|
return self.PreviousCoalition
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the owning coalition name of the zone.
|
--- Get the owning coalition name of the zone.
|
||||||
-- @param #ZONE_GOAL_COALITION self
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
-- @return #string Coalition name.
|
-- @return #string Coalition name.
|
||||||
@@ -142,7 +139,6 @@ do -- ZoneGoal
|
|||||||
return UTILS.GetCoalitionName( self.Coalition )
|
return UTILS.GetCoalitionName( self.Coalition )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check status Coalition ownership.
|
--- Check status Coalition ownership.
|
||||||
-- @param #ZONE_GOAL_COALITION self
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
-- @return #ZONE_GOAL_COALITION
|
-- @return #ZONE_GOAL_COALITION
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ __Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )
|
||||||
|
|||||||
@@ -1740,6 +1740,10 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Wind
|
-- Wind
|
||||||
|
-- Adding a space after each digit of WINDFROM to convert this to aviation-speak for TTS via SRS
|
||||||
|
if self.useSRS then
|
||||||
|
WINDFROM = string.gsub(WINDFROM,".", "%1 ")
|
||||||
|
end
|
||||||
if self.metric then
|
if self.metric then
|
||||||
subtitle = string.format( "Wind from %s at %s m/s", WINDFROM, WINDSPEED )
|
subtitle = string.format( "Wind from %s at %s m/s", WINDFROM, WINDSPEED )
|
||||||
else
|
else
|
||||||
@@ -2197,7 +2201,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
-- TACAN
|
-- TACAN
|
||||||
if self.tacan then
|
if self.tacan then
|
||||||
subtitle = string.format( "TACAN channel %dX", self.tacan )
|
subtitle = string.format( "TACAN channel %dX Ray", self.tacan )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
self:Transmission( ATIS.Sound.TACANChannel, 1.0, subtitle )
|
self:Transmission( ATIS.Sound.TACANChannel, 1.0, subtitle )
|
||||||
self.radioqueue:Number2Transmission( tostring( self.tacan ), nil, 0.2 )
|
self.radioqueue:Number2Transmission( tostring( self.tacan ), nil, 0.2 )
|
||||||
|
|||||||
@@ -32,9 +32,12 @@
|
|||||||
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_(CVN-73)) (CVN-73) [Super Carrier Module]
|
-- * [USS George Washington](https://en.wikipedia.org/wiki/USS_George_Washington_(CVN-73)) (CVN-73) [Super Carrier Module]
|
||||||
-- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module]
|
-- * [USS Harry S. Truman](https://en.wikipedia.org/wiki/USS_Harry_S._Truman) (CVN-75) [Super Carrier Module]
|
||||||
-- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_(CV-59)) (CV-59) [Heatblur Carrier Module]
|
-- * [USS Forrestal](https://en.wikipedia.org/wiki/USS_Forrestal_(CV-59)) (CV-59) [Heatblur Carrier Module]
|
||||||
|
-- * [HMS Hermes](https://en.wikipedia.org/wiki/HMS_Hermes_(R12)) (R12) [**WIP**]
|
||||||
|
-- * [HMS Invincible](https://en.wikipedia.org/wiki/HMS_Invincible_(R05) (R05) [**WIP**]
|
||||||
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1)) (LHA-1) [**WIP**]
|
-- * [USS Tarawa](https://en.wikipedia.org/wiki/USS_Tarawa_(LHA-1)) (LHA-1) [**WIP**]
|
||||||
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_(LHA-6)) (LHA-6) [**WIP**]
|
-- * [USS America](https://en.wikipedia.org/wiki/USS_America_(LHA-6)) (LHA-6) [**WIP**]
|
||||||
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61) [**WIP**]
|
-- * [Juan Carlos I](https://en.wikipedia.org/wiki/Spanish_amphibious_assault_ship_Juan_Carlos_I) (L61) [**WIP**]
|
||||||
|
-- * [HMAS Canberra](https://en.wikipedia.org/wiki/HMAS_Canberra_(L02)) (L02) [**WIP**]
|
||||||
--
|
--
|
||||||
-- **Supported Aircraft:**
|
-- **Supported Aircraft:**
|
||||||
--
|
--
|
||||||
@@ -51,9 +54,9 @@
|
|||||||
--
|
--
|
||||||
-- At the moment, optimized parameters are available for the F/A-18C Hornet (Lot 20) and A-4E community mod as aircraft and the USS John C. Stennis as carrier.
|
-- At the moment, optimized parameters are available for the F/A-18C Hornet (Lot 20) and A-4E community mod as aircraft and the USS John C. Stennis as carrier.
|
||||||
--
|
--
|
||||||
-- The AV-8B Harrier, the USS Tarawa, USS America, HMAS Canberra and Juan Carlos I are WIP. The AV-8B harrier and the LHA's and LHD can only be used together, i.e. these ships are the only carriers the harrier is supposed to land on and
|
-- The AV-8B Harrier, HMS Hermes, HMS Invincible, the USS Tarawa, USS America, HMAS Canberra, and Juan Carlos I are WIP. The AV-8B harrier and the LHA's and LHD can only be used together, i.e. these ships are the only carriers the harrier is supposed to land on and
|
||||||
-- no other fixed wing aircraft (human or AI controlled) are supposed to land on these ships. Currently only Case I is supported. Case II/III take slightly different steps from the CVN carrier.
|
-- no other fixed wing aircraft (human or AI controlled) are supposed to land on these ships. Currently only Case I is supported. Case II/III take slightly different steps from the CVN carrier.
|
||||||
-- However, the two Case II/III pattern are very similar so this is not a big drawback.
|
-- However, if no offset is used for the holding radial this provides a very close representation of the V/STOL Case III, allowing for an approach to over the deck and a vertical landing.
|
||||||
--
|
--
|
||||||
-- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well. Same goes for the A version.
|
-- Heatblur's mighty F-14B Tomcat has been added (March 13th 2019) as well. Same goes for the A version.
|
||||||
--
|
--
|
||||||
@@ -113,10 +116,11 @@
|
|||||||
-- * [Harrier Ship Landing Mission with Auto LSO!](https://www.youtube.com/watch?v=lqmVvpunk2c)
|
-- * [Harrier Ship Landing Mission with Auto LSO!](https://www.youtube.com/watch?v=lqmVvpunk2c)
|
||||||
-- * [Updated Airboss V/STOL Features USS Tarawa](https://youtu.be/K7I4pU6j718)
|
-- * [Updated Airboss V/STOL Features USS Tarawa](https://youtu.be/K7I4pU6j718)
|
||||||
-- * [Harrier Practice pattern USS America](https://youtu.be/99NigITYmcI)
|
-- * [Harrier Practice pattern USS America](https://youtu.be/99NigITYmcI)
|
||||||
|
-- * [Harrier CASE III TACAN Approach USS Tarawa](https://www.youtube.com/watch?v=bTgJXZ9Mhdc&t=1s)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky** LHA and LHD V/STOL additions by **Pene**
|
||||||
-- ### Special Thanks To **Bankler**
|
-- ### Special Thanks To **Bankler**
|
||||||
-- For his great [Recovery Trainer](https://forums.eagle.ru/showthread.php?t=221412) mission and script!
|
-- For his great [Recovery Trainer](https://forums.eagle.ru/showthread.php?t=221412) mission and script!
|
||||||
-- His work was the initial inspiration for this class. Also note that this implementation uses some routines for determining the player position in Case I recoveries he developed.
|
-- His work was the initial inspiration for this class. Also note that this implementation uses some routines for determining the player position in Case I recoveries he developed.
|
||||||
@@ -1260,7 +1264,7 @@ AIRBOSS = {
|
|||||||
|
|
||||||
--- Aircraft types capable of landing on carrier (human+AI).
|
--- Aircraft types capable of landing on carrier (human+AI).
|
||||||
-- @type AIRBOSS.AircraftCarrier
|
-- @type AIRBOSS.AircraftCarrier
|
||||||
-- @field #string AV8B AV-8B Night Harrier. Works only with the USS Tarawa, USS America and Juan Carlos I.
|
-- @field #string AV8B AV-8B Night Harrier. Works only with the HMS Hermes, HMS Invincible, USS Tarawa, USS America, and Juan Carlos I.
|
||||||
-- @field #string A4EC A-4E Community mod.
|
-- @field #string A4EC A-4E Community mod.
|
||||||
-- @field #string HORNET F/A-18C Lot 20 Hornet by Eagle Dynamics.
|
-- @field #string HORNET F/A-18C Lot 20 Hornet by Eagle Dynamics.
|
||||||
-- @field #string F14A F-14A by Heatblur.
|
-- @field #string F14A F-14A by Heatblur.
|
||||||
@@ -1296,6 +1300,8 @@ AIRBOSS.AircraftCarrier={
|
|||||||
-- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module]
|
-- @field #string TRUMAN USS Harry S. Truman (CVN-75) [Super Carrier Module]
|
||||||
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
-- @field #string FORRESTAL USS Forrestal (CV-59) [Heatblur Carrier Module]
|
||||||
-- @field #string VINSON USS Carl Vinson (CVN-70) [Obsolete]
|
-- @field #string VINSON USS Carl Vinson (CVN-70) [Obsolete]
|
||||||
|
-- @field #string HERMES HMS Hermes (R12) [V/STOL Carrier]
|
||||||
|
-- @field #string INVINCIBLE HMS Invincible (R05) [V/STOL Carrier]
|
||||||
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
-- @field #string TARAWA USS Tarawa (LHA-1) [V/STOL Carrier]
|
||||||
-- @field #string AMERICA USS America (LHA-6) [V/STOL Carrier]
|
-- @field #string AMERICA USS America (LHA-6) [V/STOL Carrier]
|
||||||
-- @field #string JCARLOS Juan Carlos I (L61) [V/STOL Carrier]
|
-- @field #string JCARLOS Juan Carlos I (L61) [V/STOL Carrier]
|
||||||
@@ -1309,6 +1315,8 @@ AIRBOSS.CarrierType = {
|
|||||||
STENNIS = "Stennis",
|
STENNIS = "Stennis",
|
||||||
FORRESTAL = "Forrestal",
|
FORRESTAL = "Forrestal",
|
||||||
VINSON = "VINSON",
|
VINSON = "VINSON",
|
||||||
|
HERMES = "HERMES81",
|
||||||
|
INVINCIBLE = "hms_invincible",
|
||||||
TARAWA = "LHA_Tarawa",
|
TARAWA = "LHA_Tarawa",
|
||||||
AMERICA = "USS America LHA-6",
|
AMERICA = "USS America LHA-6",
|
||||||
JCARLOS = "L61",
|
JCARLOS = "L61",
|
||||||
@@ -1980,6 +1988,12 @@ function AIRBOSS:New( carriername, alias )
|
|||||||
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
elseif self.carriertype == AIRBOSS.CarrierType.VINSON then
|
||||||
-- TODO: Carl Vinson parameters.
|
-- TODO: Carl Vinson parameters.
|
||||||
self:_InitStennis()
|
self:_InitStennis()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.HERMES then
|
||||||
|
-- Hermes parameters.
|
||||||
|
self:_InitHermes()
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.INVINCIBLE then
|
||||||
|
-- Invincible parameters.
|
||||||
|
self:_InitInvincible()
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then
|
elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then
|
||||||
-- Tarawa parameters.
|
-- Tarawa parameters.
|
||||||
self:_InitTarawa()
|
self:_InitTarawa()
|
||||||
@@ -2082,7 +2096,7 @@ function AIRBOSS:New( carriername, alias )
|
|||||||
-- cL:FlareYellow()
|
-- cL:FlareYellow()
|
||||||
|
|
||||||
-- Carrier specific.
|
-- Carrier specific.
|
||||||
if self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.TARAWA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.AMERICA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.JCARLOS or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.CANBERRA then
|
if self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.INVINCIBLE or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.HERMES or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.TARAWA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.AMERICA or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.JCARLOS or self.carrier:GetTypeName() ~= AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
-- Flare wires.
|
-- Flare wires.
|
||||||
local w1 = stern:Translate( self.carrierparam.wire1, FB, true )
|
local w1 = stern:Translate( self.carrierparam.wire1, FB, true )
|
||||||
@@ -2811,13 +2825,29 @@ end
|
|||||||
-- @param #number Low
|
-- @param #number Low
|
||||||
-- @param #number LOW
|
-- @param #number LOW
|
||||||
-- @return #AIRBOSS self
|
-- @return #AIRBOSS self
|
||||||
|
|
||||||
function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW)
|
function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW)
|
||||||
|
|
||||||
|
--Check if V/STOL Carrier
|
||||||
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
|
-- allow a larger GSE for V/STOL operations --Pene Testing
|
||||||
|
self.gle._max=_max or 0.7
|
||||||
|
self.gle.High=High or 1.4
|
||||||
|
self.gle.HIGH=HIGH or 1.9
|
||||||
|
self.gle._min=_min or -0.5
|
||||||
|
self.gle.Low=Low or -1.2
|
||||||
|
self.gle.LOW=LOW or -1.5
|
||||||
|
-- CVN values
|
||||||
|
else
|
||||||
self.gle._max=_max or 0.4
|
self.gle._max=_max or 0.4
|
||||||
self.gle.High=High or 0.8
|
self.gle.High=High or 0.8
|
||||||
self.gle.HIGH=HIGH or 1.5
|
self.gle.HIGH=HIGH or 1.5
|
||||||
self.gle._min=_min or -0.3
|
self.gle._min=_min or -0.3
|
||||||
self.gle.Low=Low or -0.6
|
self.gle.Low=Low or -0.6
|
||||||
self.gle.LOW=LOW or -0.9
|
self.gle.LOW=LOW or -0.9
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2832,7 +2862,23 @@ end
|
|||||||
-- @param #number RightMed
|
-- @param #number RightMed
|
||||||
-- @param #number RIGHT
|
-- @param #number RIGHT
|
||||||
-- @return #AIRBOSS self
|
-- @return #AIRBOSS self
|
||||||
|
|
||||||
function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LeftMed, LEFT, Right, RightMed, RIGHT)
|
function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LeftMed, LEFT, Right, RightMed, RIGHT)
|
||||||
|
|
||||||
|
--Check if V/STOL Carrier -- Pene testing
|
||||||
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
|
-- V/STOL Values -- allow a larger LUE for V/STOL operations
|
||||||
|
self.lue._max=_max or 1.8
|
||||||
|
self.lue._min=_min or -1.8
|
||||||
|
self.lue.Left=Left or -2.8
|
||||||
|
self.lue.LeftMed=LeftMed or -3.8
|
||||||
|
self.lue.LEFT=LEFT or -4.5
|
||||||
|
self.lue.Right=Right or 2.8
|
||||||
|
self.lue.RightMed=RightMed or 3.8
|
||||||
|
self.lue.RIGHT=RIGHT or 4.5
|
||||||
|
-- CVN Values
|
||||||
|
else
|
||||||
self.lue._max=_max or 0.5
|
self.lue._max=_max or 0.5
|
||||||
self.lue._min=_min or -0.5
|
self.lue._min=_min or -0.5
|
||||||
self.lue.Left=Left or -1.0
|
self.lue.Left=Left or -1.0
|
||||||
@@ -2841,6 +2887,8 @@ function AIRBOSS:SetLineupErrorThresholds( _max, _min, Left, LeftMed, LEFT, Righ
|
|||||||
self.lue.Right=Right or 1.0
|
self.lue.Right=Right or 1.0
|
||||||
self.lue.RightMed=RightMed or 2.0
|
self.lue.RightMed=RightMed or 2.0
|
||||||
self.lue.RIGHT=RIGHT or 3.0
|
self.lue.RIGHT=RIGHT or 3.0
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4384,6 +4432,86 @@ function AIRBOSS:_InitForrestal()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Init parameters for R12 HMS Hermes carrier.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitHermes()
|
||||||
|
|
||||||
|
-- Init Stennis as default.
|
||||||
|
self:_InitStennis()
|
||||||
|
|
||||||
|
-- Carrier Parameters.
|
||||||
|
self.carrierparam.sterndist = -105
|
||||||
|
self.carrierparam.deckheight = 12 -- From model viewer WL0.
|
||||||
|
|
||||||
|
-- Total size of the carrier (approx as rectangle).
|
||||||
|
self.carrierparam.totlength = 228.19
|
||||||
|
self.carrierparam.totwidthport = 20.5
|
||||||
|
self.carrierparam.totwidthstarboard = 24.5
|
||||||
|
|
||||||
|
-- Landing runway.
|
||||||
|
self.carrierparam.rwyangle = 0
|
||||||
|
self.carrierparam.rwylength = 215
|
||||||
|
self.carrierparam.rwywidth = 13
|
||||||
|
|
||||||
|
-- Wires.
|
||||||
|
self.carrierparam.wire1 = nil
|
||||||
|
self.carrierparam.wire2 = nil
|
||||||
|
self.carrierparam.wire3 = nil
|
||||||
|
self.carrierparam.wire4 = nil
|
||||||
|
|
||||||
|
-- Late break.
|
||||||
|
self.BreakLate.name = "Late Break"
|
||||||
|
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
|
||||||
|
self.BreakLate.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks?
|
||||||
|
self.BreakLate.Zmin = -UTILS.NMToMeters( 1.6 ) -- Not more than 1.6 NM port.
|
||||||
|
self.BreakLate.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard.
|
||||||
|
self.BreakLate.LimitXmin = 0 -- Check and next step 0.8 NM port and in front of boat.
|
||||||
|
self.BreakLate.LimitXmax = nil
|
||||||
|
self.BreakLate.LimitZmin = -UTILS.NMToMeters( 0.5 ) -- 926 m port, closer than the stennis as abeam is 0.8-1.0 rather than 1.2
|
||||||
|
self.BreakLate.LimitZmax = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Init parameters for R05 HMS Invincible carrier.
|
||||||
|
-- @param #AIRBOSS self
|
||||||
|
function AIRBOSS:_InitInvincible()
|
||||||
|
|
||||||
|
-- Init Stennis as default.
|
||||||
|
self:_InitStennis()
|
||||||
|
|
||||||
|
-- Carrier Parameters.
|
||||||
|
self.carrierparam.sterndist = -105
|
||||||
|
self.carrierparam.deckheight = 12 -- From model viewer WL0.
|
||||||
|
|
||||||
|
-- Total size of the carrier (approx as rectangle).
|
||||||
|
self.carrierparam.totlength = 228.19
|
||||||
|
self.carrierparam.totwidthport = 20.5
|
||||||
|
self.carrierparam.totwidthstarboard = 24.5
|
||||||
|
|
||||||
|
-- Landing runway.
|
||||||
|
self.carrierparam.rwyangle = 0
|
||||||
|
self.carrierparam.rwylength = 215
|
||||||
|
self.carrierparam.rwywidth = 13
|
||||||
|
|
||||||
|
-- Wires.
|
||||||
|
self.carrierparam.wire1 = nil
|
||||||
|
self.carrierparam.wire2 = nil
|
||||||
|
self.carrierparam.wire3 = nil
|
||||||
|
self.carrierparam.wire4 = nil
|
||||||
|
|
||||||
|
-- Late break.
|
||||||
|
self.BreakLate.name = "Late Break"
|
||||||
|
self.BreakLate.Xmin = -UTILS.NMToMeters( 1 ) -- Not more than 1 NM behind the boat. Last check was at 0.
|
||||||
|
self.BreakLate.Xmax = UTILS.NMToMeters( 5 ) -- Not more than 5 NM in front of the boat. Enough for late breaks?
|
||||||
|
self.BreakLate.Zmin = -UTILS.NMToMeters( 1.6 ) -- Not more than 1.6 NM port.
|
||||||
|
self.BreakLate.Zmax = UTILS.NMToMeters( 1 ) -- Not more than 1 NM starboard.
|
||||||
|
self.BreakLate.LimitXmin = 0 -- Check and next step 0.8 NM port and in front of boat.
|
||||||
|
self.BreakLate.LimitXmax = nil
|
||||||
|
self.BreakLate.LimitZmin = -UTILS.NMToMeters( 0.5 ) -- 926 m port, closer than the stennis as abeam is 0.8-1.0 rather than 1.2
|
||||||
|
self.BreakLate.LimitZmax = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Init parameters for LHA-1 Tarawa carrier.
|
--- Init parameters for LHA-1 Tarawa carrier.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
function AIRBOSS:_InitTarawa()
|
function AIRBOSS:_InitTarawa()
|
||||||
@@ -5007,14 +5135,16 @@ function AIRBOSS:_GetAircraftAoA( playerData )
|
|||||||
aoa.Fast = 8.25 -- =17.5/2
|
aoa.Fast = 8.25 -- =17.5/2
|
||||||
aoa.FAST = 8.00 -- =16.5/2
|
aoa.FAST = 8.00 -- =16.5/2
|
||||||
elseif harrier then
|
elseif harrier then
|
||||||
-- AV-8B Harrier parameters. Tuning done on the Fast AoA to allow for abeam and ninety at Nozzles 60 - 73.
|
|
||||||
aoa.SLOW = 14.0
|
-- AV-8B Harrier parameters. Tuning done on the Fast AoA to allow for abeam and ninety at Nozzles 55. Pene testing
|
||||||
aoa.Slow = 13.0
|
aoa.SLOW = 16.0
|
||||||
aoa.OnSpeedMax = 12.0
|
aoa.Slow = 13.5
|
||||||
aoa.OnSpeed = 11.0
|
aoa.OnSpeedMax = 12.5
|
||||||
aoa.OnSpeedMin = 10.0
|
aoa.OnSpeed = 10.0
|
||||||
|
aoa.OnSpeedMin = 9.5
|
||||||
aoa.Fast = 8.0
|
aoa.Fast = 8.0
|
||||||
aoa.FAST = 7.5
|
aoa.FAST = 7.5
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return aoa
|
return aoa
|
||||||
@@ -5273,8 +5403,8 @@ function AIRBOSS:_GetAircraftParameters( playerData, step )
|
|||||||
elseif skyhawk then
|
elseif skyhawk then
|
||||||
alt = UTILS.FeetToMeters( 300 ) -- ?
|
alt = UTILS.FeetToMeters( 300 ) -- ?
|
||||||
elseif harrier then
|
elseif harrier then
|
||||||
-- 300-325 ft
|
alt=UTILS.FeetToMeters(312)-- 300-325 ft
|
||||||
alt = UTILS.FeetToMeters( 300 ) -- Need to verify
|
|
||||||
end
|
end
|
||||||
|
|
||||||
aoa = aoaac.OnSpeed
|
aoa = aoaac.OnSpeed
|
||||||
@@ -6058,7 +6188,7 @@ function AIRBOSS:_RefuelAI( flight )
|
|||||||
-- Guide AI to divert field --
|
-- Guide AI to divert field --
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
-- Closest Airfield of the coaliton.
|
-- Closest Airfield of the coalition.
|
||||||
local divertfield = self:GetCoordinate():GetClosestAirbase( Airbase.Category.AIRDROME, self:GetCoalition() )
|
local divertfield = self:GetCoordinate():GetClosestAirbase( Airbase.Category.AIRDROME, self:GetCoalition() )
|
||||||
|
|
||||||
-- Handle case where there is no divert field of the own coalition and try neutral instead.
|
-- Handle case where there is no divert field of the own coalition and try neutral instead.
|
||||||
@@ -6209,7 +6339,7 @@ function AIRBOSS:_GetMarshalAltitude( stack, case )
|
|||||||
p2 = Carrier:Translate( UTILS.NMToMeters( 1.5 ), hdg )
|
p2 = Carrier:Translate( UTILS.NMToMeters( 1.5 ), hdg )
|
||||||
|
|
||||||
-- Tarawa,LHA,LHD Delta patterns.
|
-- Tarawa,LHA,LHD Delta patterns.
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
-- Pattern is directly overhead the carrier.
|
-- Pattern is directly overhead the carrier.
|
||||||
p1 = Carrier:Translate( UTILS.NMToMeters( 1.0 ), hdg + 90 )
|
p1 = Carrier:Translate( UTILS.NMToMeters( 1.0 ), hdg + 90 )
|
||||||
@@ -8048,7 +8178,7 @@ function AIRBOSS:OnEventLand( EventData )
|
|||||||
self:T( self.lid .. text )
|
self:T( self.lid .. text )
|
||||||
|
|
||||||
-- Check carrier type.
|
-- Check carrier type.
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
-- Power "Idle".
|
-- Power "Idle".
|
||||||
self:RadioTransmission( self.LSORadio, self.LSOCall.IDLE, false, 1, nil, true )
|
self:RadioTransmission( self.LSORadio, self.LSOCall.IDLE, false, 1, nil, true )
|
||||||
@@ -8083,7 +8213,7 @@ function AIRBOSS:OnEventLand( EventData )
|
|||||||
-- AI unit landed --
|
-- AI unit landed --
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
if self.carriertype ~= AIRBOSS.CarrierType.TARAWA or self.carriertype ~= AIRBOSS.CarrierType.AMERICA or self.carriertype ~= AIRBOSS.CarrierType.JCARLOS or self.carriertype ~= AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype ~= AIRBOSS.CarrierType.INVINCIBLE or self.carriertype ~= AIRBOSS.CarrierType.HERMES or self.carriertype ~= AIRBOSS.CarrierType.TARAWA or self.carriertype ~= AIRBOSS.CarrierType.AMERICA or self.carriertype ~= AIRBOSS.CarrierType.JCARLOS or self.carriertype ~= AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
-- Coordinate at landing event
|
-- Coordinate at landing event
|
||||||
local coord = EventData.IniUnit:GetCoordinate()
|
local coord = EventData.IniUnit:GetCoordinate()
|
||||||
@@ -9121,7 +9251,7 @@ function AIRBOSS:_CheckForLongDownwind( playerData )
|
|||||||
local limit = UTILS.NMToMeters( -1.6 )
|
local limit = UTILS.NMToMeters( -1.6 )
|
||||||
|
|
||||||
-- For the tarawa, other LHA and LHD we give a bit more space.
|
-- For the tarawa, other LHA and LHD we give a bit more space.
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
limit = UTILS.NMToMeters( -2.0 )
|
limit = UTILS.NMToMeters( -2.0 )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -9208,7 +9338,7 @@ function AIRBOSS:_Ninety( playerData )
|
|||||||
self:_PlayerHint( playerData )
|
self:_PlayerHint( playerData )
|
||||||
|
|
||||||
-- Next step: wake.
|
-- Next step: wake.
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
-- Harrier has no wake stop. It stays port of the boat.
|
-- Harrier has no wake stop. It stays port of the boat.
|
||||||
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.FINAL )
|
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.FINAL )
|
||||||
else
|
else
|
||||||
@@ -9464,8 +9594,9 @@ function AIRBOSS:_Groove( playerData )
|
|||||||
-- Speed difference.
|
-- Speed difference.
|
||||||
local dv = math.abs( vplayer - vcarrier )
|
local dv = math.abs( vplayer - vcarrier )
|
||||||
|
|
||||||
-- Stable when speed difference < 20 km/h.
|
|
||||||
local stable = dv < 20
|
-- Stable when speed difference < 30 km/h.(16 Kts)Pene Testing
|
||||||
|
local stable=dv<30
|
||||||
|
|
||||||
-- Check if player is inside the zone.
|
-- Check if player is inside the zone.
|
||||||
if playerData.unit:IsInZone( ZoneALS ) and stable then
|
if playerData.unit:IsInZone( ZoneALS ) and stable then
|
||||||
@@ -9497,8 +9628,8 @@ function AIRBOSS:_Groove( playerData )
|
|||||||
-- Speed difference.
|
-- Speed difference.
|
||||||
local dv = math.abs( vplayer - vcarrier )
|
local dv = math.abs( vplayer - vcarrier )
|
||||||
|
|
||||||
-- Stable when v<10 km/h.
|
-- Stable when v<15 km/h.
|
||||||
local stable = dv < 10
|
local stable=dv<15
|
||||||
|
|
||||||
-- Radio Transmission "Stabilized" once the aircraft has been cleared to cross and is over the Landing Spot and stable.
|
-- Radio Transmission "Stabilized" once the aircraft has been cleared to cross and is over the Landing Spot and stable.
|
||||||
if playerData.unit:IsInZone( ZoneLS ) and stable and playerData.stable == true then
|
if playerData.unit:IsInZone( ZoneLS ) and stable and playerData.stable == true then
|
||||||
@@ -9537,9 +9668,10 @@ function AIRBOSS:_Groove( playerData )
|
|||||||
-- Nothing else necessary.
|
-- Nothing else necessary.
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Long V/STOL groove time Wave Off over 75 seconds to IC - TOPGUN level Only. --pene testing (WIP)
|
-- Long V/STOL groove time Wave Off over 75 seconds to IC - TOPGUN level Only. --pene testing (WIP)--- Need to think more about this.
|
||||||
|
|
||||||
--if rho>=RAR and rho<=RIC and not playerData.waveoff and playerData.difficulty==AIRBOSS.Difficulty.HARD and playerData.actype== AIRBOSS.AircraftCarrier.AV8B then
|
--if rho>=RAR and rho<=RIC and not playerData.waveoff and playerData.difficulty==AIRBOSS.Difficulty.HARD and playerData.actype== AIRBOSS.AircraftCarrier.AV8B then
|
||||||
-- Get groove time
|
-- Get groove time
|
||||||
@@ -9726,8 +9858,8 @@ function AIRBOSS:_CheckWaveOff( glideslopeError, lineupError, AoA, playerData )
|
|||||||
-- For the harrier, we allow a bit more room.
|
-- For the harrier, we allow a bit more room.
|
||||||
if playerData.actype == AIRBOSS.AircraftCarrier.AV8B then
|
if playerData.actype == AIRBOSS.AircraftCarrier.AV8B then
|
||||||
glMax = 2.6
|
glMax = 2.6
|
||||||
glMin = -2.0
|
glMin = -2.2 -- Testing, @Engines may be just dragging it in on Hermes, or the carrier parameters need adjusting.
|
||||||
luAbs = 4.1 -- Testing Pene (WIP) needs feedback to tighten up tolerences.
|
luAbs = 4.1 -- Testing Pene.
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -9894,15 +10026,21 @@ function AIRBOSS:_GetSternCoord()
|
|||||||
|
|
||||||
-- Final bearing (true).
|
-- Final bearing (true).
|
||||||
local FB=self:GetFinalBearing()
|
local FB=self:GetFinalBearing()
|
||||||
|
local case=self.case
|
||||||
|
|
||||||
-- Stern coordinate (sterndist<0). Also translate 10 meters starboard wrt Final bearing.
|
-- Stern coordinate (sterndist<0). Also translate 10 meters starboard wrt Final bearing.
|
||||||
self.sterncoord:UpdateFromCoordinate( self:GetCoordinate() )
|
self.sterncoord:UpdateFromCoordinate( self:GetCoordinate() )
|
||||||
-- local stern=self:GetCoordinate()
|
-- local stern=self:GetCoordinate()
|
||||||
|
|
||||||
-- Stern coordinate (sterndist<0).
|
-- Stern coordinate (sterndist<0). --Pene testing Case III
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then
|
||||||
-- Tarawa: Translate 8 meters port.
|
if case==3 then
|
||||||
|
-- CASE III V/STOL translation Due over deck approach if needed.
|
||||||
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true)
|
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true)
|
||||||
|
elseif case==2 or case==1 then
|
||||||
|
-- V/Stol: Translate 8 meters port.
|
||||||
|
self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true)
|
||||||
|
end
|
||||||
elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then
|
elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then
|
||||||
-- Stennis: translate 7 meters starboard wrt Final bearing.
|
-- Stennis: translate 7 meters starboard wrt Final bearing.
|
||||||
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7, FB + 90, true, true )
|
self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7, FB + 90, true, true )
|
||||||
@@ -10536,7 +10674,8 @@ function AIRBOSS:_GetZoneRunwayBox()
|
|||||||
return self.zoneRunwaybox
|
return self.zoneRunwaybox
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get zone of primary abeam landing position of USS Tarawa, USS America and Juan Carlos. Box length 50 meters and width 30 meters.
|
--- Get zone of primary abeam landing position of HMS Hermes, HMS Invincible, USS Tarawa, USS America and Juan Carlos. Box length 50 meters and width 30 meters.
|
||||||
|
|
||||||
--- Allow for Clear to land call from LSO approaching abeam the landing spot if stable as per NATOPS 00-80T
|
--- Allow for Clear to land call from LSO approaching abeam the landing spot if stable as per NATOPS 00-80T
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @return Core.Zone#ZONE_POLYGON Zone surrounding landing runway.
|
-- @return Core.Zone#ZONE_POLYGON Zone surrounding landing runway.
|
||||||
@@ -10548,7 +10687,7 @@ function AIRBOSS:_GetZoneAbeamLandingSpot()
|
|||||||
-- Current carrier heading.
|
-- Current carrier heading.
|
||||||
local FB = self:GetFinalBearing( false )
|
local FB = self:GetFinalBearing( false )
|
||||||
|
|
||||||
-- Coordinate array.
|
-- Coordinate array. Pene Testing extended Abeam landing spot V/STOL.
|
||||||
local p={}
|
local p={}
|
||||||
|
|
||||||
-- Points.
|
-- Points.
|
||||||
@@ -10640,7 +10779,7 @@ function AIRBOSS:_GetZoneHolding( case, stack )
|
|||||||
self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", Post:GetVec2(), self.marshalradius )
|
self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", Post:GetVec2(), self.marshalradius )
|
||||||
|
|
||||||
-- Delta pattern.
|
-- Delta pattern.
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", self.carrier:GetVec2(), UTILS.NMToMeters( 5 ) )
|
self.zoneHolding = ZONE_RADIUS:New( "CASE I Holding Zone", self.carrier:GetVec2(), UTILS.NMToMeters( 5 ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -10692,7 +10831,7 @@ function AIRBOSS:_GetZoneCommence( case, stack )
|
|||||||
-- Three position
|
-- Three position
|
||||||
local Three = self:GetCoordinate():Translate( D, hdg + 275 )
|
local Three = self:GetCoordinate():Translate( D, hdg + 275 )
|
||||||
|
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
local Dx = UTILS.NMToMeters( 2.25 )
|
local Dx = UTILS.NMToMeters( 2.25 )
|
||||||
|
|
||||||
@@ -10983,7 +11122,7 @@ function AIRBOSS:_GetAltCarrier( unit )
|
|||||||
return h
|
return h
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get optimal landing position of the aircraft. Usually between second and third wire. In case of Tarawa and America we take the abeam landing spot 120 ft abeam the 7.5 position, for the Juan Carlos I it is 120 ft and abeam the 5 position.
|
--- Get optimal landing position of the aircraft. Usually between second and third wire. In case of Tarawa, Canberrra, Juan Carlos and America we take the abeam landing spot 120 ft above and 21 ft abeam the 7.5 position, for the Juan Carlos I, HMS Invincible, and HMS Hermes and Invincible it is 120 ft above and 21 ft abeam the 5 position. For CASE III it is 120ft directly above the landing spot.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @return Core.Point#COORDINATE Optimal landing coordinate.
|
-- @return Core.Point#COORDINATE Optimal landing coordinate.
|
||||||
function AIRBOSS:_GetOptLandingCoordinate()
|
function AIRBOSS:_GetOptLandingCoordinate()
|
||||||
@@ -10993,44 +11132,27 @@ function AIRBOSS:_GetOptLandingCoordinate()
|
|||||||
|
|
||||||
-- Stern coordinate.
|
-- Stern coordinate.
|
||||||
-- local stern=self:_GetSternCoord()
|
-- local stern=self:_GetSternCoord()
|
||||||
|
|
||||||
-- Final bearing.
|
-- Final bearing.
|
||||||
|
|
||||||
local FB=self:GetFinalBearing(false)
|
local FB=self:GetFinalBearing(false)
|
||||||
|
local case=self.case
|
||||||
|
-- set Case III V/STOL abeam landing spot over deck -- Pene Testing
|
||||||
|
if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then
|
||||||
|
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA then
|
if case==3 then
|
||||||
|
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate())
|
||||||
|
-- Altitude 120ft -- is this corect for Case III?
|
||||||
|
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
|
||||||
|
|
||||||
|
elseif case==2 or case==1 then
|
||||||
|
|
||||||
-- Landing 100 ft abeam, 120 ft alt.
|
-- Landing 100 ft abeam, 120 ft alt.
|
||||||
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()):Translate(35, FB-90, true, true)
|
self.landingcoord:UpdateFromCoordinate(self:_GetLandingSpotCoordinate()):Translate(35, FB-90, true, true)
|
||||||
--stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90)
|
--stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90)
|
||||||
|
|
||||||
-- Alitude 120 ft.
|
-- Atlitude 120 ft.
|
||||||
self.landingcoord:SetAltitude( UTILS.FeetToMeters( 120 ) )
|
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.AMERICA then
|
|
||||||
|
|
||||||
-- Landing 100 ft abeam, 120 ft alt. To allow adjustments to match different deck configurations.
|
|
||||||
self.landingcoord:UpdateFromCoordinate( self:_GetLandingSpotCoordinate() ):Translate( 35, FB - 90, true, true )
|
|
||||||
-- stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90)
|
|
||||||
|
|
||||||
-- Alitude 120 ft.
|
|
||||||
self.landingcoord:SetAltitude( UTILS.FeetToMeters( 120 ) )
|
|
||||||
|
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.JCARLOS then
|
|
||||||
|
|
||||||
-- Landing 100 ft abeam, 120 ft alt.
|
|
||||||
self.landingcoord:UpdateFromCoordinate( self:_GetLandingSpotCoordinate() ):Translate( 35, FB - 90, true, true )
|
|
||||||
-- stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90)
|
|
||||||
|
|
||||||
-- Alitude 120 ft.
|
|
||||||
self.landingcoord:SetAltitude( UTILS.FeetToMeters( 120 ) )
|
|
||||||
|
|
||||||
elseif self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
|
||||||
|
|
||||||
-- Landing 100 ft abeam, 120 ft alt.
|
|
||||||
self.landingcoord:UpdateFromCoordinate( self:_GetLandingSpotCoordinate() ):Translate( 35, FB - 90, true, true )
|
|
||||||
-- stern=self:_GetLandingSpotCoordinate():Translate(35, FB-90)
|
|
||||||
|
|
||||||
-- Alitude 120 ft.
|
|
||||||
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
|
self.landingcoord:SetAltitude(UTILS.FeetToMeters(120))
|
||||||
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -11059,7 +11181,21 @@ function AIRBOSS:_GetLandingSpotCoordinate()
|
|||||||
-- Stern coordinate.
|
-- Stern coordinate.
|
||||||
-- local stern=self:_GetSternCoord()
|
-- local stern=self:_GetSternCoord()
|
||||||
|
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA then
|
if self.carriertype==AIRBOSS.CarrierType.HERMES then
|
||||||
|
|
||||||
|
-- Landing 100 ft abeam, 100 alt.
|
||||||
|
local hdg = self:GetHeading()
|
||||||
|
|
||||||
|
-- Primary landing spot 5
|
||||||
|
self.landingspotcoord:Translate( 69, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.INVINCIBLE then
|
||||||
|
|
||||||
|
-- Using spot 3 as the default
|
||||||
|
local hdg = self:GetHeading()
|
||||||
|
|
||||||
|
self.landingspotcoord:Translate( 69, hdg, true, true ):SetAltitude( self.carrierparam.deckheight )
|
||||||
|
-- This location looks good.
|
||||||
|
elseif self.carriertype == AIRBOSS.CarrierType.TARAWA then
|
||||||
|
|
||||||
-- Landing 100 ft abeam, 120 alt.
|
-- Landing 100 ft abeam, 120 alt.
|
||||||
local hdg = self:GetHeading()
|
local hdg = self:GetHeading()
|
||||||
@@ -11127,7 +11263,7 @@ end
|
|||||||
|
|
||||||
--- Get wind direction and speed at carrier position.
|
--- Get wind direction and speed at carrier position.
|
||||||
-- @param #AIRBOSS self
|
-- @param #AIRBOSS self
|
||||||
-- @param #number alt Altitude ASL in meters. Default 50 m.
|
-- @param #number alt Altitude ASL in meters. Default 15 m.
|
||||||
-- @param #boolean magnetic Direction including magnetic declination.
|
-- @param #boolean magnetic Direction including magnetic declination.
|
||||||
-- @param Core.Point#COORDINATE coord (Optional) Coordinate at which to get the wind. Default is current carrier position.
|
-- @param Core.Point#COORDINATE coord (Optional) Coordinate at which to get the wind. Default is current carrier position.
|
||||||
-- @return #number Direction the wind is blowing **from** in degrees.
|
-- @return #number Direction the wind is blowing **from** in degrees.
|
||||||
@@ -11137,8 +11273,8 @@ function AIRBOSS:GetWind( alt, magnetic, coord )
|
|||||||
-- Current position of the carrier or input.
|
-- Current position of the carrier or input.
|
||||||
local cv = coord or self:GetCoordinate()
|
local cv = coord or self:GetCoordinate()
|
||||||
|
|
||||||
-- Wind direction and speed. By default at 50 meters ASL.
|
-- Wind direction and speed. By default at 15 meters ASL.
|
||||||
local Wdir, Wspeed = cv:GetWind( alt or 50 )
|
local Wdir, Wspeed = cv:GetWind( alt or 15 )
|
||||||
|
|
||||||
-- Include magnetic declination.
|
-- Include magnetic declination.
|
||||||
if magnetic then
|
if magnetic then
|
||||||
@@ -11650,11 +11786,13 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
|
|
||||||
-- Count number of minor, normal and major deviations.
|
-- Count number of minor, normal and major deviations.
|
||||||
local N=nXX+nIM+nIC+nAR
|
local N=nXX+nIM+nIC+nAR
|
||||||
|
local Nv=nXX+nIM
|
||||||
local nL=count(G, '_')/2
|
local nL=count(G, '_')/2
|
||||||
local nS=count(G, '%(')
|
local nS=count(G, '%(')
|
||||||
local nN=N-nS-nL
|
local nN=N-nS-nL
|
||||||
|
local nNv=Nv-nS-nL
|
||||||
|
|
||||||
-- Groove time 15-18.99 sec for a unicorn. Or 65-70 for V/STOL unicorn.
|
-- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn.
|
||||||
local Tgroove=playerData.Tgroove
|
local Tgroove=playerData.Tgroove
|
||||||
local TgrooveUnicorn=Tgroove and (Tgroove>=15.0 and Tgroove<=18.99) or false
|
local TgrooveUnicorn=Tgroove and (Tgroove>=15.0 and Tgroove<=18.99) or false
|
||||||
local TgrooveVstolUnicorn=Tgroove and (Tgroove>=60.0 and Tgroove<=65.0)and playerData.actype==AIRBOSS.AircraftCarrier.AV8B or false
|
local TgrooveVstolUnicorn=Tgroove and (Tgroove>=60.0 and Tgroove<=65.0)and playerData.actype==AIRBOSS.AircraftCarrier.AV8B or false
|
||||||
@@ -11668,16 +11806,20 @@ function AIRBOSS:_LSOgrade( playerData )
|
|||||||
G = "Unicorn"
|
G = "Unicorn"
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Add AV-8B Harrier devation allowances due to lower groundspeed and 3x conventional groove time, this allows to maintain LSO tolerances while respecting the deviations are not unsafe. (WIP requires feedback)
|
-- Add AV-8B Harrier devation allowances due to lower groundspeed and 3x conventional groove time, this allows to maintain LSO tolerances while respecting the deviations are not unsafe.--Pene testing
|
||||||
-- Large devaitions still result in a No Grade, A Unicorn still requires a clean pass with no deviation.
|
-- Large devaitions still result in a No Grade, A Unicorn still requires a clean pass with no deviation.
|
||||||
if nL > 3 and playerData.actype == AIRBOSS.AircraftCarrier.AV8B then
|
if nL > 1 and playerData.actype==AIRBOSS.AircraftCarrier.AV8B then
|
||||||
-- Larger deviations ==> "No grade" 2.0 points.
|
-- Larger deviations ==> "No grade" 2.0 points.
|
||||||
grade="--"
|
grade="--"
|
||||||
points=2.0
|
points=2.0
|
||||||
elseif nN > 2 and playerData.actype == AIRBOSS.AircraftCarrier.AV8B then
|
elseif nNv >= 1 and playerData.actype==AIRBOSS.AircraftCarrier.AV8B then
|
||||||
-- Only average deviations ==> "Fair Pass" Pass with average deviations and corrections.
|
-- Only average deviations ==> "Fair Pass" Pass with average deviations and corrections.
|
||||||
grade="(OK)"
|
grade="(OK)"
|
||||||
points=3.0
|
points=3.0
|
||||||
|
elseif nNv < 1 and playerData.actype==AIRBOSS.AircraftCarrier.AV8B then
|
||||||
|
-- Only minor average deviations ==> "OK" Pass with minor deviations and corrections. (test nNv<=1 and)
|
||||||
|
grade="OK"
|
||||||
|
points=4.0
|
||||||
elseif nL > 0 then
|
elseif nL > 0 then
|
||||||
-- Larger deviations ==> "No grade" 2.0 points.
|
-- Larger deviations ==> "No grade" 2.0 points.
|
||||||
grade="--"
|
grade="--"
|
||||||
@@ -11994,7 +12136,7 @@ function AIRBOSS:_GS( step, n )
|
|||||||
if n == -1 then
|
if n == -1 then
|
||||||
gp = AIRBOSS.GroovePos.IC
|
gp = AIRBOSS.GroovePos.IC
|
||||||
elseif n == 1 then
|
elseif n == 1 then
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
gp = AIRBOSS.GroovePos.AL
|
gp = AIRBOSS.GroovePos.AL
|
||||||
else
|
else
|
||||||
gp = AIRBOSS.GroovePos.IW
|
gp = AIRBOSS.GroovePos.IW
|
||||||
@@ -13873,7 +14015,7 @@ function AIRBOSS:_IsCarrierAircraft( unit )
|
|||||||
|
|
||||||
-- Special case for Harrier which can only land on Tarawa, LHA and LHD.
|
-- Special case for Harrier which can only land on Tarawa, LHA and LHD.
|
||||||
if aircrafttype == AIRBOSS.AircraftCarrier.AV8B then
|
if aircrafttype == AIRBOSS.AircraftCarrier.AV8B then
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
@@ -13881,7 +14023,7 @@ function AIRBOSS:_IsCarrierAircraft( unit )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Also only Harriers can land on the Tarawa, LHA and LHD.
|
-- Also only Harriers can land on the Tarawa, LHA and LHD.
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
if aircrafttype ~= AIRBOSS.AircraftCarrier.AV8B then
|
if aircrafttype ~= AIRBOSS.AircraftCarrier.AV8B then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -17238,7 +17380,7 @@ function AIRBOSS:_MarkCaseZones( _unitName, flare )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Tarawa, LHA and LHD landing spots.
|
-- Tarawa, LHA and LHD landing spots.
|
||||||
if self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then
|
||||||
text = text .. "\n* abeam landing stop with RED flares"
|
text = text .. "\n* abeam landing stop with RED flares"
|
||||||
-- Abeam landing spot zone.
|
-- Abeam landing spot zone.
|
||||||
local ALSPT = self:_GetZoneAbeamLandingSpot()
|
local ALSPT = self:_GetZoneAbeamLandingSpot()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+1133
-213
File diff suppressed because it is too large
Load Diff
@@ -45,14 +45,13 @@
|
|||||||
-- @field Core.Point#COORDINATE coordinate Coordinate from where the transmission is send.
|
-- @field Core.Point#COORDINATE coordinate Coordinate from where the transmission is send.
|
||||||
-- @field #string path Path to the SRS exe. This includes the final slash "/".
|
-- @field #string path Path to the SRS exe. This includes the final slash "/".
|
||||||
-- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json".
|
-- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json".
|
||||||
|
-- @field #string Label Label showing up on the SRS radio overlay. Default is "ROBOT". No spaces allowed.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # The MSRS Concept
|
-- # The MSRS Concept
|
||||||
--
|
--
|
||||||
-- This class allows to broadcast sound files or text via Simple Radio Standalone (SRS).
|
-- This class allows to broadcast sound files or text via Simple Radio Standalone (SRS).
|
||||||
@@ -95,6 +94,14 @@
|
|||||||
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
|
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
|
||||||
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
|
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
|
||||||
--
|
--
|
||||||
|
-- **NOTE on using GOOGLE TTS with SRS:** You need to have the C# library installed in your SRS folder for Google to work.
|
||||||
|
-- You can obtain it e.g. here: [NuGet](https://www.nuget.org/packages/Grpc.Core)
|
||||||
|
--
|
||||||
|
-- **Pro-Tipp** - use the command line with power shell to call DCS-SR-ExternalAudio.exe - it will tell you what is missing.
|
||||||
|
-- and also the Google Console error, in case you have missed a step in setting up your Google TTS.
|
||||||
|
-- E.g. `.\DCS-SR-ExternalAudio.exe -t "Text Message" -f 255 -m AM -c 2 -s 2 -z -G "Path_To_You_Google.Json"`
|
||||||
|
-- Plays a message on 255AM for the blue coalition in-game.
|
||||||
|
--
|
||||||
-- ## Set Voice
|
-- ## Set Voice
|
||||||
--
|
--
|
||||||
-- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
|
-- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
|
||||||
@@ -106,6 +113,14 @@
|
|||||||
--
|
--
|
||||||
-- Use @{#MSRS.SetCoordinate} to define the origin from where the transmission is broadcasted.
|
-- Use @{#MSRS.SetCoordinate} to define the origin from where the transmission is broadcasted.
|
||||||
--
|
--
|
||||||
|
-- ## Set SRS Port
|
||||||
|
--
|
||||||
|
-- Use @{#MSRS.SetPort} to define the SRS port. Defaults to 5002.
|
||||||
|
--
|
||||||
|
-- ## Set SRS Volume
|
||||||
|
--
|
||||||
|
-- Use @{#MSRS.SetVolume} to define the SRS volume. Defaults to 1.0. Allowed values are between 0.0 and 1.0, from silent to loudest.
|
||||||
|
--
|
||||||
-- @field #MSRS
|
-- @field #MSRS
|
||||||
MSRS = {
|
MSRS = {
|
||||||
ClassName = "MSRS",
|
ClassName = "MSRS",
|
||||||
@@ -121,11 +136,12 @@ MSRS = {
|
|||||||
volume = 1,
|
volume = 1,
|
||||||
speed = 1,
|
speed = 1,
|
||||||
coordinate = nil,
|
coordinate = nil,
|
||||||
|
Label = "ROBOT",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- MSRS class version.
|
--- MSRS class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
MSRS.version="0.0.3"
|
MSRS.version="0.1.0"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -144,8 +160,9 @@ MSRS.version="0.0.3"
|
|||||||
-- @param #string PathToSRS Path to the directory, where SRS is located.
|
-- @param #string PathToSRS Path to the directory, where SRS is located.
|
||||||
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies.
|
-- @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 #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 #number Volume Volume - 1.0 is max, 0.0 is silence
|
||||||
-- @return #MSRS self
|
-- @return #MSRS self
|
||||||
function MSRS:New(PathToSRS, Frequency, Modulation)
|
function MSRS:New(PathToSRS, Frequency, Modulation, Volume)
|
||||||
|
|
||||||
-- Defaults.
|
-- Defaults.
|
||||||
Frequency =Frequency or 143
|
Frequency =Frequency or 143
|
||||||
@@ -160,6 +177,13 @@ function MSRS:New(PathToSRS, Frequency, Modulation)
|
|||||||
self:SetModulations(Modulation)
|
self:SetModulations(Modulation)
|
||||||
self:SetGender()
|
self:SetGender()
|
||||||
self:SetCoalition()
|
self:SetCoalition()
|
||||||
|
self:SetLabel()
|
||||||
|
self:SetVolume()
|
||||||
|
self.lid = string.format("%s-%s | ", self.name, self.version)
|
||||||
|
|
||||||
|
if not io or not os then
|
||||||
|
self:E(self.lid.."***** ERROR - io or os NOT desanitized! MSRS will not work!")
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -202,12 +226,47 @@ function MSRS:GetPath()
|
|||||||
return self.path
|
return self.path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set SRS volume.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #number Volume Volume - 1.0 is max, 0.0 is silence
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:SetVolume(Volume)
|
||||||
|
local volume = Volume or 1
|
||||||
|
if volume > 1 then volume = 1 elseif volume < 0 then volume = 0 end
|
||||||
|
self.volume = volume
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get SRS volume.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @return #number Volume Volume - 1.0 is max, 0.0 is silence
|
||||||
|
function MSRS:GetVolume()
|
||||||
|
return self.volume
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set label.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #number Label. Default "ROBOT"
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:SetLabel(Label)
|
||||||
|
self.Label=Label or "ROBOT"
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get label.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @return #number Label.
|
||||||
|
function MSRS:GetLabel()
|
||||||
|
return self.Label
|
||||||
|
end
|
||||||
|
|
||||||
--- Set port.
|
--- Set port.
|
||||||
-- @param #MSRS self
|
-- @param #MSRS self
|
||||||
-- @param #number Port Port. Default 5002.
|
-- @param #number Port Port. Default 5002.
|
||||||
-- @return #MSRS self
|
-- @return #MSRS self
|
||||||
function MSRS:SetPort(Port)
|
function MSRS:SetPort(Port)
|
||||||
self.port=Port or 5002
|
self.port=Port or 5002
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get port.
|
--- Get port.
|
||||||
@@ -223,6 +282,7 @@ end
|
|||||||
-- @return #MSRS self
|
-- @return #MSRS self
|
||||||
function MSRS:SetCoalition(Coalition)
|
function MSRS:SetCoalition(Coalition)
|
||||||
self.coalition=Coalition or 0
|
self.coalition=Coalition or 0
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get coalition.
|
--- Get coalition.
|
||||||
@@ -391,22 +451,11 @@ function MSRS:PlaySoundFile(Soundfile, Delay)
|
|||||||
local command=self:_GetCommand()
|
local command=self:_GetCommand()
|
||||||
|
|
||||||
-- Append file.
|
-- Append file.
|
||||||
command=command.." --file="..tostring(soundfile)
|
command=command..' --file="'..tostring(soundfile)..'"'
|
||||||
|
|
||||||
|
-- Execute command.
|
||||||
self:_ExecCommand(command)
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
command=command.." > bla.txt"
|
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
self:I(string.format("MSRS PlaySoundfile command=%s", command))
|
|
||||||
|
|
||||||
-- Execute SRS command.
|
|
||||||
local x=os.execute(command)
|
|
||||||
|
|
||||||
]]
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -432,16 +481,6 @@ function MSRS:PlaySoundText(SoundText, Delay)
|
|||||||
-- Execute command.
|
-- Execute command.
|
||||||
self:_ExecCommand(command)
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
--[[
|
|
||||||
command=command.." > bla.txt"
|
|
||||||
|
|
||||||
-- Debug putput.
|
|
||||||
self:I(string.format("MSRS PlaySoundfile command=%s", command))
|
|
||||||
|
|
||||||
-- Execute SRS command.
|
|
||||||
local x=os.execute(command)
|
|
||||||
]]
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -467,37 +506,48 @@ function MSRS:PlayText(Text, Delay)
|
|||||||
-- Execute command.
|
-- Execute command.
|
||||||
self:_ExecCommand(command)
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
-- Check that length of command is max 255 chars or os.execute() will not work!
|
|
||||||
if string.len(command)>255 then
|
|
||||||
|
|
||||||
-- Create a tmp file.
|
|
||||||
local filename = os.getenv('TMP') .. "\\MSRS-"..STTS.uuid()..".bat"
|
|
||||||
|
|
||||||
local script = io.open(filename, "w+")
|
|
||||||
script:write(command.." && exit")
|
|
||||||
script:close()
|
|
||||||
|
|
||||||
-- Play command.
|
|
||||||
command=string.format("\"%s\"", filename)
|
|
||||||
|
|
||||||
-- Play file in 0.05 seconds
|
|
||||||
timer.scheduleFunction(os.execute, command, timer.getTime()+0.05)
|
|
||||||
|
|
||||||
-- Remove file in 1 second.
|
|
||||||
timer.scheduleFunction(os.remove, filename, timer.getTime()+1)
|
|
||||||
else
|
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
self:I(string.format("MSRS Text command=%s", command))
|
|
||||||
|
|
||||||
-- Execute SRS command.
|
|
||||||
local x=os.execute(command)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
]]
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Play text message via STTS with explicitly specified options.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #string Text Text message.
|
||||||
|
-- @param #number Delay Delay in seconds, before the message is played.
|
||||||
|
-- @param #table Frequencies Radio frequencies.
|
||||||
|
-- @param #table Modulations Radio modulations.
|
||||||
|
-- @param #string Gender Gender.
|
||||||
|
-- @param #string Culture Culture.
|
||||||
|
-- @param #string Voice Voice.
|
||||||
|
-- @param #number Volume Volume.
|
||||||
|
-- @param #string Label Label.
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MSRS.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Ensure table.
|
||||||
|
if Frequencies and type(Frequencies)~="table" then
|
||||||
|
Frequencies={Frequencies}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure table.
|
||||||
|
if Modulations and type(Modulations)~="table" then
|
||||||
|
Modulations={Modulations}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get command line.
|
||||||
|
local command=self:_GetCommand(Frequencies, Modulations, nil, Gender, Voice, Culture, Volume, nil, nil, Label)
|
||||||
|
|
||||||
|
-- Append text.
|
||||||
|
command=command..string.format(" --text=\"%s\"", tostring(Text))
|
||||||
|
|
||||||
|
-- Execute command.
|
||||||
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -634,8 +684,9 @@ end
|
|||||||
-- @param #number volume Volume.
|
-- @param #number volume Volume.
|
||||||
-- @param #number speed Speed.
|
-- @param #number speed Speed.
|
||||||
-- @param #number port Port.
|
-- @param #number port Port.
|
||||||
|
-- @param #string label Label, defaults to "ROBOT" (displayed sender name in the radio overlay of SRS) - No spaces allowed!
|
||||||
-- @return #string Command.
|
-- @return #string Command.
|
||||||
function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port)
|
function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port,label)
|
||||||
|
|
||||||
local path=self:GetPath() or STTS.DIRECTORY
|
local path=self:GetPath() or STTS.DIRECTORY
|
||||||
local exe=STTS.EXECUTABLE or "DCS-SR-ExternalAudio.exe"
|
local exe=STTS.EXECUTABLE or "DCS-SR-ExternalAudio.exe"
|
||||||
@@ -648,6 +699,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
|||||||
volume=volume or self.volume
|
volume=volume or self.volume
|
||||||
speed=speed or self.speed
|
speed=speed or self.speed
|
||||||
port=port or self.port
|
port=port or self.port
|
||||||
|
label=label or self.Label
|
||||||
|
|
||||||
-- Replace modulation
|
-- Replace modulation
|
||||||
modus=modus:gsub("0", "AM")
|
modus=modus:gsub("0", "AM")
|
||||||
@@ -657,12 +709,12 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
|||||||
--local command=string.format("%s --freqs=%s --modulations=%s --coalition=%d --port=%d --volume=%.2f --speed=%d", exe, freqs, modus, coal, port, volume, speed)
|
--local command=string.format("%s --freqs=%s --modulations=%s --coalition=%d --port=%d --volume=%.2f --speed=%d", exe, freqs, modus, coal, port, volume, speed)
|
||||||
|
|
||||||
-- Command from orig STTS script. Works better for some unknown reason!
|
-- Command from orig STTS script. Works better for some unknown reason!
|
||||||
local command=string.format("start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", path, exe, freqs, modus, coal, port, "ROBOT")
|
--local command=string.format("start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", path, exe, freqs, modus, coal, port, "ROBOT")
|
||||||
|
|
||||||
--local command=string.format('start /b "" /d "%s" "%s" -f %s -m %s -c %s -p %s -n "%s" > bla.txt', path, exe, freqs, modus, coal, port, "ROBOT")
|
--local command=string.format('start /b "" /d "%s" "%s" -f %s -m %s -c %s -p %s -n "%s" > bla.txt', path, exe, freqs, modus, coal, port, "ROBOT")
|
||||||
|
|
||||||
-- Command.
|
-- Command.
|
||||||
local command=string.format('%s/%s -f %s -m %s -c %s -p %s -n "%s"', path, exe, freqs, modus, coal, port, "ROBOT")
|
local command=string.format('"%s\\%s" -f %s -m %s -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume)
|
||||||
|
|
||||||
-- Set voice or gender/culture.
|
-- Set voice or gender/culture.
|
||||||
if voice then
|
if voice then
|
||||||
@@ -671,7 +723,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
|||||||
else
|
else
|
||||||
-- Add gender.
|
-- Add gender.
|
||||||
if gender and gender~="female" then
|
if gender and gender~="female" then
|
||||||
command=command..string.format(" --gender=%s", tostring(gender))
|
command=command..string.format(" -g %s", tostring(gender))
|
||||||
end
|
end
|
||||||
-- Add culture.
|
-- Add culture.
|
||||||
if culture and culture~="en-GB" then
|
if culture and culture~="en-GB" then
|
||||||
@@ -696,6 +748,353 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
|||||||
return command
|
return command
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Manages radio transmissions.
|
||||||
|
--
|
||||||
|
-- The purpose of the MSRSQUEUE class is to manage SRS text-to-speech (TTS) messages using the MSRS class.
|
||||||
|
-- This can be used to submit multiple TTS messages and the class takes care that they are transmitted one after the other (and not overlapping).
|
||||||
|
--
|
||||||
|
-- @type MSRSQUEUE
|
||||||
|
-- @field #string ClassName Name of the class "MSRSQUEUE".
|
||||||
|
-- @field #string lid ID for dcs.log.
|
||||||
|
-- @field #table queue The queue of transmissions.
|
||||||
|
-- @field #string alias Name of the radio queue.
|
||||||
|
-- @field #number dt Time interval in seconds for checking the radio queue.
|
||||||
|
-- @field #number Tlast Time (abs) when the last transmission finished.
|
||||||
|
-- @field #boolean checking If `true`, the queue update function is scheduled to be called again.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
MSRSQUEUE = {
|
||||||
|
ClassName = "MSRSQUEUE",
|
||||||
|
Debugmode = nil,
|
||||||
|
lid = nil,
|
||||||
|
queue = {},
|
||||||
|
alias = nil,
|
||||||
|
dt = nil,
|
||||||
|
Tlast = nil,
|
||||||
|
checking = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Radio queue transmission data.
|
||||||
|
-- @type MSRSQUEUE.Transmission
|
||||||
|
-- @field #string text Text to be transmitted.
|
||||||
|
-- @field Sound.SRS#MSRS msrs MOOSE SRS object.
|
||||||
|
-- @field #number duration Duration in seconds.
|
||||||
|
-- @field #table subgroups Groups to send subtitle to.
|
||||||
|
-- @field #string subtitle Subtitle of the transmission.
|
||||||
|
-- @field #number subduration Duration of the subtitle being displayed.
|
||||||
|
-- @field #number frequency Frequency.
|
||||||
|
-- @field #number modulation Modulation.
|
||||||
|
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
||||||
|
-- @field #boolean isplaying If true, transmission is currently playing.
|
||||||
|
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
||||||
|
-- @field #number interval Interval in seconds before next transmission.
|
||||||
|
|
||||||
|
--- Create a new MSRSQUEUE object for a given radio frequency/modulation.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #string alias (Optional) Name of the radio queue.
|
||||||
|
-- @return #MSRSQUEUE self The MSRSQUEUE object.
|
||||||
|
function MSRSQUEUE:New(alias)
|
||||||
|
|
||||||
|
-- Inherit base
|
||||||
|
local self=BASE:Inherit(self, BASE:New()) --#MSRSQUEUE
|
||||||
|
|
||||||
|
self.alias=alias or "My Radio"
|
||||||
|
|
||||||
|
self.dt=1.0
|
||||||
|
|
||||||
|
self.lid=string.format("MSRSQUEUE %s | ", self.alias)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Clear the radio queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @return #MSRSQUEUE self The MSRSQUEUE object.
|
||||||
|
function MSRSQUEUE:Clear()
|
||||||
|
self:I(self.lid.."Clearning MSRSQUEUE")
|
||||||
|
self.queue={}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a transmission to the radio queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #MSRSQUEUE.Transmission transmission The transmission data table.
|
||||||
|
-- @return #MSRSQUEUE self
|
||||||
|
function MSRSQUEUE:AddTransmission(transmission)
|
||||||
|
|
||||||
|
-- Init.
|
||||||
|
transmission.isplaying=false
|
||||||
|
transmission.Tstarted=nil
|
||||||
|
|
||||||
|
-- Add to queue.
|
||||||
|
table.insert(self.queue, transmission)
|
||||||
|
|
||||||
|
-- Start checking.
|
||||||
|
if not self.checking then
|
||||||
|
self:_CheckRadioQueue()
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a new transmission and add it to the radio queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #string text Text to play.
|
||||||
|
-- @param #number duration Duration in seconds the file lasts. Default is determined by number of characters of the text message.
|
||||||
|
-- @param Sound.SRS#MSRS msrs MOOSE SRS object.
|
||||||
|
-- @param #number tstart Start time (abs) seconds. Default now.
|
||||||
|
-- @param #number interval Interval in seconds after the last transmission finished.
|
||||||
|
-- @param #table subgroups Groups that should receive the subtiltle.
|
||||||
|
-- @param #string subtitle Subtitle displayed when the message is played.
|
||||||
|
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
|
||||||
|
-- @param #number frequency Radio frequency if other than MSRS default.
|
||||||
|
-- @param #number modulation Radio modulation if other then MSRS default.
|
||||||
|
-- @return #MSRSQUEUE.Transmission Radio transmission table.
|
||||||
|
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation)
|
||||||
|
|
||||||
|
-- Sanity checks.
|
||||||
|
if not text then
|
||||||
|
self:E(self.lid.."ERROR: No text specified.")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if type(text)~="string" then
|
||||||
|
self:E(self.lid.."ERROR: Text specified is NOT a string.")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Create a new transmission object.
|
||||||
|
local transmission={} --#MSRSQUEUE.Transmission
|
||||||
|
transmission.text=text
|
||||||
|
transmission.duration=duration or STTS.getSpeechTime(text)
|
||||||
|
transmission.msrs=msrs
|
||||||
|
transmission.Tplay=tstart or timer.getAbsTime()
|
||||||
|
transmission.subtitle=subtitle
|
||||||
|
transmission.interval=interval or 0
|
||||||
|
transmission.frequency=frequency
|
||||||
|
transmission.modulation=modulation
|
||||||
|
transmission.subgroups=subgroups
|
||||||
|
if transmission.subtitle then
|
||||||
|
transmission.subduration=subduration or transmission.duration
|
||||||
|
else
|
||||||
|
transmission.subduration=0 --nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add transmission to queue.
|
||||||
|
self:AddTransmission(transmission)
|
||||||
|
|
||||||
|
return transmission
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Broadcast radio message.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #MSRSQUEUE.Transmission transmission The transmission.
|
||||||
|
function MSRSQUEUE:Broadcast(transmission)
|
||||||
|
|
||||||
|
if transmission.frequency then
|
||||||
|
transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, Gender, Culture, Voice, Volume, Label)
|
||||||
|
else
|
||||||
|
transmission.msrs:PlayText(transmission.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function texttogroup(gid)
|
||||||
|
-- Text to group.
|
||||||
|
trigger.action.outTextForGroup(gid, transmission.subtitle, transmission.subduration, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
if transmission.subgroups and #transmission.subgroups>0 then
|
||||||
|
|
||||||
|
for _,_group in pairs(transmission.subgroups) do
|
||||||
|
local group=_group --Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
if group and group:IsAlive() then
|
||||||
|
local gid=group:GetID()
|
||||||
|
|
||||||
|
self:ScheduleOnce(4, texttogroup, gid)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculate total transmission duration of all transmission in the queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @return #number Total transmission duration.
|
||||||
|
function MSRSQUEUE:CalcTransmisstionDuration()
|
||||||
|
|
||||||
|
local Tnow=timer.getAbsTime()
|
||||||
|
|
||||||
|
local T=0
|
||||||
|
for _,_transmission in pairs(self.queue) do
|
||||||
|
local transmission=_transmission --#MSRSQUEUE.Transmission
|
||||||
|
|
||||||
|
if transmission.isplaying then
|
||||||
|
|
||||||
|
-- Playing for dt seconds.
|
||||||
|
local dt=Tnow-transmission.Tstarted
|
||||||
|
|
||||||
|
T=T+transmission.duration-dt
|
||||||
|
|
||||||
|
else
|
||||||
|
T=T+transmission.duration
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return T
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check radio queue for transmissions to be broadcasted.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #number delay Delay in seconds before checking.
|
||||||
|
function MSRSQUEUE:_CheckRadioQueue(delay)
|
||||||
|
|
||||||
|
-- Transmissions in queue.
|
||||||
|
local N=#self.queue
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T2(self.lid..string.format("Check radio queue %s: delay=%.3f sec, N=%d, checking=%s", self.alias, delay or 0, N, tostring(self.checking)))
|
||||||
|
|
||||||
|
if delay and delay>0 then
|
||||||
|
|
||||||
|
-- Delayed call.
|
||||||
|
self:ScheduleOnce(delay, MSRSQUEUE._CheckRadioQueue, self)
|
||||||
|
|
||||||
|
-- Checking on.
|
||||||
|
self.checking=true
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Check if queue is empty.
|
||||||
|
if N==0 then
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
|
||||||
|
|
||||||
|
-- Queue is now empty. Nothing to else to do. We start checking again, if a transmission is added.
|
||||||
|
self.checking=false
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get current abs time.
|
||||||
|
local time=timer.getAbsTime()
|
||||||
|
|
||||||
|
-- Checking on.
|
||||||
|
self.checking=true
|
||||||
|
|
||||||
|
-- Set dt.
|
||||||
|
local dt=self.dt
|
||||||
|
|
||||||
|
|
||||||
|
local playing=false
|
||||||
|
local next=nil --#MSRSQUEUE.Transmission
|
||||||
|
local remove=nil
|
||||||
|
for i,_transmission in ipairs(self.queue) do
|
||||||
|
local transmission=_transmission --#MSRSQUEUE.Transmission
|
||||||
|
|
||||||
|
-- Check if transmission time has passed.
|
||||||
|
if time>=transmission.Tplay then
|
||||||
|
|
||||||
|
-- Check if transmission is currently playing.
|
||||||
|
if transmission.isplaying then
|
||||||
|
|
||||||
|
-- Check if transmission is finished.
|
||||||
|
if time>=transmission.Tstarted+transmission.duration then
|
||||||
|
|
||||||
|
-- Transmission over.
|
||||||
|
transmission.isplaying=false
|
||||||
|
|
||||||
|
-- Remove ith element in queue.
|
||||||
|
remove=i
|
||||||
|
|
||||||
|
-- Store time last transmission finished.
|
||||||
|
self.Tlast=time
|
||||||
|
|
||||||
|
else -- still playing
|
||||||
|
|
||||||
|
-- Transmission is still playing.
|
||||||
|
playing=true
|
||||||
|
|
||||||
|
dt=transmission.duration-(time-transmission.Tstarted)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else -- not playing yet
|
||||||
|
|
||||||
|
local Tlast=self.Tlast
|
||||||
|
|
||||||
|
if transmission.interval==nil then
|
||||||
|
|
||||||
|
-- Not playing ==> this will be next.
|
||||||
|
if next==nil then
|
||||||
|
next=transmission
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
if Tlast==nil or time-Tlast>=transmission.interval then
|
||||||
|
next=transmission
|
||||||
|
else
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
|
||||||
|
if next or Tlast then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Transmission not due yet.
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Found a new transmission.
|
||||||
|
if next~=nil and not playing then
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Broadcasting text=\"%s\" at T=%.3f", next.text, time))
|
||||||
|
|
||||||
|
-- Call SRS.
|
||||||
|
self:Broadcast(next)
|
||||||
|
|
||||||
|
next.isplaying=true
|
||||||
|
next.Tstarted=time
|
||||||
|
dt=next.duration
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove completed call from queue.
|
||||||
|
if remove then
|
||||||
|
-- Remove from queue.
|
||||||
|
table.remove(self.queue, remove)
|
||||||
|
N=N-1
|
||||||
|
|
||||||
|
-- Check if queue is empty.
|
||||||
|
if #self.queue==0 then
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
|
||||||
|
|
||||||
|
self.checking=false
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check queue.
|
||||||
|
self:_CheckRadioQueue(dt)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -183,13 +183,17 @@ do -- Sound File
|
|||||||
|
|
||||||
--- Set path, where the sound file is located.
|
--- Set path, where the sound file is located.
|
||||||
-- @param #SOUNDFILE self
|
-- @param #SOUNDFILE self
|
||||||
-- @param #string Path Path to the directory, where the sound file is located.
|
-- @param #string Path Path to the directory, where the sound file is located. In case this is nil, it defaults to the DCS mission temp directory.
|
||||||
-- @return #SOUNDFILE self
|
-- @return #SOUNDFILE self
|
||||||
function SOUNDFILE:SetPath(Path)
|
function SOUNDFILE:SetPath(Path)
|
||||||
|
|
||||||
-- Init path.
|
-- Init path.
|
||||||
self.path=Path or "l10n/DEFAULT/"
|
self.path=Path or "l10n/DEFAULT/"
|
||||||
|
|
||||||
|
if not Path and self.useSRS then -- use path to mission temp dir
|
||||||
|
self.path = os.getenv('TMP') .. "\\DCS\\Mission\\l10n\\DEFAULT"
|
||||||
|
end
|
||||||
|
|
||||||
-- Remove (back)slashes.
|
-- Remove (back)slashes.
|
||||||
local nmax=1000 ; local n=1
|
local nmax=1000 ; local n=1
|
||||||
while (self.path:sub(-1)=="/" or self.path:sub(-1)==[[\]]) and n<=nmax do
|
while (self.path:sub(-1)=="/" or self.path:sub(-1)==[[\]]) and n<=nmax do
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ do -- UserSound
|
|||||||
-- @param #USERSOUND self
|
-- @param #USERSOUND self
|
||||||
-- @param #string UserSoundFileName The filename of the usersound.
|
-- @param #string UserSoundFileName The filename of the usersound.
|
||||||
-- @return #USERSOUND
|
-- @return #USERSOUND
|
||||||
function USERSOUND:New( UserSoundFileName ) --R2.3
|
function USERSOUND:New( UserSoundFileName )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
||||||
--
|
--
|
||||||
function USERSOUND:SetFileName( UserSoundFileName ) --R2.3
|
function USERSOUND:SetFileName( UserSoundFileName )
|
||||||
|
|
||||||
self.UserSoundFileName = UserSoundFileName
|
self.UserSoundFileName = UserSoundFileName
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToAll() --R2.3
|
function USERSOUND:ToAll()
|
||||||
|
|
||||||
trigger.action.outSound( self.UserSoundFileName )
|
trigger.action.outSound( self.UserSoundFileName )
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToCoalition( Coalition ) --R2.3
|
function USERSOUND:ToCoalition( Coalition )
|
||||||
|
|
||||||
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToCountry( Country ) --R2.3
|
function USERSOUND:ToCountry( Country )
|
||||||
|
|
||||||
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
||||||
|
|
||||||
@@ -123,9 +123,9 @@ do -- UserSound
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
||||||
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the sound that Blue has won to the player group.
|
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the victory sound to the player group.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToGroup( Group, Delay ) --R2.3
|
function USERSOUND:ToGroup( Group, Delay )
|
||||||
|
|
||||||
Delay=Delay or 0
|
Delay=Delay or 0
|
||||||
if Delay>0 then
|
if Delay>0 then
|
||||||
@@ -137,4 +137,26 @@ do -- UserSound
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Play the usersound to the given @{Wrapper.Unit}.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit The @{Wrapper.Unit} to play the usersound to.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the sound is played. Default 0.
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- local PlayerUnit = UNIT:FindByName( "PlayerUnit" ) -- Search for the active group named "PlayerUnit", a human player.
|
||||||
|
-- BlueVictory:ToUnit( PlayerUnit ) -- Play the victory sound to the player unit.
|
||||||
|
--
|
||||||
|
function USERSOUND:ToUnit( Unit, Delay )
|
||||||
|
|
||||||
|
Delay=Delay or 0
|
||||||
|
if Delay>0 then
|
||||||
|
SCHEDULER:New(nil, USERSOUND.ToUnit,{self, Unit}, Delay)
|
||||||
|
else
|
||||||
|
trigger.action.outSoundForUnit( Unit:GetID(), self.UserSoundFileName )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -132,7 +132,7 @@ MISSION = {
|
|||||||
-- @param #string MissionName Name of the mission. This name will be used to reference the status of each mission by the players.
|
-- @param #string MissionName Name of the mission. This name will be used to reference the status of each mission by the players.
|
||||||
-- @param #string MissionPriority String indicating the "priority" of the Mission. e.g. "Primary", "Secondary". It is free format and up to the Mission designer to choose. There are no rules behind this field.
|
-- @param #string MissionPriority String indicating the "priority" of the Mission. e.g. "Primary", "Secondary". It is free format and up to the Mission designer to choose. There are no rules behind this field.
|
||||||
-- @param #string MissionBriefing String indicating the mission briefing to be shown when a player joins a @{CLIENT}.
|
-- @param #string MissionBriefing String indicating the mission briefing to be shown when a player joins a @{CLIENT}.
|
||||||
-- @param DCS#coaliton.side MissionCoalition Side of the coalition, i.e. and enumerator @{#DCS.coalition.side} corresponding to RED, BLUE or NEUTRAL.
|
-- @param DCS#coalition.side MissionCoalition Side of the coalition, i.e. and enumerator @{#DCS.coalition.side} corresponding to RED, BLUE or NEUTRAL.
|
||||||
-- @return #MISSION self
|
-- @return #MISSION self
|
||||||
function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition )
|
function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefing, MissionCoalition )
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- A statistic report on the progress of the mission. Each task achievement will increase the %-tage to 100% as a goal to complete the task.
|
-- A statistic report on the progress of the mission. Each task achievement will increase the % to 100% as a goal to complete the task.
|
||||||
--
|
--
|
||||||
-- ## 1.3) Join a Task.
|
-- ## 1.3) Join a Task.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ ENUMS = {}
|
|||||||
-- @type ENUMS.ROE
|
-- @type ENUMS.ROE
|
||||||
-- @field #number WeaponFree AI will engage any enemy group it detects. Target prioritization is based based on the threat of the target.
|
-- @field #number WeaponFree AI will engage any enemy group it detects. Target prioritization is based based on the threat of the target.
|
||||||
-- @field #number OpenFireWeaponFree AI will engage any enemy group it detects, but will prioritize targets specified in the groups tasking.
|
-- @field #number OpenFireWeaponFree AI will engage any enemy group it detects, but will prioritize targets specified in the groups tasking.
|
||||||
-- @field #number OpenFire AI will engage only targets specified in its tasking.
|
-- @field #number OpenFire AI will engage only targets specified in its taskings.
|
||||||
-- @field #number ReturnFire AI will only engage threats that shoot first.
|
-- @field #number ReturnFire AI will only engage threats that shoot first.
|
||||||
-- @field #number WeaponHold AI will hold fire under all circumstances.
|
-- @field #number WeaponHold AI will hold fire under all circumstances.
|
||||||
ENUMS.ROE = {
|
ENUMS.ROE = {
|
||||||
@@ -67,7 +67,7 @@ ENUMS.AlarmState = {
|
|||||||
Red=2,
|
Red=2,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on Hoggit wiki.
|
--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerotor on hoggit wiki.
|
||||||
-- @type ENUMS.WeaponFlag
|
-- @type ENUMS.WeaponFlag
|
||||||
ENUMS.WeaponFlag={
|
ENUMS.WeaponFlag={
|
||||||
-- Bombs
|
-- Bombs
|
||||||
@@ -111,7 +111,7 @@ ENUMS.WeaponFlag={
|
|||||||
--
|
--
|
||||||
-- Bombs
|
-- Bombs
|
||||||
GuidedBomb = 14, -- (LGB + TvGB + SNSGB)
|
GuidedBomb = 14, -- (LGB + TvGB + SNSGB)
|
||||||
AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispenser + CandleBomb + ParachuteBomb)
|
AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb)
|
||||||
AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb)
|
AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb)
|
||||||
--- Rockets
|
--- Rockets
|
||||||
AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket
|
AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket
|
||||||
@@ -126,6 +126,8 @@ ENUMS.WeaponFlag={
|
|||||||
AnyMissile = 268402688, -- AnyASM + AnyAAM
|
AnyMissile = 268402688, -- AnyASM + AnyAAM
|
||||||
--- Guns
|
--- Guns
|
||||||
Cannons = 805306368, -- GUN_POD + BuiltInCannon
|
Cannons = 805306368, -- GUN_POD + BuiltInCannon
|
||||||
|
--- Torpedo
|
||||||
|
Torpedo = 4294967296,
|
||||||
---
|
---
|
||||||
-- Even More Genral
|
-- Even More Genral
|
||||||
Auto = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons)
|
Auto = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons)
|
||||||
@@ -136,6 +138,93 @@ ENUMS.WeaponFlag={
|
|||||||
AnyGuided = 268402702, -- Any Guided Weapon
|
AnyGuided = 268402702, -- Any Guided Weapon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Weapon types by category. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on hoggit wiki.
|
||||||
|
-- @type ENUMS.WeaponType
|
||||||
|
-- @field #table Bomb Bombs.
|
||||||
|
-- @field #table Rocket Rocket.
|
||||||
|
-- @field #table Gun Guns.
|
||||||
|
-- @field #table Missile Missiles.
|
||||||
|
-- @field #table AAM Air-to-Air missiles.
|
||||||
|
-- @field #table Torpedo Torpedos.
|
||||||
|
-- @field #table Any Combinations.
|
||||||
|
ENUMS.WeaponType={}
|
||||||
|
ENUMS.WeaponType.Bomb={
|
||||||
|
-- Bombs
|
||||||
|
LGB = 2,
|
||||||
|
TvGB = 4,
|
||||||
|
SNSGB = 8,
|
||||||
|
HEBomb = 16,
|
||||||
|
Penetrator = 32,
|
||||||
|
NapalmBomb = 64,
|
||||||
|
FAEBomb = 128,
|
||||||
|
ClusterBomb = 256,
|
||||||
|
Dispencer = 512,
|
||||||
|
CandleBomb = 1024,
|
||||||
|
ParachuteBomb = 2147483648,
|
||||||
|
-- Combinations
|
||||||
|
GuidedBomb = 14, -- (LGB + TvGB + SNSGB)
|
||||||
|
AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb)
|
||||||
|
AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb)
|
||||||
|
}
|
||||||
|
ENUMS.WeaponType.Rocket={
|
||||||
|
-- Rockets
|
||||||
|
LightRocket = 2048,
|
||||||
|
MarkerRocket = 4096,
|
||||||
|
CandleRocket = 8192,
|
||||||
|
HeavyRocket = 16384,
|
||||||
|
-- Combinations
|
||||||
|
AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket
|
||||||
|
}
|
||||||
|
ENUMS.WeaponType.Gun={
|
||||||
|
-- Guns
|
||||||
|
GunPod = 268435456,
|
||||||
|
BuiltInCannon = 536870912,
|
||||||
|
-- Combinations
|
||||||
|
Cannons = 805306368, -- GUN_POD + BuiltInCannon
|
||||||
|
}
|
||||||
|
ENUMS.WeaponType.Missile={
|
||||||
|
-- Missiles
|
||||||
|
AntiRadarMissile = 32768,
|
||||||
|
AntiShipMissile = 65536,
|
||||||
|
AntiTankMissile = 131072,
|
||||||
|
FireAndForgetASM = 262144,
|
||||||
|
LaserASM = 524288,
|
||||||
|
TeleASM = 1048576,
|
||||||
|
CruiseMissile = 2097152,
|
||||||
|
AntiRadarMissile2 = 1073741824,
|
||||||
|
-- Combinations
|
||||||
|
GuidedASM = 1572864, -- (LaserASM + TeleASM)
|
||||||
|
TacticalASM = 1835008, -- (GuidedASM + FireAndForgetASM)
|
||||||
|
AnyASM = 4161536, -- (AntiRadarMissile + AntiShipMissile + AntiTankMissile + FireAndForgetASM + GuidedASM + CruiseMissile)
|
||||||
|
AnyASM2 = 1077903360, -- 4161536+1073741824,
|
||||||
|
AnyAutonomousMissile = 36012032, -- IR_AAM + AntiRadarMissile + AntiShipMissile + FireAndForgetASM + CruiseMissile
|
||||||
|
AnyMissile = 268402688, -- AnyASM + AnyAAM
|
||||||
|
}
|
||||||
|
ENUMS.WeaponType.AAM={
|
||||||
|
-- Air-To-Air Missiles
|
||||||
|
SRAM = 4194304,
|
||||||
|
MRAAM = 8388608,
|
||||||
|
LRAAM = 16777216,
|
||||||
|
IR_AAM = 33554432,
|
||||||
|
SAR_AAM = 67108864,
|
||||||
|
AR_AAM = 134217728,
|
||||||
|
-- Combinations
|
||||||
|
AnyAAM = 264241152, -- IR_AAM + SAR_AAM + AR_AAM + SRAAM + MRAAM + LRAAM
|
||||||
|
}
|
||||||
|
ENUMS.WeaponType.Torpedo={
|
||||||
|
-- Torpedo
|
||||||
|
Torpedo = 4294967296,
|
||||||
|
}
|
||||||
|
ENUMS.WeaponType.Any={
|
||||||
|
-- General combinations
|
||||||
|
Weapon = 3221225470, -- Any Weapon (AnyBomb + AnyRocket + AnyMissile + Cannons)
|
||||||
|
AG = 2956984318, -- Any Air-To-Ground Weapon
|
||||||
|
AA = 264241152, -- Any Air-To-Air Weapon
|
||||||
|
Unguided = 2952822768, -- Any Unguided Weapon
|
||||||
|
Guided = 268402702, -- Any Guided Weapon
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
--- Mission tasks.
|
--- Mission tasks.
|
||||||
-- @type ENUMS.MissionTask
|
-- @type ENUMS.MissionTask
|
||||||
-- @field #string NOTHING No special task. Group can perform the minimal tasks: Orbit, Refuelling, Follow and Aerobatics.
|
-- @field #string NOTHING No special task. Group can perform the minimal tasks: Orbit, Refuelling, Follow and Aerobatics.
|
||||||
@@ -173,7 +262,7 @@ ENUMS.MissionTask={
|
|||||||
TRANSPORT="Transport",
|
TRANSPORT="Transport",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki.
|
--- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
||||||
-- @type ENUMS.Formation
|
-- @type ENUMS.Formation
|
||||||
ENUMS.Formation={}
|
ENUMS.Formation={}
|
||||||
ENUMS.Formation.FixedWing={}
|
ENUMS.Formation.FixedWing={}
|
||||||
@@ -244,7 +333,7 @@ ENUMS.Formation.Vehicle.Cone="Cone"
|
|||||||
ENUMS.Formation.Vehicle.Diamond="Diamond"
|
ENUMS.Formation.Vehicle.Diamond="Diamond"
|
||||||
|
|
||||||
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
|
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
|
||||||
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki.
|
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
||||||
-- @type ENUMS.FormationOld
|
-- @type ENUMS.FormationOld
|
||||||
ENUMS.FormationOld={}
|
ENUMS.FormationOld={}
|
||||||
ENUMS.FormationOld.FixedWing={}
|
ENUMS.FormationOld.FixedWing={}
|
||||||
@@ -360,3 +449,113 @@ ENUMS.Phonetic =
|
|||||||
Y = 'Yankee',
|
Y = 'Yankee',
|
||||||
Z = 'Zulu',
|
Z = 'Zulu',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Reporting Names (NATO). See the [Wikipedia](https://en.wikipedia.org/wiki/List_of_NATO_reporting_names_for_fighter_aircraft).
|
||||||
|
-- DCS known aircraft types
|
||||||
|
--
|
||||||
|
-- @type ENUMS.ReportingName
|
||||||
|
ENUMS.ReportingName =
|
||||||
|
{
|
||||||
|
NATO = {
|
||||||
|
-- Fighters
|
||||||
|
Dragon = "JF-17", -- China, correctly Fierce Dragon, Thunder for PAC
|
||||||
|
Fagot = "MiG-15",
|
||||||
|
Farmer = "MiG-19", -- Shenyang J-6 and Mikoyan-Gurevich MiG-19
|
||||||
|
Felon = "Su-57",
|
||||||
|
Fencer = "Su-24",
|
||||||
|
Fishbed = "MiG-21",
|
||||||
|
Fitter = "Su-17", -- Sukhoi Su-7 and Su-17/Su-20/Su-22
|
||||||
|
Flogger = "MiG-23", --and MiG-27
|
||||||
|
Flogger_D = "MiG-27", --and MiG-23
|
||||||
|
Flagon = "Su-15",
|
||||||
|
Foxbat = "MiG-25",
|
||||||
|
Fulcrum = "MiG-29",
|
||||||
|
Foxhound = "MiG-31",
|
||||||
|
Flanker = "Su-27", -- Sukhoi Su-27/Su-30/Su-33/Su-35/Su-37 and Shenyang J-11/J-15/J-16
|
||||||
|
Flanker_C = "Su-30",
|
||||||
|
Flanker_E = "Su-35",
|
||||||
|
Flanker_F = "Su-37",
|
||||||
|
Flanker_L = "J-11A",
|
||||||
|
Firebird = "J-10",
|
||||||
|
Sea_Flanker = "Su-33",
|
||||||
|
Fullback = "Su-34", -- also Su-32
|
||||||
|
Frogfoot = "Su-25",
|
||||||
|
Tomcat = "F-14", -- Iran
|
||||||
|
Mirage = "Mirage", -- various non-NATO
|
||||||
|
Codling = "Yak-40",
|
||||||
|
Maya = "L-39",
|
||||||
|
-- Fighters US/NATO
|
||||||
|
Warthog = "A-10",
|
||||||
|
--Mosquito = "A-20",
|
||||||
|
Skyhawk = "A-4E",
|
||||||
|
Viggen = "AJS37",
|
||||||
|
Harrier = "AV-8B",
|
||||||
|
Spirit = "B-2",
|
||||||
|
Aviojet = "C-101",
|
||||||
|
Nighthawk = "F-117A",
|
||||||
|
Eagle = "F-15C",
|
||||||
|
Mudhen = "F-15E",
|
||||||
|
Viper = "F-16",
|
||||||
|
Phantom = "F-4E",
|
||||||
|
Tiger = "F-5", -- was thinking to name this MiG-25 ;)
|
||||||
|
Sabre = "F-86",
|
||||||
|
Hornet = "A-18", -- avoiding the slash
|
||||||
|
Hawk = "Hawk",
|
||||||
|
Albatros = "L-39",
|
||||||
|
Goshawk = "T-45",
|
||||||
|
Starfighter = "F-104",
|
||||||
|
Tornado = "Tornado",
|
||||||
|
-- Transport / Bomber / Others
|
||||||
|
Atlas = "A400",
|
||||||
|
Lancer = "B1-B",
|
||||||
|
Stratofortress = "B-52H",
|
||||||
|
Hercules = "C-130",
|
||||||
|
Super_Hercules = "Hercules",
|
||||||
|
Globemaster = "C-17",
|
||||||
|
Greyhound = "C-2A",
|
||||||
|
Galaxy = "C-5",
|
||||||
|
Hawkeye = "E-2D",
|
||||||
|
Sentry = "E-3A",
|
||||||
|
Stratotanker = "KC-135",
|
||||||
|
Extender = "KC-10",
|
||||||
|
Orion = "P-3C",
|
||||||
|
Viking = "S-3B",
|
||||||
|
Osprey = "V-22",
|
||||||
|
-- Bomber Rus
|
||||||
|
Badger = "H6-J",
|
||||||
|
Bear_J = "Tu-142", -- also Tu-95
|
||||||
|
Bear = "Tu-95", -- also Tu-142
|
||||||
|
Blinder = "Tu-22",
|
||||||
|
Blackjack = "Tu-160",
|
||||||
|
-- AIC / Transport / Other
|
||||||
|
Clank = "An-30",
|
||||||
|
Curl = "An-26",
|
||||||
|
Candid = "IL-76",
|
||||||
|
Midas = "IL-78",
|
||||||
|
Mainstay = "A-50",
|
||||||
|
Mainring = "KJ-2000", -- A-50 China
|
||||||
|
Yak = "Yak-52",
|
||||||
|
-- Helos
|
||||||
|
Helix = "Ka-27",
|
||||||
|
Shark = "Ka-50",
|
||||||
|
Hind = "Mi-24",
|
||||||
|
Halo = "Mi-26",
|
||||||
|
Hip = "Mi-8",
|
||||||
|
Havoc = "Mi-28",
|
||||||
|
Gazelle = "SA342",
|
||||||
|
-- Helos US
|
||||||
|
Huey = "UH-1H",
|
||||||
|
Cobra = "AH-1",
|
||||||
|
Apache = "AH-64",
|
||||||
|
Chinook = "CH-47",
|
||||||
|
Sea_Stallion = "CH-53",
|
||||||
|
Kiowa = "OH-58",
|
||||||
|
Seahawk = "SH-60",
|
||||||
|
Blackhawk = "UH-60",
|
||||||
|
Sea_King = "S-61",
|
||||||
|
-- Drones
|
||||||
|
UCAV = "WingLoong",
|
||||||
|
Reaper = "MQ-9",
|
||||||
|
Predator = "MQ-1A",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,773 @@
|
|||||||
|
--- **UTILS** - ClassicFiFo Stack.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Main Features:
|
||||||
|
--
|
||||||
|
-- * Build a simple multi-purpose FiFo (First-In, First-Out) stack for generic data.
|
||||||
|
-- * [Wikipedia](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **applevangelist**
|
||||||
|
-- @module Utils.FiFo
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
-- Date: April 2022
|
||||||
|
|
||||||
|
do
|
||||||
|
--- FIFO class.
|
||||||
|
-- @type FIFO
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #string version Version of FiFo
|
||||||
|
-- @field #number counter
|
||||||
|
-- @field #number pointer
|
||||||
|
-- @field #table stackbypointer
|
||||||
|
-- @field #table stackbyid
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @type FIFO.IDEntry
|
||||||
|
-- @field #number pointer
|
||||||
|
-- @field #table data
|
||||||
|
-- @field #table uniqueID
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @field #FIFO
|
||||||
|
FIFO = {
|
||||||
|
ClassName = "FIFO",
|
||||||
|
lid = "",
|
||||||
|
version = "0.0.5",
|
||||||
|
counter = 0,
|
||||||
|
pointer = 0,
|
||||||
|
stackbypointer = {},
|
||||||
|
stackbyid = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Instantiate a new FIFO Stack
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #FIFO self
|
||||||
|
function FIFO:New()
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
local self=BASE:Inherit(self, BASE:New())
|
||||||
|
self.pointer = 0
|
||||||
|
self.counter = 0
|
||||||
|
self.stackbypointer = {}
|
||||||
|
self.stackbyid = {}
|
||||||
|
self.uniquecounter = 0
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("%s (%s) | ", "FiFo", self.version)
|
||||||
|
self:T(self.lid .."Created.")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Empty FIFO Stack
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #FIFO self
|
||||||
|
function FIFO:Clear()
|
||||||
|
self:T(self.lid.."Clear")
|
||||||
|
self.pointer = 0
|
||||||
|
self.counter = 0
|
||||||
|
self.stackbypointer = nil
|
||||||
|
self.stackbyid = nil
|
||||||
|
self.stackbypointer = {}
|
||||||
|
self.stackbyid = {}
|
||||||
|
self.uniquecounter = 0
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Push Object to Stack
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @param #table Object
|
||||||
|
-- @param #string UniqueID (optional) - will default to current pointer + 1. Note - if you intend to use `FIFO:GetIDStackSorted()` keep the UniqueID numerical!
|
||||||
|
-- @return #FIFO self
|
||||||
|
function FIFO:Push(Object,UniqueID)
|
||||||
|
self:T(self.lid.."Push")
|
||||||
|
self:T({Object,UniqueID})
|
||||||
|
self.pointer = self.pointer + 1
|
||||||
|
self.counter = self.counter + 1
|
||||||
|
local uniID = UniqueID
|
||||||
|
if not UniqueID then
|
||||||
|
self.uniquecounter = self.uniquecounter + 1
|
||||||
|
uniID = self.uniquecounter
|
||||||
|
end
|
||||||
|
self.stackbyid[uniID] = { pointer = self.pointer, data = Object, uniqueID = uniID }
|
||||||
|
self.stackbypointer[self.pointer] = { pointer = self.pointer, data = Object, uniqueID = uniID }
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Pull Object from Stack
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #table Object or nil if stack is empty
|
||||||
|
function FIFO:Pull()
|
||||||
|
self:T(self.lid.."Pull")
|
||||||
|
if self.counter == 0 then return nil end
|
||||||
|
--local object = self.stackbypointer[self.pointer].data
|
||||||
|
--self.stackbypointer[self.pointer] = nil
|
||||||
|
local object = self.stackbypointer[1].data
|
||||||
|
self.stackbypointer[1] = nil
|
||||||
|
self.counter = self.counter - 1
|
||||||
|
--self.pointer = self.pointer - 1
|
||||||
|
self:Flatten()
|
||||||
|
return object
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Pull Object from Stack by Pointer
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @param #number Pointer
|
||||||
|
-- @return #table Object or nil if stack is empty
|
||||||
|
function FIFO:PullByPointer(Pointer)
|
||||||
|
self:T(self.lid.."PullByPointer " .. tostring(Pointer))
|
||||||
|
if self.counter == 0 then return nil end
|
||||||
|
local object = self.stackbypointer[Pointer] -- #FIFO.IDEntry
|
||||||
|
self.stackbypointer[Pointer] = nil
|
||||||
|
if object then self.stackbyid[object.uniqueID] = nil end
|
||||||
|
self.counter = self.counter - 1
|
||||||
|
self:Flatten()
|
||||||
|
if object then
|
||||||
|
return object.data
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- FIFO Read, not Pull, Object from Stack by Pointer
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @param #number Pointer
|
||||||
|
-- @return #table Object or nil if stack is empty or pointer does not exist
|
||||||
|
function FIFO:ReadByPointer(Pointer)
|
||||||
|
self:T(self.lid.."ReadByPointer " .. tostring(Pointer))
|
||||||
|
if self.counter == 0 or not Pointer or not self.stackbypointer[Pointer] then return nil end
|
||||||
|
local object = self.stackbypointer[Pointer] -- #FIFO.IDEntry
|
||||||
|
if object then
|
||||||
|
return object.data
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Read, not Pull, Object from Stack by UniqueID
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @param #number UniqueID
|
||||||
|
-- @return #table Object data or nil if stack is empty or ID does not exist
|
||||||
|
function FIFO:ReadByID(UniqueID)
|
||||||
|
self:T(self.lid.."ReadByID " .. tostring(UniqueID))
|
||||||
|
if self.counter == 0 or not UniqueID or not self.stackbyid[UniqueID] then return nil end
|
||||||
|
local object = self.stackbyid[UniqueID] -- #FIFO.IDEntry
|
||||||
|
if object then
|
||||||
|
return object.data
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Pull Object from Stack by UniqueID
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @param #tableUniqueID
|
||||||
|
-- @return #table Object or nil if stack is empty
|
||||||
|
function FIFO:PullByID(UniqueID)
|
||||||
|
self:T(self.lid.."PullByID " .. tostring(UniqueID))
|
||||||
|
if self.counter == 0 then return nil end
|
||||||
|
local object = self.stackbyid[UniqueID] -- #FIFO.IDEntry
|
||||||
|
--self.stackbyid[UniqueID] = nil
|
||||||
|
if object then
|
||||||
|
return self:PullByPointer(object.pointer)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Housekeeping
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #FIFO self
|
||||||
|
function FIFO:Flatten()
|
||||||
|
self:T(self.lid.."Flatten")
|
||||||
|
-- rebuild stacks
|
||||||
|
local pointerstack = {}
|
||||||
|
local idstack = {}
|
||||||
|
local counter = 0
|
||||||
|
for _ID,_entry in pairs(self.stackbypointer) do
|
||||||
|
counter = counter + 1
|
||||||
|
pointerstack[counter] = { pointer = counter, data = _entry.data, uniqueID = _entry.uniqueID}
|
||||||
|
end
|
||||||
|
for _ID,_entry in pairs(pointerstack) do
|
||||||
|
idstack[_entry.uniqueID] = { pointer = _entry.pointer , data = _entry.data, uniqueID = _entry.uniqueID}
|
||||||
|
end
|
||||||
|
self.stackbypointer = nil
|
||||||
|
self.stackbypointer = pointerstack
|
||||||
|
self.stackbyid = nil
|
||||||
|
self.stackbyid = idstack
|
||||||
|
self.counter = counter
|
||||||
|
self.pointer = counter
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Check Stack is empty
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #boolean empty
|
||||||
|
function FIFO:IsEmpty()
|
||||||
|
self:T(self.lid.."IsEmpty")
|
||||||
|
return self.counter == 0 and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Get stack size
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #number size
|
||||||
|
function FIFO:GetSize()
|
||||||
|
self:T(self.lid.."GetSize")
|
||||||
|
return self.counter
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Get stack size
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #number size
|
||||||
|
function FIFO:Count()
|
||||||
|
self:T(self.lid.."Count")
|
||||||
|
return self.counter
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Check Stack is NOT empty
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #boolean notempty
|
||||||
|
function FIFO:IsNotEmpty()
|
||||||
|
self:T(self.lid.."IsNotEmpty")
|
||||||
|
return not self:IsEmpty()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Get the data stack by pointer
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #table Table of #FIFO.IDEntry entries
|
||||||
|
function FIFO:GetPointerStack()
|
||||||
|
self:T(self.lid.."GetPointerStack")
|
||||||
|
return self.stackbypointer
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Check if a certain UniqeID exists
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #boolean exists
|
||||||
|
function FIFO:HasUniqueID(UniqueID)
|
||||||
|
self:T(self.lid.."HasUniqueID")
|
||||||
|
if self.stackbyid[UniqueID] ~= nil then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Get the data stack by UniqueID
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #table Table of #FIFO.IDEntry entries
|
||||||
|
function FIFO:GetIDStack()
|
||||||
|
self:T(self.lid.."GetIDStack")
|
||||||
|
return self.stackbyid
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Get table of UniqueIDs sorted smallest to largest
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #table Table with index [1] to [n] of UniqueID entries
|
||||||
|
function FIFO:GetIDStackSorted()
|
||||||
|
self:T(self.lid.."GetIDStackSorted")
|
||||||
|
|
||||||
|
local stack = self:GetIDStack()
|
||||||
|
local idstack = {}
|
||||||
|
for _id,_entry in pairs(stack) do
|
||||||
|
idstack[#idstack+1] = _id
|
||||||
|
|
||||||
|
self:T({"pre",_id})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sortID(a, b)
|
||||||
|
return a < b
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(idstack)
|
||||||
|
|
||||||
|
return idstack
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Get table of data entries
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #table Raw table indexed [1] to [n] of object entries - might be empty!
|
||||||
|
function FIFO:GetDataTable()
|
||||||
|
self:T(self.lid.."GetDataTable")
|
||||||
|
local datatable = {}
|
||||||
|
for _,_entry in pairs(self.stackbypointer) do
|
||||||
|
datatable[#datatable+1] = _entry.data
|
||||||
|
end
|
||||||
|
return datatable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Get sorted table of data entries by UniqueIDs (must be numerical UniqueIDs only!)
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #table Table indexed [1] to [n] of sorted object entries - might be empty!
|
||||||
|
function FIFO:GetSortedDataTable()
|
||||||
|
self:T(self.lid.."GetSortedDataTable")
|
||||||
|
local datatable = {}
|
||||||
|
local idtablesorted = self:GetIDStackSorted()
|
||||||
|
for _,_entry in pairs(idtablesorted) do
|
||||||
|
datatable[#datatable+1] = self:ReadByID(_entry)
|
||||||
|
end
|
||||||
|
return datatable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Iterate the FIFO and call an iterator function for the given FIFO data, providing the object for each element of the stack and optional parameters.
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @param #function IteratorFunction The function that will be called.
|
||||||
|
-- @param #table Arg (Optional) Further Arguments of the IteratorFunction.
|
||||||
|
-- @param #function Function (Optional) A function returning a #boolean true/false. Only if true, the IteratorFunction is called.
|
||||||
|
-- @param #table FunctionArguments (Optional) Function arguments.
|
||||||
|
-- @return #FIFO self
|
||||||
|
function FIFO:ForEach( IteratorFunction, Arg, Function, FunctionArguments )
|
||||||
|
self:T(self.lid.."ForEach")
|
||||||
|
|
||||||
|
local Set = self:GetPointerStack() or {}
|
||||||
|
Arg = Arg or {}
|
||||||
|
|
||||||
|
local function CoRoutine()
|
||||||
|
local Count = 0
|
||||||
|
for ObjectID, ObjectData in pairs( Set ) do
|
||||||
|
local Object = ObjectData.data
|
||||||
|
self:T( {Object} )
|
||||||
|
if Function then
|
||||||
|
if Function( unpack( FunctionArguments or {} ), Object ) == true then
|
||||||
|
IteratorFunction( Object, unpack( Arg ) )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
IteratorFunction( Object, unpack( Arg ) )
|
||||||
|
end
|
||||||
|
Count = Count + 1
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local co = CoRoutine
|
||||||
|
|
||||||
|
local function Schedule()
|
||||||
|
|
||||||
|
local status, res = co()
|
||||||
|
self:T( { status, res } )
|
||||||
|
|
||||||
|
if status == false then
|
||||||
|
error( res )
|
||||||
|
end
|
||||||
|
if res == false then
|
||||||
|
return true -- resume next time the loop
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
Schedule()
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- FIFO Print stacks to dcs.log
|
||||||
|
-- @param #FIFO self
|
||||||
|
-- @return #FIFO self
|
||||||
|
function FIFO:Flush()
|
||||||
|
self:T(self.lid.."FiFo Flush")
|
||||||
|
self:I("FIFO Flushing Stack by Pointer")
|
||||||
|
for _id,_data in pairs (self.stackbypointer) do
|
||||||
|
local data = _data -- #FIFO.IDEntry
|
||||||
|
self:I(string.format("Pointer: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID)))
|
||||||
|
end
|
||||||
|
self:I("FIFO Flushing Stack by ID")
|
||||||
|
for _id,_data in pairs (self.stackbyid) do
|
||||||
|
local data = _data -- #FIFO.IDEntry
|
||||||
|
self:I(string.format("ID: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID)))
|
||||||
|
end
|
||||||
|
self:I("Counter = " .. self.counter)
|
||||||
|
self:I("Pointer = ".. self.pointer)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- End FIFO
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- LIFO
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
do
|
||||||
|
--- **UTILS** - LiFo Stack.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Build a simple multi-purpose LiFo (Last-In, First-Out) stack for generic data.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **applevangelist**
|
||||||
|
|
||||||
|
--- LIFO class.
|
||||||
|
-- @type LIFO
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #string version Version of LiFo
|
||||||
|
-- @field #number counter
|
||||||
|
-- @field #number pointer
|
||||||
|
-- @field #table stackbypointer
|
||||||
|
-- @field #table stackbyid
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @type LIFO.IDEntry
|
||||||
|
-- @field #number pointer
|
||||||
|
-- @field #table data
|
||||||
|
-- @field #table uniqueID
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @field #LIFO
|
||||||
|
LIFO = {
|
||||||
|
ClassName = "LIFO",
|
||||||
|
lid = "",
|
||||||
|
version = "0.0.5",
|
||||||
|
counter = 0,
|
||||||
|
pointer = 0,
|
||||||
|
stackbypointer = {},
|
||||||
|
stackbyid = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Instantiate a new LIFO Stack
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #LIFO self
|
||||||
|
function LIFO:New()
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
local self=BASE:Inherit(self, BASE:New())
|
||||||
|
self.pointer = 0
|
||||||
|
self.counter = 0
|
||||||
|
self.uniquecounter = 0
|
||||||
|
self.stackbypointer = {}
|
||||||
|
self.stackbyid = {}
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("%s (%s) | ", "LiFo", self.version)
|
||||||
|
self:T(self.lid .."Created.")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Empty LIFO Stack
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #LIFO self
|
||||||
|
function LIFO:Clear()
|
||||||
|
self:T(self.lid.."Clear")
|
||||||
|
self.pointer = 0
|
||||||
|
self.counter = 0
|
||||||
|
self.stackbypointer = nil
|
||||||
|
self.stackbyid = nil
|
||||||
|
self.stackbypointer = {}
|
||||||
|
self.stackbyid = {}
|
||||||
|
self.uniquecounter = 0
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Push Object to Stack
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @param #table Object
|
||||||
|
-- @param #string UniqueID (optional) - will default to current pointer + 1
|
||||||
|
-- @return #LIFO self
|
||||||
|
function LIFO:Push(Object,UniqueID)
|
||||||
|
self:T(self.lid.."Push")
|
||||||
|
self:T({Object,UniqueID})
|
||||||
|
self.pointer = self.pointer + 1
|
||||||
|
self.counter = self.counter + 1
|
||||||
|
local uniID = UniqueID
|
||||||
|
if not UniqueID then
|
||||||
|
self.uniquecounter = self.uniquecounter + 1
|
||||||
|
uniID = self.uniquecounter
|
||||||
|
end
|
||||||
|
self.stackbyid[uniID] = { pointer = self.pointer, data = Object, uniqueID = uniID }
|
||||||
|
self.stackbypointer[self.pointer] = { pointer = self.pointer, data = Object, uniqueID = uniID }
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Pull Object from Stack
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #table Object or nil if stack is empty
|
||||||
|
function LIFO:Pull()
|
||||||
|
self:T(self.lid.."Pull")
|
||||||
|
if self.counter == 0 then return nil end
|
||||||
|
local object = self.stackbypointer[self.pointer].data
|
||||||
|
self.stackbypointer[self.pointer] = nil
|
||||||
|
--local object = self.stackbypointer[1].data
|
||||||
|
--self.stackbypointer[1] = nil
|
||||||
|
self.counter = self.counter - 1
|
||||||
|
self.pointer = self.pointer - 1
|
||||||
|
self:Flatten()
|
||||||
|
return object
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Pull Object from Stack by Pointer
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @param #number Pointer
|
||||||
|
-- @return #table Object or nil if stack is empty
|
||||||
|
function LIFO:PullByPointer(Pointer)
|
||||||
|
self:T(self.lid.."PullByPointer " .. tostring(Pointer))
|
||||||
|
if self.counter == 0 then return nil end
|
||||||
|
local object = self.stackbypointer[Pointer] -- #FIFO.IDEntry
|
||||||
|
self.stackbypointer[Pointer] = nil
|
||||||
|
if object then self.stackbyid[object.uniqueID] = nil end
|
||||||
|
self.counter = self.counter - 1
|
||||||
|
self:Flatten()
|
||||||
|
if object then
|
||||||
|
return object.data
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Read, not Pull, Object from Stack by Pointer
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @param #number Pointer
|
||||||
|
-- @return #table Object or nil if stack is empty or pointer does not exist
|
||||||
|
function LIFO:ReadByPointer(Pointer)
|
||||||
|
self:T(self.lid.."ReadByPointer " .. tostring(Pointer))
|
||||||
|
if self.counter == 0 or not Pointer or not self.stackbypointer[Pointer] then return nil end
|
||||||
|
local object = self.stackbypointer[Pointer] -- #LIFO.IDEntry
|
||||||
|
if object then
|
||||||
|
return object.data
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Read, not Pull, Object from Stack by UniqueID
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @param #number UniqueID
|
||||||
|
-- @return #table Object or nil if stack is empty or ID does not exist
|
||||||
|
function LIFO:ReadByID(UniqueID)
|
||||||
|
self:T(self.lid.."ReadByID " .. tostring(UniqueID))
|
||||||
|
if self.counter == 0 or not UniqueID or not self.stackbyid[UniqueID] then return nil end
|
||||||
|
local object = self.stackbyid[UniqueID] -- #LIFO.IDEntry
|
||||||
|
if object then
|
||||||
|
return object.data
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Pull Object from Stack by UniqueID
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @param #tableUniqueID
|
||||||
|
-- @return #table Object or nil if stack is empty
|
||||||
|
function LIFO:PullByID(UniqueID)
|
||||||
|
self:T(self.lid.."PullByID " .. tostring(UniqueID))
|
||||||
|
if self.counter == 0 then return nil end
|
||||||
|
local object = self.stackbyid[UniqueID] -- #LIFO.IDEntry
|
||||||
|
--self.stackbyid[UniqueID] = nil
|
||||||
|
if object then
|
||||||
|
return self:PullByPointer(object.pointer)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Housekeeping
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #LIFO self
|
||||||
|
function LIFO:Flatten()
|
||||||
|
self:T(self.lid.."Flatten")
|
||||||
|
-- rebuild stacks
|
||||||
|
local pointerstack = {}
|
||||||
|
local idstack = {}
|
||||||
|
local counter = 0
|
||||||
|
for _ID,_entry in pairs(self.stackbypointer) do
|
||||||
|
counter = counter + 1
|
||||||
|
pointerstack[counter] = { pointer = counter, data = _entry.data, uniqueID = _entry.uniqueID}
|
||||||
|
end
|
||||||
|
for _ID,_entry in pairs(pointerstack) do
|
||||||
|
idstack[_entry.uniqueID] = { pointer = _entry.pointer , data = _entry.data, uniqueID = _entry.uniqueID}
|
||||||
|
end
|
||||||
|
self.stackbypointer = nil
|
||||||
|
self.stackbypointer = pointerstack
|
||||||
|
self.stackbyid = nil
|
||||||
|
self.stackbyid = idstack
|
||||||
|
self.counter = counter
|
||||||
|
self.pointer = counter
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Check Stack is empty
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #boolean empty
|
||||||
|
function LIFO:IsEmpty()
|
||||||
|
self:T(self.lid.."IsEmpty")
|
||||||
|
return self.counter == 0 and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Get stack size
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #number size
|
||||||
|
function LIFO:GetSize()
|
||||||
|
self:T(self.lid.."GetSize")
|
||||||
|
return self.counter
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Get stack size
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #number size
|
||||||
|
function LIFO:Count()
|
||||||
|
self:T(self.lid.."Count")
|
||||||
|
return self.counter
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Check Stack is NOT empty
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #boolean notempty
|
||||||
|
function LIFO:IsNotEmpty()
|
||||||
|
self:T(self.lid.."IsNotEmpty")
|
||||||
|
return not self:IsEmpty()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Get the data stack by pointer
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #table Table of #LIFO.IDEntry entries
|
||||||
|
function LIFO:GetPointerStack()
|
||||||
|
self:T(self.lid.."GetPointerStack")
|
||||||
|
return self.stackbypointer
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Get the data stack by UniqueID
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #table Table of #LIFO.IDEntry entries
|
||||||
|
function LIFO:GetIDStack()
|
||||||
|
self:T(self.lid.."GetIDStack")
|
||||||
|
return self.stackbyid
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Get table of UniqueIDs sorted smallest to largest
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #table Table of #LIFO.IDEntry entries
|
||||||
|
function LIFO:GetIDStackSorted()
|
||||||
|
self:T(self.lid.."GetIDStackSorted")
|
||||||
|
|
||||||
|
local stack = self:GetIDStack()
|
||||||
|
local idstack = {}
|
||||||
|
for _id,_entry in pairs(stack) do
|
||||||
|
idstack[#idstack+1] = _id
|
||||||
|
|
||||||
|
self:T({"pre",_id})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sortID(a, b)
|
||||||
|
return a < b
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(idstack)
|
||||||
|
|
||||||
|
return idstack
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Check if a certain UniqeID exists
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #boolean exists
|
||||||
|
function LIFO:HasUniqueID(UniqueID)
|
||||||
|
self:T(self.lid.."HasUniqueID")
|
||||||
|
return self.stackbyid[UniqueID] and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Print stacks to dcs.log
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #LIFO self
|
||||||
|
function LIFO:Flush()
|
||||||
|
self:T(self.lid.."FiFo Flush")
|
||||||
|
self:I("LIFO Flushing Stack by Pointer")
|
||||||
|
for _id,_data in pairs (self.stackbypointer) do
|
||||||
|
local data = _data -- #LIFO.IDEntry
|
||||||
|
self:I(string.format("Pointer: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID)))
|
||||||
|
end
|
||||||
|
self:I("LIFO Flushing Stack by ID")
|
||||||
|
for _id,_data in pairs (self.stackbyid) do
|
||||||
|
local data = _data -- #LIFO.IDEntry
|
||||||
|
self:I(string.format("ID: %s | Entry: Number = %s Data = %s UniqueID = %s",tostring(_id),tostring(data.pointer),tostring(data.data),tostring(data.uniqueID)))
|
||||||
|
end
|
||||||
|
self:I("Counter = " .. self.counter)
|
||||||
|
self:I("Pointer = ".. self.pointer)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Get table of data entries
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #table Raw table indexed [1] to [n] of object entries - might be empty!
|
||||||
|
function LIFO:GetDataTable()
|
||||||
|
self:T(self.lid.."GetDataTable")
|
||||||
|
local datatable = {}
|
||||||
|
for _,_entry in pairs(self.stackbypointer) do
|
||||||
|
datatable[#datatable+1] = _entry.data
|
||||||
|
end
|
||||||
|
return datatable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- LIFO Get sorted table of data entries by UniqueIDs (must be numerical UniqueIDs only!)
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @return #table Table indexed [1] to [n] of sorted object entries - might be empty!
|
||||||
|
function LIFO:GetSortedDataTable()
|
||||||
|
self:T(self.lid.."GetSortedDataTable")
|
||||||
|
local datatable = {}
|
||||||
|
local idtablesorted = self:GetIDStackSorted()
|
||||||
|
for _,_entry in pairs(idtablesorted) do
|
||||||
|
datatable[#datatable+1] = self:ReadByID(_entry)
|
||||||
|
end
|
||||||
|
return datatable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Iterate the LIFO and call an iterator function for the given LIFO data, providing the object for each element of the stack and optional parameters.
|
||||||
|
-- @param #LIFO self
|
||||||
|
-- @param #function IteratorFunction The function that will be called.
|
||||||
|
-- @param #table Arg (Optional) Further Arguments of the IteratorFunction.
|
||||||
|
-- @param #function Function (Optional) A function returning a #boolean true/false. Only if true, the IteratorFunction is called.
|
||||||
|
-- @param #table FunctionArguments (Optional) Function arguments.
|
||||||
|
-- @return #LIFO self
|
||||||
|
function LIFO:ForEach( IteratorFunction, Arg, Function, FunctionArguments )
|
||||||
|
self:T(self.lid.."ForEach")
|
||||||
|
|
||||||
|
local Set = self:GetPointerStack() or {}
|
||||||
|
Arg = Arg or {}
|
||||||
|
|
||||||
|
local function CoRoutine()
|
||||||
|
local Count = 0
|
||||||
|
for ObjectID, ObjectData in pairs( Set ) do
|
||||||
|
local Object = ObjectData.data
|
||||||
|
self:T( {Object} )
|
||||||
|
if Function then
|
||||||
|
if Function( unpack( FunctionArguments or {} ), Object ) == true then
|
||||||
|
IteratorFunction( Object, unpack( Arg ) )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
IteratorFunction( Object, unpack( Arg ) )
|
||||||
|
end
|
||||||
|
Count = Count + 1
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local co = CoRoutine
|
||||||
|
|
||||||
|
local function Schedule()
|
||||||
|
|
||||||
|
local status, res = co()
|
||||||
|
self:T( { status, res } )
|
||||||
|
|
||||||
|
if status == false then
|
||||||
|
error( res )
|
||||||
|
end
|
||||||
|
if res == false then
|
||||||
|
return true -- resume next time the loop
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
Schedule()
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- End LIFO
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
end
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
--- This module contains derived utilities taken from the MIST framework, which are excellent tools to be reused in an OO environment.
|
--- This module contains derived utilities taken from the MIST framework, as well as a lot of added helpers from the MOOSE community.
|
||||||
--
|
--
|
||||||
-- ### Authors:
|
-- ### Authors:
|
||||||
--
|
--
|
||||||
@@ -7,10 +7,12 @@
|
|||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- * FlightControl : Rework to OO framework.
|
-- * FlightControl : Rework to OO framework.
|
||||||
|
-- * And many more
|
||||||
--
|
--
|
||||||
-- @module Utils
|
-- @module Utils
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type SMOKECOLOR
|
--- @type SMOKECOLOR
|
||||||
-- @field Green
|
-- @field Green
|
||||||
-- @field Red
|
-- @field Red
|
||||||
@@ -50,6 +52,7 @@ BIGSMOKEPRESET = {
|
|||||||
-- @field #string TheChannel The Channel map.
|
-- @field #string TheChannel The Channel map.
|
||||||
-- @field #string Syria Syria map.
|
-- @field #string Syria Syria map.
|
||||||
-- @field #string MarianaIslands Mariana Islands map.
|
-- @field #string MarianaIslands Mariana Islands map.
|
||||||
|
-- @field #string Falklands South Atlantic map.
|
||||||
DCSMAP = {
|
DCSMAP = {
|
||||||
Caucasus="Caucasus",
|
Caucasus="Caucasus",
|
||||||
NTTR="Nevada",
|
NTTR="Nevada",
|
||||||
@@ -58,8 +61,10 @@ DCSMAP = {
|
|||||||
TheChannel="TheChannel",
|
TheChannel="TheChannel",
|
||||||
Syria="Syria",
|
Syria="Syria",
|
||||||
MarianaIslands="MarianaIslands",
|
MarianaIslands="MarianaIslands",
|
||||||
|
Falklands="Falklands",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--- See [DCS_enum_callsigns](https://wiki.hoggitworld.com/view/DCS_enum_callsigns)
|
--- See [DCS_enum_callsigns](https://wiki.hoggitworld.com/view/DCS_enum_callsigns)
|
||||||
-- @type CALLSIGN
|
-- @type CALLSIGN
|
||||||
CALLSIGN={
|
CALLSIGN={
|
||||||
@@ -128,6 +133,62 @@ CALLSIGN = {
|
|||||||
Dublin=9,
|
Dublin=9,
|
||||||
Perth=10,
|
Perth=10,
|
||||||
},
|
},
|
||||||
|
F16={
|
||||||
|
Viper=9,
|
||||||
|
Venom=10,
|
||||||
|
Lobo=11,
|
||||||
|
Cowboy=12,
|
||||||
|
Python=13,
|
||||||
|
Rattler=14,
|
||||||
|
Panther=15,
|
||||||
|
Wolf=16,
|
||||||
|
Weasel=17,
|
||||||
|
Wild=18,
|
||||||
|
Ninja=19,
|
||||||
|
Jedi=20,
|
||||||
|
},
|
||||||
|
F18={
|
||||||
|
Hornet=9,
|
||||||
|
Squid=10,
|
||||||
|
Ragin=11,
|
||||||
|
Roman=12,
|
||||||
|
Sting=13,
|
||||||
|
Jury=14,
|
||||||
|
Jokey=15,
|
||||||
|
Ram=16,
|
||||||
|
Hawk=17,
|
||||||
|
Devil=18,
|
||||||
|
Check=19,
|
||||||
|
Snake=20,
|
||||||
|
},
|
||||||
|
F15E={
|
||||||
|
Dude=9,
|
||||||
|
Thud=10,
|
||||||
|
Gunny=11,
|
||||||
|
Trek=12,
|
||||||
|
Sniper=13,
|
||||||
|
Sled=14,
|
||||||
|
Best=15,
|
||||||
|
Jazz=16,
|
||||||
|
Rage=17,
|
||||||
|
Tahoe=18,
|
||||||
|
},
|
||||||
|
B1B={
|
||||||
|
Bone=9,
|
||||||
|
Dark=10,
|
||||||
|
Vader=11
|
||||||
|
},
|
||||||
|
B52={
|
||||||
|
Buff=9,
|
||||||
|
Dump=10,
|
||||||
|
Kenworth=11,
|
||||||
|
},
|
||||||
|
TransportAircraft={
|
||||||
|
Heavy=9,
|
||||||
|
Trash=10,
|
||||||
|
Cargo=11,
|
||||||
|
Ascot=12,
|
||||||
|
},
|
||||||
} --#CALLSIGN
|
} --#CALLSIGN
|
||||||
|
|
||||||
--- Utilities static class.
|
--- Utilities static class.
|
||||||
@@ -199,6 +260,7 @@ UTILS.IsInstanceOf = function( object, className )
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Deep copy a table. See http://lua-users.org/wiki/CopyTable
|
--- Deep copy a table. See http://lua-users.org/wiki/CopyTable
|
||||||
-- @param #table object The input table.
|
-- @param #table object The input table.
|
||||||
-- @return #table Copy of the input table.
|
-- @return #table Copy of the input table.
|
||||||
@@ -230,6 +292,7 @@ UTILS.DeepCopy = function( object )
|
|||||||
return objectreturn
|
return objectreturn
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Porting in Slmod's serialize_slmod2.
|
--- Porting in Slmod's serialize_slmod2.
|
||||||
-- @param #table tbl Input table.
|
-- @param #table tbl Input table.
|
||||||
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
|
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
|
||||||
@@ -322,6 +385,7 @@ UTILS.BasicSerialize = function( s )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
UTILS.ToDegree = function(angle)
|
UTILS.ToDegree = function(angle)
|
||||||
return angle*180/math.pi
|
return angle*180/math.pi
|
||||||
end
|
end
|
||||||
@@ -412,20 +476,20 @@ UTILS.KnotsToMps = function( knots )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Convert temperature from Celsius to Fahrenheit.
|
--- Convert temperature from Celsius to Fahrenheit.
|
||||||
-- @param #number Celsius Temperature in degrees Celsius.
|
-- @param #number Celcius Temperature in degrees Celsius.
|
||||||
-- @return #number Temperature in degrees Fahrenheit.
|
-- @return #number Temperature in degrees Fahrenheit.
|
||||||
UTILS.CelsiusToFahrenheit = function( Celsius )
|
UTILS.CelsiusToFahrenheit = function( Celcius )
|
||||||
return Celsius * 9 / 5 + 32
|
return Celcius * 9/5 + 32
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert pressure from hectopascal (hPa) to inches of mercury (inHg).
|
--- Convert pressure from hecto Pascal (hPa) to inches of mercury (inHg).
|
||||||
-- @param #number hPa Pressure in hPa.
|
-- @param #number hPa Pressure in hPa.
|
||||||
-- @return #number Pressure in inHg.
|
-- @return #number Pressure in inHg.
|
||||||
UTILS.hPa2inHg = function( hPa )
|
UTILS.hPa2inHg = function( hPa )
|
||||||
return hPa * 0.0295299830714
|
return hPa * 0.0295299830714
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert knots to altitude corrected KIAS, e.g. for tankers.
|
--- Convert knots to alitude corrected KIAS, e.g. for tankers.
|
||||||
-- @param #number knots Speed in knots.
|
-- @param #number knots Speed in knots.
|
||||||
-- @param #number altitude Altitude in feet
|
-- @param #number altitude Altitude in feet
|
||||||
-- @return #number Corrected KIAS
|
-- @return #number Corrected KIAS
|
||||||
@@ -433,14 +497,14 @@ UTILS.KnotsToAltKIAS = function( knots, altitude )
|
|||||||
return (knots * 0.018 * (altitude / 1000)) + knots
|
return (knots * 0.018 * (altitude / 1000)) + knots
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert pressure from hectopascal (hPa) to millimeters of mercury (mmHg).
|
--- Convert pressure from hecto Pascal (hPa) to millimeters of mercury (mmHg).
|
||||||
-- @param #number hPa Pressure in hPa.
|
-- @param #number hPa Pressure in hPa.
|
||||||
-- @return #number Pressure in mmHg.
|
-- @return #number Pressure in mmHg.
|
||||||
UTILS.hPa2mmHg = function( hPa )
|
UTILS.hPa2mmHg = function( hPa )
|
||||||
return hPa * 0.7500615613030
|
return hPa * 0.7500615613030
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert kilograms (kg) to pounds (lbs).
|
--- Convert kilo gramms (kg) to pounds (lbs).
|
||||||
-- @param #number kg Mass in kg.
|
-- @param #number kg Mass in kg.
|
||||||
-- @return #number Mass in lbs.
|
-- @return #number Mass in lbs.
|
||||||
UTILS.kg2lbs = function( kg )
|
UTILS.kg2lbs = function( kg )
|
||||||
@@ -507,7 +571,8 @@ UTILS.tostringLL = function( lat, lon, acc, DMS )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- 024° 23' 12"N or 024° 23' 12.03"N
|
-- 024° 23' 12"N or 024° 23' 12.03"N
|
||||||
return string.format( '%03d°', latDeg ) .. string.format( '%02d', latMin ) .. '\'' .. string.format( secFrmtStr, latSec ) .. '"' .. latHemi .. ' ' .. string.format( '%03d°', lonDeg ) .. string.format( '%02d', lonMin ) .. '\'' .. string.format( secFrmtStr, lonSec ) .. '"' .. lonHemi
|
return string.format('%03d°', latDeg)..string.format('%02d', latMin)..'\''..string.format(secFrmtStr, latSec)..'"'..latHemi..' '
|
||||||
|
.. string.format('%03d°', lonDeg)..string.format('%02d', lonMin)..'\''..string.format(secFrmtStr, lonSec)..'"'..lonHemi
|
||||||
|
|
||||||
else -- degrees, decimal minutes.
|
else -- degrees, decimal minutes.
|
||||||
latMin = UTILS.Round(latMin, acc)
|
latMin = UTILS.Round(latMin, acc)
|
||||||
@@ -532,7 +597,8 @@ UTILS.tostringLL = function( lat, lon, acc, DMS )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- 024 23'N or 024 23.123'N
|
-- 024 23'N or 024 23.123'N
|
||||||
return string.format( '%03d°', latDeg ) .. ' ' .. string.format( minFrmtStr, latMin ) .. '\'' .. latHemi .. ' ' .. string.format( '%03d°', lonDeg ) .. ' ' .. string.format( minFrmtStr, lonMin ) .. '\'' .. lonHemi
|
return string.format('%03d°', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' '
|
||||||
|
.. string.format('%03d°', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -557,12 +623,8 @@ UTILS.tostringMGRS = function( MGRS, acc ) -- R2.1
|
|||||||
local nN=5-string.len(Northing)
|
local nN=5-string.len(Northing)
|
||||||
|
|
||||||
-- Get leading zeros (if any).
|
-- Get leading zeros (if any).
|
||||||
for i = 1, nE do
|
for i=1,nE do Easting="0"..Easting end
|
||||||
Easting = "0" .. Easting
|
for i=1,nN do Northing="0"..Northing end
|
||||||
end
|
|
||||||
for i = 1, nN do
|
|
||||||
Northing = "0" .. Northing
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Return MGRS string.
|
-- Return MGRS string.
|
||||||
return string.format("%s %s %s %s", MGRS.UTMZone, MGRS.MGRSDigraph, string.sub(Easting, 1, acc), string.sub(Northing, 1, acc))
|
return string.format("%s %s %s %s", MGRS.UTMZone, MGRS.MGRSDigraph, string.sub(Easting, 1, acc), string.sub(Northing, 1, acc))
|
||||||
@@ -570,6 +632,7 @@ UTILS.tostringMGRS = function( MGRS, acc ) -- R2.1
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- From http://lua-users.org/wiki/SimpleRound
|
--- From http://lua-users.org/wiki/SimpleRound
|
||||||
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
|
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
|
||||||
function UTILS.Round( num, idp )
|
function UTILS.Round( num, idp )
|
||||||
@@ -591,16 +654,12 @@ end
|
|||||||
function UTILS.spairs( t, order )
|
function UTILS.spairs( t, order )
|
||||||
-- collect the keys
|
-- collect the keys
|
||||||
local keys = {}
|
local keys = {}
|
||||||
for k in pairs( t ) do
|
for k in pairs(t) do keys[#keys+1] = k end
|
||||||
keys[#keys + 1] = k
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if order function given, sort by it by passing the table and keys a, b,
|
-- if order function given, sort by it by passing the table and keys a, b,
|
||||||
-- otherwise just sort the keys
|
-- otherwise just sort the keys
|
||||||
if order then
|
if order then
|
||||||
table.sort( keys, function( a, b )
|
table.sort(keys, function(a,b) return order(t, a, b) end)
|
||||||
return order( t, a, b )
|
|
||||||
end )
|
|
||||||
else
|
else
|
||||||
table.sort(keys)
|
table.sort(keys)
|
||||||
end
|
end
|
||||||
@@ -615,22 +674,18 @@ function UTILS.spairs( t, order )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Here is a customized version of pairs, which I called kpairs because it iterates over the table in a sorted order, based on a function that will determine the keys as reference first.
|
-- Here is a customized version of pairs, which I called kpairs because it iterates over the table in a sorted order, based on a function that will determine the keys as reference first.
|
||||||
function UTILS.kpairs( t, getkey, order )
|
function UTILS.kpairs( t, getkey, order )
|
||||||
-- collect the keys
|
-- collect the keys
|
||||||
local keys = {}
|
local keys = {}
|
||||||
local keyso = {}
|
local keyso = {}
|
||||||
for k, o in pairs( t ) do
|
for k, o in pairs(t) do keys[#keys+1] = k keyso[#keyso+1] = getkey( o ) end
|
||||||
keys[#keys + 1] = k
|
|
||||||
keyso[#keyso + 1] = getkey( o )
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if order function given, sort by it by passing the table and keys a, b,
|
-- if order function given, sort by it by passing the table and keys a, b,
|
||||||
-- otherwise just sort the keys
|
-- otherwise just sort the keys
|
||||||
if order then
|
if order then
|
||||||
table.sort( keys, function( a, b )
|
table.sort(keys, function(a,b) return order(t, a, b) end)
|
||||||
return order( t, a, b )
|
|
||||||
end )
|
|
||||||
else
|
else
|
||||||
table.sort(keys)
|
table.sort(keys)
|
||||||
end
|
end
|
||||||
@@ -650,9 +705,7 @@ function UTILS.rpairs( t )
|
|||||||
-- collect the keys
|
-- collect the keys
|
||||||
|
|
||||||
local keys = {}
|
local keys = {}
|
||||||
for k in pairs( t ) do
|
for k in pairs(t) do keys[#keys+1] = k end
|
||||||
keys[#keys + 1] = k
|
|
||||||
end
|
|
||||||
|
|
||||||
local random = {}
|
local random = {}
|
||||||
local j = #keys
|
local j = #keys
|
||||||
@@ -691,6 +744,7 @@ function UTILS.RemoveMark( MarkID, Delay )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Test if a Vec2 is in a radius of another Vec2
|
-- Test if a Vec2 is in a radius of another Vec2
|
||||||
function UTILS.IsInRadius( InVec2, Vec2, Radius )
|
function UTILS.IsInRadius( InVec2, Vec2, Radius )
|
||||||
|
|
||||||
@@ -757,9 +811,9 @@ function UTILS.BeaufortScale( speed )
|
|||||||
return bn,bd
|
return bn,bd
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Split string at separators. C.f. http://stackoverflow.com/questions/1426954/split-string-in-lua
|
--- Split string at seperators. C.f. [split-string-in-lua](http://stackoverflow.com/questions/1426954/split-string-in-lua).
|
||||||
-- @param #string str Sting to split.
|
-- @param #string str Sting to split.
|
||||||
-- @param #string sep Separator for split.
|
-- @param #string sep Speparator for split.
|
||||||
-- @return #table Split text.
|
-- @return #table Split text.
|
||||||
function UTILS.Split(str, sep)
|
function UTILS.Split(str, sep)
|
||||||
local result = {}
|
local result = {}
|
||||||
@@ -836,7 +890,7 @@ function UTILS.SecondsOfToday()
|
|||||||
return UTILS.ClockToSeconds(clock)
|
return UTILS.ClockToSeconds(clock)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Count seconds until next midnight.
|
--- Cound seconds until next midnight.
|
||||||
-- @return #number Seconds to midnight.
|
-- @return #number Seconds to midnight.
|
||||||
function UTILS.SecondsToMidnight()
|
function UTILS.SecondsToMidnight()
|
||||||
return 24*60*60-UTILS.SecondsOfToday()
|
return 24*60*60-UTILS.SecondsOfToday()
|
||||||
@@ -987,6 +1041,7 @@ function UTILS.Vec2Dot( a, b )
|
|||||||
return a.x*b.x + a.y*b.y
|
return a.x*b.x + a.y*b.y
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Calculate the [euclidean norm](https://en.wikipedia.org/wiki/Euclidean_distance) (length) of a 3D vector.
|
--- Calculate the [euclidean norm](https://en.wikipedia.org/wiki/Euclidean_distance) (length) of a 3D vector.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @return #number Norm of the vector.
|
-- @return #number Norm of the vector.
|
||||||
@@ -1014,6 +1069,7 @@ function UTILS.VecDist2D( a, b )
|
|||||||
return d
|
return d
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Calculate the distance between two 3D vectors.
|
--- Calculate the distance between two 3D vectors.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
@@ -1043,6 +1099,14 @@ function UTILS.VecSubstract( a, b )
|
|||||||
return {x=a.x-b.x, y=a.y-b.y, z=a.z-b.z}
|
return {x=a.x-b.x, y=a.y-b.y, z=a.z-b.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Calculate the difference between two 2D vectors by substracting the x,y components from each other.
|
||||||
|
-- @param DCS#Vec2 a Vector in 2D with x, y components.
|
||||||
|
-- @param DCS#Vec2 b Vector in 2D with x, y components.
|
||||||
|
-- @return DCS#Vec2 Vector c=a-b with c(i)=a(i)-b(i), i=x,y.
|
||||||
|
function UTILS.Vec2Substract(a, b)
|
||||||
|
return {x=a.x-b.x, y=a.y-b.y}
|
||||||
|
end
|
||||||
|
|
||||||
--- Calculate the total vector of two 3D vectors by adding the x,y,z components of each other.
|
--- Calculate the total vector of two 3D vectors by adding the x,y,z components of each other.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
@@ -1051,6 +1115,14 @@ function UTILS.VecAdd( a, b )
|
|||||||
return {x=a.x+b.x, y=a.y+b.y, z=a.z+b.z}
|
return {x=a.x+b.x, y=a.y+b.y, z=a.z+b.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Calculate the total vector of two 2D vectors by adding the x,y components of each other.
|
||||||
|
-- @param DCS#Vec2 a Vector in 2D with x, y components.
|
||||||
|
-- @param DCS#Vec2 b Vector in 2D with x, y components.
|
||||||
|
-- @return DCS#Vec2 Vector c=a+b with c(i)=a(i)+b(i), i=x,y.
|
||||||
|
function UTILS.Vec2Add(a, b)
|
||||||
|
return {x=a.x+b.x, y=a.y+b.y}
|
||||||
|
end
|
||||||
|
|
||||||
--- Calculate the angle between two 3D vectors.
|
--- Calculate the angle between two 3D vectors.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
@@ -1112,6 +1184,7 @@ function UTILS.HdgDiff( h1, h2 )
|
|||||||
return math.abs(delta)
|
return math.abs(delta)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Translate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged.
|
--- Translate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged.
|
||||||
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
-- @param #number distance The distance to translate.
|
-- @param #number distance The distance to translate.
|
||||||
@@ -1183,6 +1256,7 @@ function UTILS.Vec2Rotate2D( a, angle )
|
|||||||
return A
|
return A
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Converts a TACAN Channel/Mode couple into a frequency in Hz.
|
--- Converts a TACAN Channel/Mode couple into a frequency in Hz.
|
||||||
-- @param #number TACANChannel The TACAN channel, i.e. the 10 in "10X".
|
-- @param #number TACANChannel The TACAN channel, i.e. the 10 in "10X".
|
||||||
-- @param #string TACANMode The TACAN mode, i.e. the "X" in "10X".
|
-- @param #string TACANMode The TACAN mode, i.e. the "X" in "10X".
|
||||||
@@ -1219,6 +1293,7 @@ function UTILS.TACANToFrequency( TACANChannel, TACANMode )
|
|||||||
return (A + TACANChannel - B) * 1000000
|
return (A + TACANChannel - B) * 1000000
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the DCS map/theatre as optained by env.mission.theatre
|
--- Returns the DCS map/theatre as optained by env.mission.theatre
|
||||||
-- @return #string DCS map name.
|
-- @return #string DCS map name.
|
||||||
function UTILS.GetDCSMap()
|
function UTILS.GetDCSMap()
|
||||||
@@ -1264,26 +1339,6 @@ function UTILS.GetMissionDayOfYear( Time )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the current date.
|
|
||||||
-- @return #string Mission date in yyyy/mm/dd format.
|
|
||||||
-- @return #number The year anno domini.
|
|
||||||
-- @return #number The month.
|
|
||||||
-- @return #number The day.
|
|
||||||
function UTILS.GetDate()
|
|
||||||
|
|
||||||
-- Mission start date
|
|
||||||
local date, year, month, day = UTILS.GetDCSMissionDate()
|
|
||||||
|
|
||||||
local time = timer.getAbsTime()
|
|
||||||
|
|
||||||
local clock = UTILS.SecondsToClock( time, false )
|
|
||||||
|
|
||||||
local x = tonumber( UTILS.Split( clock, "+" )[2] )
|
|
||||||
|
|
||||||
local day = day + x
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Returns the magnetic declination of the map.
|
--- Returns the magnetic declination of the map.
|
||||||
-- Returned values for the current maps are:
|
-- Returned values for the current maps are:
|
||||||
--
|
--
|
||||||
@@ -1294,6 +1349,7 @@ end
|
|||||||
-- * The Cannel Map -10 (West)
|
-- * The Cannel Map -10 (West)
|
||||||
-- * Syria +5 (East)
|
-- * Syria +5 (East)
|
||||||
-- * Mariana Islands +2 (East)
|
-- * Mariana Islands +2 (East)
|
||||||
|
-- * Falklands +12 (East) - note there's a LOT of deviation across the map, as we're closer to the South Pole
|
||||||
-- @param #string map (Optional) Map for which the declination is returned. Default is from env.mission.theatre
|
-- @param #string map (Optional) Map for which the declination is returned. Default is from env.mission.theatre
|
||||||
-- @return #number Declination in degrees.
|
-- @return #number Declination in degrees.
|
||||||
function UTILS.GetMagneticDeclination(map)
|
function UTILS.GetMagneticDeclination(map)
|
||||||
@@ -1316,6 +1372,8 @@ function UTILS.GetMagneticDeclination( map )
|
|||||||
declination=5
|
declination=5
|
||||||
elseif map==DCSMAP.MarianaIslands then
|
elseif map==DCSMAP.MarianaIslands then
|
||||||
declination=2
|
declination=2
|
||||||
|
elseif map==DCSMAP.Falklands then
|
||||||
|
declination=12
|
||||||
else
|
else
|
||||||
declination=0
|
declination=0
|
||||||
end
|
end
|
||||||
@@ -1353,6 +1411,7 @@ function UTILS.CheckMemory( output )
|
|||||||
return mem
|
return mem
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the coalition name from its numerical ID, e.g. coaliton.side.RED.
|
--- Get the coalition name from its numerical ID, e.g. coaliton.side.RED.
|
||||||
-- @param #number Coalition The coalition ID.
|
-- @param #number Coalition The coalition ID.
|
||||||
-- @return #string The coalition name, i.e. "Neutral", "Red" or "Blue" (or "Unknown").
|
-- @return #string The coalition name, i.e. "Neutral", "Red" or "Blue" (or "Unknown").
|
||||||
@@ -1393,6 +1452,23 @@ function UTILS.GetModulationName( Modulation )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the NATO reporting name of a unit type name
|
||||||
|
-- @param #number Typename The type name.
|
||||||
|
-- @return #string The Reporting name or "Bogey".
|
||||||
|
function UTILS.GetReportingName(Typename)
|
||||||
|
|
||||||
|
local typename = string.lower(Typename)
|
||||||
|
|
||||||
|
for name, value in pairs(ENUMS.ReportingName.NATO) do
|
||||||
|
local svalue = string.lower(value)
|
||||||
|
if string.find(typename,svalue,1,true) then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return "Bogey"
|
||||||
|
end
|
||||||
|
|
||||||
--- Get the callsign name from its enumerator value
|
--- Get the callsign name from its enumerator value
|
||||||
-- @param #number Callsign The enumerator callsign.
|
-- @param #number Callsign The enumerator callsign.
|
||||||
-- @return #string The callsign name or "Ghostrider".
|
-- @return #string The callsign name or "Ghostrider".
|
||||||
@@ -1422,6 +1498,48 @@ function UTILS.GetCallsignName( Callsign )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for name, value in pairs(CALLSIGN.B1B) do
|
||||||
|
if value==Callsign then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, value in pairs(CALLSIGN.B52) do
|
||||||
|
if value==Callsign then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, value in pairs(CALLSIGN.F15E) do
|
||||||
|
if value==Callsign then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, value in pairs(CALLSIGN.F16) do
|
||||||
|
if value==Callsign then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, value in pairs(CALLSIGN.F18) do
|
||||||
|
if value==Callsign then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, value in pairs(CALLSIGN.FARP) do
|
||||||
|
if value==Callsign then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, value in pairs(CALLSIGN.TransportAircraft) do
|
||||||
|
if value==Callsign then
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return "Ghostrider"
|
return "Ghostrider"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1452,6 +1570,7 @@ function UTILS.GMTToLocalTimeDifference()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the day of the year. Counting starts on 1st of January.
|
--- Get the day of the year. Counting starts on 1st of January.
|
||||||
-- @param #number Year The year.
|
-- @param #number Year The year.
|
||||||
-- @param #number Month The month.
|
-- @param #number Month The month.
|
||||||
@@ -1485,31 +1604,18 @@ function UTILS.GetSunRiseAndSet( DayOfYear, Latitude, Longitude, Rising, Tlocal
|
|||||||
local n=DayOfYear
|
local n=DayOfYear
|
||||||
Tlocal=Tlocal or 0
|
Tlocal=Tlocal or 0
|
||||||
|
|
||||||
|
|
||||||
-- Short cuts.
|
-- Short cuts.
|
||||||
local rad = math.rad
|
local rad = math.rad
|
||||||
local deg = math.deg
|
local deg = math.deg
|
||||||
local floor = math.floor
|
local floor = math.floor
|
||||||
local frac = function( n )
|
local frac = function(n) return n - floor(n) end
|
||||||
return n - floor( n )
|
local cos = function(d) return math.cos(rad(d)) end
|
||||||
end
|
local acos = function(d) return deg(math.acos(d)) end
|
||||||
local cos = function( d )
|
local sin = function(d) return math.sin(rad(d)) end
|
||||||
return math.cos( rad( d ) )
|
local asin = function(d) return deg(math.asin(d)) end
|
||||||
end
|
local tan = function(d) return math.tan(rad(d)) end
|
||||||
local acos = function( d )
|
local atan = function(d) return deg(math.atan(d)) end
|
||||||
return deg( math.acos( d ) )
|
|
||||||
end
|
|
||||||
local sin = function( d )
|
|
||||||
return math.sin( rad( d ) )
|
|
||||||
end
|
|
||||||
local asin = function( d )
|
|
||||||
return deg( math.asin( d ) )
|
|
||||||
end
|
|
||||||
local tan = function( d )
|
|
||||||
return math.tan( rad( d ) )
|
|
||||||
end
|
|
||||||
local atan = function( d )
|
|
||||||
return deg( math.atan( d ) )
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fit_into_range(val, min, max)
|
local function fit_into_range(val, min, max)
|
||||||
local range = max - min
|
local range = max - min
|
||||||
@@ -1619,15 +1725,21 @@ end
|
|||||||
-- @return #number Os time in seconds.
|
-- @return #number Os time in seconds.
|
||||||
function UTILS.GetOSTime()
|
function UTILS.GetOSTime()
|
||||||
if os then
|
if os then
|
||||||
return os.clock()
|
local ts = 0
|
||||||
end
|
local t = os.date("*t")
|
||||||
|
local s = t.sec
|
||||||
|
local m = t.min * 60
|
||||||
|
local h = t.hour * 3600
|
||||||
|
ts = s+m+h
|
||||||
|
return ts
|
||||||
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Shuffle a table accoring to Fisher Yeates algorithm
|
--- Shuffle a table accoring to Fisher Yeates algorithm
|
||||||
-- @param #table t Table to be shuffled
|
--@param #table t Table to be shuffled.
|
||||||
-- @return #table
|
--@return #table Shuffled table.
|
||||||
function UTILS.ShuffleTable(t)
|
function UTILS.ShuffleTable(t)
|
||||||
if t == nil or type(t) ~= "table" then
|
if t == nil or type(t) ~= "table" then
|
||||||
BASE:I("Error in ShuffleTable: Missing or wrong type of Argument")
|
BASE:I("Error in ShuffleTable: Missing or wrong type of Argument")
|
||||||
@@ -1645,60 +1757,99 @@ function UTILS.ShuffleTable( t )
|
|||||||
return TempTable
|
return TempTable
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get a random element of a table.
|
||||||
|
--@param #table t Table.
|
||||||
|
--@param #boolean replace If `true`, the drawn element is replaced, i.e. not deleted.
|
||||||
|
--@return #number Table element.
|
||||||
|
function UTILS.GetRandomTableElement(t, replace)
|
||||||
|
|
||||||
|
if t == nil or type(t) ~= "table" then
|
||||||
|
BASE:I("Error in ShuffleTable: Missing or wrong type of Argument")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
math.random()
|
||||||
|
|
||||||
|
local r=math.random(#t)
|
||||||
|
|
||||||
|
local element=t[r]
|
||||||
|
|
||||||
|
if not replace then
|
||||||
|
table.remove(t, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
return element
|
||||||
|
end
|
||||||
|
|
||||||
--- (Helicopter) Check if one loading door is open.
|
--- (Helicopter) Check if one loading door is open.
|
||||||
--@param #string unit_name Unit name to be checked
|
--@param #string unit_name Unit name to be checked
|
||||||
--@return #boolean Outcome - true if a (loading door) is open, false if not, nil if none exists.
|
--@return #boolean Outcome - true if a (loading door) is open, false if not, nil if none exists.
|
||||||
function UTILS.IsLoadingDoorOpen( unit_name )
|
function UTILS.IsLoadingDoorOpen( unit_name )
|
||||||
|
|
||||||
local ret_val = false
|
|
||||||
local unit = Unit.getByName(unit_name)
|
local unit = Unit.getByName(unit_name)
|
||||||
|
|
||||||
if unit ~= nil then
|
if unit ~= nil then
|
||||||
local type_name = unit:getTypeName()
|
local type_name = unit:getTypeName()
|
||||||
|
BASE:T("TypeName = ".. type_name)
|
||||||
|
|
||||||
if type_name == "Mi-8MT" and unit:getDrawArgumentValue( 38 ) == 1 or unit:getDrawArgumentValue( 86 ) == 1 or unit:getDrawArgumentValue( 250 ) < 0 then
|
if type_name == "Mi-8MT" and (unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1 or unit:getDrawArgumentValue(250) < 0) then
|
||||||
BASE:T(unit_name .. " Cargo doors are open or cargo door not present")
|
BASE:T(unit_name .. " Cargo doors are open or cargo door not present")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if type_name == "Mi-24P" and unit:getDrawArgumentValue( 38 ) == 1 or unit:getDrawArgumentValue( 86 ) == 1 then
|
if type_name == "Mi-24P" and (unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(86) == 1) then
|
||||||
BASE:T(unit_name .. " a side door is open")
|
BASE:T(unit_name .. " a side door is open")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if type_name == "UH-1H" and unit:getDrawArgumentValue( 43 ) == 1 or unit:getDrawArgumentValue( 44 ) == 1 then
|
if type_name == "UH-1H" and (unit:getDrawArgumentValue(43) == 1 or unit:getDrawArgumentValue(44) == 1) then
|
||||||
BASE:T(unit_name .. " a side door is open ")
|
BASE:T(unit_name .. " a side door is open ")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if string.find( type_name, "SA342" ) and unit:getDrawArgumentValue( 34 ) == 1 or unit:getDrawArgumentValue( 38 ) == 1 then
|
if string.find(type_name, "SA342" ) and (unit:getDrawArgumentValue(34) == 1) then
|
||||||
BASE:T( unit_name .. " front door(s) are open" )
|
BASE:T(unit_name .. " front door(s) are open or doors removed")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if string.find( type_name, "Hercules" ) and unit:getDrawArgumentValue( 1215 ) == 1 and unit:getDrawArgumentValue( 1216 ) == 1 then
|
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1215) == 1 and unit:getDrawArgumentValue(1216) == 1) then
|
||||||
BASE:T(unit_name .. " rear doors are open")
|
BASE:T(unit_name .. " rear doors are open")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1220) == 1 or unit:getDrawArgumentValue(1221) == 1) then
|
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1220) == 1 or unit:getDrawArgumentValue(1221) == 1) then
|
||||||
BASE:T(unit_name .. " para doors are open")
|
BASE:T(unit_name .. " para doors are open")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if string.find( type_name, "Hercules" ) and unit:getDrawArgumentValue( 1217 ) == 1 then
|
if string.find(type_name, "Hercules") and (unit:getDrawArgumentValue(1217) == 1) then
|
||||||
BASE:T(unit_name .. " side door is open")
|
BASE:T(unit_name .. " side door is open")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if string.find(type_name, "Bell-47") then -- bell aint got no doors so always ready to load injured soldiers
|
if string.find(type_name, "Bell-47") then -- bell aint got no doors so always ready to load injured soldiers
|
||||||
BASE:T(unit_name .. " door is open")
|
BASE:T(unit_name .. " door is open")
|
||||||
ret_val = true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if ret_val == false then
|
if string.find(type_name, "UH-60L") and (unit:getDrawArgumentValue(401) == 1 or unit:getDrawArgumentValue(402) == 1) then
|
||||||
BASE:T( unit_name .. " all doors are closed" )
|
BASE:T(unit_name .. " cargo door is open")
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
return ret_val
|
|
||||||
|
if string.find(type_name, "UH-60L" ) and (unit:getDrawArgumentValue(38) == 1 or unit:getDrawArgumentValue(400) == 1 ) then
|
||||||
|
BASE:T(unit_name .. " front door(s) are open")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if type_name == "AH-64D_BLK_II" then
|
||||||
|
BASE:T(unit_name .. " front door(s) are open")
|
||||||
|
return true -- no doors on this one ;)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
end -- nil
|
end -- nil
|
||||||
|
|
||||||
@@ -1838,7 +1989,9 @@ function UTILS.GenerateLaserCodes()
|
|||||||
while _code < 1777 and _count < 30 do
|
while _code < 1777 and _count < 30 do
|
||||||
while true do
|
while true do
|
||||||
_code = _code + 1
|
_code = _code + 1
|
||||||
if not ContainsDigit( _code, 8 ) and not ContainsDigit( _code, 9 ) and not ContainsDigit( _code, 0 ) then
|
if not ContainsDigit(_code, 8)
|
||||||
|
and not ContainsDigit(_code, 9)
|
||||||
|
and not ContainsDigit(_code, 0) then
|
||||||
table.insert(jtacGeneratedLaserCodes, _code)
|
table.insert(jtacGeneratedLaserCodes, _code)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@@ -2105,9 +2258,7 @@ end
|
|||||||
-- @return #table Table of data objects (tables) containing groupname, coordinate and group object. Returns nil when file cannot be read.
|
-- @return #table Table of data objects (tables) containing groupname, coordinate and group object. Returns nil when file cannot be read.
|
||||||
function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce)
|
function UTILS.LoadStationaryListOfGroups(Path,Filename,Reduce)
|
||||||
local reduce = true
|
local reduce = true
|
||||||
if Reduce == false then
|
if Reduce == false then reduce = false end
|
||||||
reduce = false
|
|
||||||
end
|
|
||||||
local filename = Filename or "StateListofGroups"
|
local filename = Filename or "StateListofGroups"
|
||||||
local datatable = {}
|
local datatable = {}
|
||||||
if UTILS.CheckFileExists(Path,filename) then
|
if UTILS.CheckFileExists(Path,filename) then
|
||||||
@@ -2126,9 +2277,8 @@ function UTILS.LoadStationaryListOfGroups( Path, Filename, Reduce )
|
|||||||
local data = { groupname=groupname, size=size, coordinate=coordinate, group=GROUP:FindByName(groupname) }
|
local data = { groupname=groupname, size=size, coordinate=coordinate, group=GROUP:FindByName(groupname) }
|
||||||
if reduce then
|
if reduce then
|
||||||
local actualgroup = GROUP:FindByName(groupname)
|
local actualgroup = GROUP:FindByName(groupname)
|
||||||
local actualsize = actualgroup:CountAliveUnits()
|
if actualgroup and actualgroup:IsAlive() and actualgroup:CountAliveUnits() > size then
|
||||||
if actualsize > size then
|
local reduction = actualgroup:CountAliveUnits() - size
|
||||||
local reduction = actualsize - size
|
|
||||||
BASE:I("Reducing groupsize by ".. reduction .. " units!")
|
BASE:I("Reducing groupsize by ".. reduction .. " units!")
|
||||||
-- reduce existing group
|
-- reduce existing group
|
||||||
local units = actualgroup:GetUnits()
|
local units = actualgroup:GetUnits()
|
||||||
@@ -2154,9 +2304,7 @@ end
|
|||||||
-- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate }`
|
-- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate }`
|
||||||
function UTILS.LoadSetOfGroups(Path,Filename,Spawn)
|
function UTILS.LoadSetOfGroups(Path,Filename,Spawn)
|
||||||
local spawn = true
|
local spawn = true
|
||||||
if Spawn == false then
|
if Spawn == false then spawn = false end
|
||||||
spawn = false
|
|
||||||
end
|
|
||||||
BASE:I("Spawn = "..tostring(spawn))
|
BASE:I("Spawn = "..tostring(spawn))
|
||||||
local filename = Filename or "SetOfGroups"
|
local filename = Filename or "SetOfGroups"
|
||||||
local setdata = SET_GROUP:New()
|
local setdata = SET_GROUP:New()
|
||||||
@@ -2179,7 +2327,10 @@ function UTILS.LoadSetOfGroups( Path, Filename, Spawn )
|
|||||||
local data = { groupname=groupname, size=size, coordinate=coordinate }
|
local data = { groupname=groupname, size=size, coordinate=coordinate }
|
||||||
table.insert(datatable,data)
|
table.insert(datatable,data)
|
||||||
if spawn then
|
if spawn then
|
||||||
local group = SPAWN:New( groupname ):InitDelayOff():OnSpawnGroup( function( spwndgrp )
|
local group = SPAWN:New(groupname)
|
||||||
|
:InitDelayOff()
|
||||||
|
:OnSpawnGroup(
|
||||||
|
function(spwndgrp)
|
||||||
setdata:AddObject(spwndgrp)
|
setdata:AddObject(spwndgrp)
|
||||||
local actualsize = spwndgrp:CountAliveUnits()
|
local actualsize = spwndgrp:CountAliveUnits()
|
||||||
if actualsize > size then
|
if actualsize > size then
|
||||||
@@ -2191,7 +2342,9 @@ function UTILS.LoadSetOfGroups( Path, Filename, Spawn )
|
|||||||
units2[i]:Destroy(false)
|
units2[i]:Destroy(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end ):SpawnFromCoordinate( coordinate )
|
end
|
||||||
|
)
|
||||||
|
:SpawnFromCoordinate(coordinate)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -2239,9 +2392,7 @@ end
|
|||||||
-- Returns nil when file cannot be read.
|
-- Returns nil when file cannot be read.
|
||||||
function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce)
|
function UTILS.LoadStationaryListOfStatics(Path,Filename,Reduce)
|
||||||
local reduce = true
|
local reduce = true
|
||||||
if Reduce == false then
|
if Reduce == false then reduce = false end
|
||||||
reduce = false
|
|
||||||
end
|
|
||||||
local filename = Filename or "StateListofStatics"
|
local filename = Filename or "StateListofStatics"
|
||||||
local datatable = {}
|
local datatable = {}
|
||||||
if UTILS.CheckFileExists(Path,filename) then
|
if UTILS.CheckFileExists(Path,filename) then
|
||||||
@@ -2271,3 +2422,50 @@ function UTILS.LoadStationaryListOfStatics( Path, Filename, Reduce )
|
|||||||
end
|
end
|
||||||
return datatable
|
return datatable
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Heading Degrees (0-360) to Cardinal
|
||||||
|
-- @param #number Heading The heading
|
||||||
|
-- @return #string Cardinal, e.g. "NORTH"
|
||||||
|
function UTILS.BearingToCardinal(Heading)
|
||||||
|
if Heading >= 0 and Heading <= 22 then return "North"
|
||||||
|
elseif Heading >= 23 and Heading <= 66 then return "North-East"
|
||||||
|
elseif Heading >= 67 and Heading <= 101 then return "East"
|
||||||
|
elseif Heading >= 102 and Heading <= 146 then return "South-East"
|
||||||
|
elseif Heading >= 147 and Heading <= 201 then return "South"
|
||||||
|
elseif Heading >= 202 and Heading <= 246 then return "South-West"
|
||||||
|
elseif Heading >= 247 and Heading <= 291 then return "West"
|
||||||
|
elseif Heading >= 292 and Heading <= 338 then return "North-West"
|
||||||
|
elseif Heading >= 339 then return "North"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a BRAA NATO call string BRAA between two GROUP objects
|
||||||
|
-- @param Wrapper.Group#GROUP FromGrp GROUP object
|
||||||
|
-- @param Wrapper.Group#GROUP ToGrp GROUP object
|
||||||
|
-- @return #string Formatted BRAA NATO call
|
||||||
|
function UTILS.ToStringBRAANATO(FromGrp,ToGrp)
|
||||||
|
local BRAANATO = "Merged."
|
||||||
|
local GroupNumber = FromGrp:GetSize()
|
||||||
|
local GroupWords = "Singleton"
|
||||||
|
if GroupNumber == 2 then GroupWords = "Two-Ship"
|
||||||
|
elseif GroupNumber >= 3 then GroupWords = "Heavy"
|
||||||
|
end
|
||||||
|
local grpLeadUnit = ToGrp:GetUnit(1)
|
||||||
|
local tgtCoord = grpLeadUnit:GetCoordinate()
|
||||||
|
local currentCoord = FromGrp:GetCoordinate()
|
||||||
|
local hdg = UTILS.Round(ToGrp:GetHeading()/100,1)*100
|
||||||
|
local bearing = UTILS.Round(currentCoord:HeadingTo(tgtCoord),0)
|
||||||
|
local rangeMetres = tgtCoord:Get2DDistance(currentCoord)
|
||||||
|
local rangeNM = UTILS.Round( UTILS.MetersToNM(rangeMetres), 0)
|
||||||
|
local aspect = tgtCoord:ToStringAspect(currentCoord)
|
||||||
|
local alt = UTILS.Round(UTILS.MetersToFeet(grpLeadUnit:GetAltitude())/1000,0)--*1000
|
||||||
|
local track = UTILS.BearingToCardinal(hdg)
|
||||||
|
if rangeNM > 3 then
|
||||||
|
if aspect == "" then
|
||||||
|
BRAANATO = string.format("%s, BRA, %03d, %d miles, Angels %d, Track %s",GroupWords,bearing, rangeNM, alt, track)
|
||||||
|
else
|
||||||
|
BRAANATO = string.format("%s, BRAA, %03d, %d miles, Angels %d, %s, Track %s",GroupWords, bearing, rangeNM, alt, aspect, track)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return BRAANATO
|
||||||
|
end
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
-- @module Wrapper.Airbase
|
-- @module Wrapper.Airbase
|
||||||
-- @image Wrapper_Airbase.JPG
|
-- @image Wrapper_Airbase.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type AIRBASE
|
--- @type AIRBASE
|
||||||
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
|
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
|
||||||
-- @field #table CategoryName Names of airbase categories.
|
-- @field #table CategoryName Names of airbase categories.
|
||||||
@@ -52,7 +51,7 @@
|
|||||||
-- * @{#AIRBASE.Find}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase object.
|
-- * @{#AIRBASE.Find}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase object.
|
||||||
-- * @{#AIRBASE.FindByName}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase name.
|
-- * @{#AIRBASE.FindByName}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase name.
|
||||||
--
|
--
|
||||||
-- IMPORTANT: ONE SHOULD NEVER SANATIZE these AIRBASE OBJECT REFERENCES! (make the AIRBASE object references nil).
|
-- IMPORTANT: ONE SHOULD NEVER SANITIZE these AIRBASE OBJECT REFERENCES! (make the AIRBASE object references nil).
|
||||||
--
|
--
|
||||||
-- ## DCS Airbase APIs
|
-- ## DCS Airbase APIs
|
||||||
--
|
--
|
||||||
@@ -137,7 +136,7 @@ AIRBASE.Caucasus = {
|
|||||||
-- * AIRBASE.Nevada.Laughlin_Airport
|
-- * AIRBASE.Nevada.Laughlin_Airport
|
||||||
-- * AIRBASE.Nevada.Lincoln_County
|
-- * AIRBASE.Nevada.Lincoln_County
|
||||||
-- * AIRBASE.Nevada.Mesquite
|
-- * AIRBASE.Nevada.Mesquite
|
||||||
-- * AIRBASE.Nevada.Mina_Airport_3Q0
|
-- * AIRBASE.Nevada.Mina_Airport
|
||||||
-- * AIRBASE.Nevada.North_Las_Vegas
|
-- * AIRBASE.Nevada.North_Las_Vegas
|
||||||
-- * AIRBASE.Nevada.Pahute_Mesa_Airstrip
|
-- * AIRBASE.Nevada.Pahute_Mesa_Airstrip
|
||||||
-- * AIRBASE.Nevada.Tonopah_Airport
|
-- * AIRBASE.Nevada.Tonopah_Airport
|
||||||
@@ -145,23 +144,23 @@ AIRBASE.Caucasus = {
|
|||||||
--
|
--
|
||||||
-- @field Nevada
|
-- @field Nevada
|
||||||
AIRBASE.Nevada = {
|
AIRBASE.Nevada = {
|
||||||
["Creech_AFB"] = "Creech AFB",
|
["Creech_AFB"] = "Creech",
|
||||||
["Groom_Lake_AFB"] = "Groom Lake AFB",
|
["Groom_Lake_AFB"] = "Groom Lake",
|
||||||
["McCarran_International_Airport"] = "McCarran International Airport",
|
["McCarran_International_Airport"] = "McCarran International",
|
||||||
["Nellis_AFB"] = "Nellis AFB",
|
["Nellis_AFB"] = "Nellis",
|
||||||
["Beatty_Airport"] = "Beatty Airport",
|
["Beatty_Airport"] = "Beatty",
|
||||||
["Boulder_City_Airport"] = "Boulder City Airport",
|
["Boulder_City_Airport"] = "Boulder City",
|
||||||
["Echo_Bay"] = "Echo Bay",
|
["Echo_Bay"] = "Echo Bay",
|
||||||
["Henderson_Executive_Airport"] = "Henderson Executive Airport",
|
["Henderson_Executive_Airport"] = "Henderson Executive",
|
||||||
["Jean_Airport"] = "Jean Airport",
|
["Jean_Airport"] = "Jean",
|
||||||
["Laughlin_Airport"] = "Laughlin Airport",
|
["Laughlin_Airport"] = "Laughlin",
|
||||||
["Lincoln_County"] = "Lincoln County",
|
["Lincoln_County"] = "Lincoln County",
|
||||||
["Mesquite"] = "Mesquite",
|
["Mesquite"] = "Mesquite",
|
||||||
["Mina_Airport_3Q0"] = "Mina Airport 3Q0",
|
["Mina_Airport"] = "Mina",
|
||||||
["North_Las_Vegas"] = "North Las Vegas",
|
["North_Las_Vegas"] = "North Las Vegas",
|
||||||
["Pahute_Mesa_Airstrip"] = "Pahute Mesa Airstrip",
|
["Pahute_Mesa_Airstrip"] = "Pahute Mesa",
|
||||||
["Tonopah_Airport"] = "Tonopah Airport",
|
["Tonopah_Airport"] = "Tonopah",
|
||||||
["Tonopah_Test_Range_Airfield"] = "Tonopah Test Range Airfield",
|
["Tonopah_Test_Range_Airfield"] = "Tonopah Test Range",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Airbases of the Normandy map:
|
--- Airbases of the Normandy map:
|
||||||
@@ -316,6 +315,9 @@ AIRBASE.PersianGulf = {
|
|||||||
-- * AIRBASE.TheChannel.Lympne
|
-- * AIRBASE.TheChannel.Lympne
|
||||||
-- * AIRBASE.TheChannel.Detling
|
-- * AIRBASE.TheChannel.Detling
|
||||||
-- * AIRBASE.TheChannel.High_Halden
|
-- * AIRBASE.TheChannel.High_Halden
|
||||||
|
-- * AIRBASE.TheChannel.Biggin_Hill
|
||||||
|
-- * AIRBASE.TheChannel.Eastchurch
|
||||||
|
-- * AIRBASE.TheChannel.Headcorn
|
||||||
--
|
--
|
||||||
-- @field TheChannel
|
-- @field TheChannel
|
||||||
AIRBASE.TheChannel = {
|
AIRBASE.TheChannel = {
|
||||||
@@ -328,6 +330,9 @@ AIRBASE.TheChannel = {
|
|||||||
["Lympne"] = "Lympne",
|
["Lympne"] = "Lympne",
|
||||||
["Detling"] = "Detling",
|
["Detling"] = "Detling",
|
||||||
["High_Halden"] = "High Halden",
|
["High_Halden"] = "High Halden",
|
||||||
|
["Biggin_Hill"] = "Biggin Hill",
|
||||||
|
["Eastchurch"] = "Eastchurch",
|
||||||
|
["Headcorn"] = "Headcorn",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Airbases of the Syria map:
|
--- Airbases of the Syria map:
|
||||||
@@ -346,7 +351,6 @@ AIRBASE.TheChannel = {
|
|||||||
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
-- * AIRBASE.Syria.Wujah_Al_Hajar
|
||||||
-- * AIRBASE.Syria.Al_Dumayr
|
-- * AIRBASE.Syria.Al_Dumayr
|
||||||
-- * AIRBASE.Syria.Gazipasa
|
-- * AIRBASE.Syria.Gazipasa
|
||||||
-- * AIRBASE.Syria.Ru_Convoy_4
|
|
||||||
-- * AIRBASE.Syria.Hatay
|
-- * AIRBASE.Syria.Hatay
|
||||||
-- * AIRBASE.Syria.Nicosia
|
-- * AIRBASE.Syria.Nicosia
|
||||||
-- * AIRBASE.Syria.Pinarbashi
|
-- * AIRBASE.Syria.Pinarbashi
|
||||||
@@ -364,7 +368,6 @@ AIRBASE.TheChannel = {
|
|||||||
-- * AIRBASE.Syria.Akrotiri
|
-- * AIRBASE.Syria.Akrotiri
|
||||||
-- * AIRBASE.Syria.Naqoura
|
-- * AIRBASE.Syria.Naqoura
|
||||||
-- * AIRBASE.Syria.Gaziantep
|
-- * AIRBASE.Syria.Gaziantep
|
||||||
-- * AIRBASE.Syria.CVN_71
|
|
||||||
-- * AIRBASE.Syria.Sayqal
|
-- * AIRBASE.Syria.Sayqal
|
||||||
-- * AIRBASE.Syria.Tiyas
|
-- * AIRBASE.Syria.Tiyas
|
||||||
-- * AIRBASE.Syria.Shayrat
|
-- * AIRBASE.Syria.Shayrat
|
||||||
@@ -385,6 +388,17 @@ AIRBASE.TheChannel = {
|
|||||||
-- * AIRBASE.Syria.Beirut_Rafic_Hariri
|
-- * AIRBASE.Syria.Beirut_Rafic_Hariri
|
||||||
-- * AIRBASE.Syria.An_Nasiriyah
|
-- * AIRBASE.Syria.An_Nasiriyah
|
||||||
-- * AIRBASE.Syria.Abu_al_Duhur
|
-- * AIRBASE.Syria.Abu_al_Duhur
|
||||||
|
-- * AIRBASE.Syria.At_Tanf
|
||||||
|
-- * AIRBASE.Syria.H3
|
||||||
|
-- * AIRBASE.Syria.H3_Northwest
|
||||||
|
-- * AIRBASE.Syria.H3_Southwest
|
||||||
|
-- * AIRBASE.Syria.Kharab_Ishk
|
||||||
|
-- * AIRBASE.Syria.Raj_al_Issa_East
|
||||||
|
-- * AIRBASE.Syria.Raj_al_Issa_West
|
||||||
|
-- * AIRBASE.Syria.Ruwayshid
|
||||||
|
-- * AIRBASE.Syria.Sanliurfa
|
||||||
|
-- * AIRBASE.Syria.Tal_Siman
|
||||||
|
-- * AIRBASE.Syria.Deir_ez_Zor
|
||||||
--
|
--
|
||||||
--@field Syria
|
--@field Syria
|
||||||
AIRBASE.Syria={
|
AIRBASE.Syria={
|
||||||
@@ -402,7 +416,7 @@ AIRBASE.Syria={
|
|||||||
["Wujah_Al_Hajar"]="Wujah Al Hajar",
|
["Wujah_Al_Hajar"]="Wujah Al Hajar",
|
||||||
["Al_Dumayr"]="Al-Dumayr",
|
["Al_Dumayr"]="Al-Dumayr",
|
||||||
["Gazipasa"]="Gazipasa",
|
["Gazipasa"]="Gazipasa",
|
||||||
["Ru_Convoy_4"]="Ru Convoy-4",
|
-- ["Ru_Convoy_4"]="Ru Convoy-4",
|
||||||
["Hatay"]="Hatay",
|
["Hatay"]="Hatay",
|
||||||
["Nicosia"]="Nicosia",
|
["Nicosia"]="Nicosia",
|
||||||
["Pinarbashi"]="Pinarbashi",
|
["Pinarbashi"]="Pinarbashi",
|
||||||
@@ -440,10 +454,19 @@ AIRBASE.Syria={
|
|||||||
["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri",
|
["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri",
|
||||||
["An_Nasiriyah"]="An Nasiriyah",
|
["An_Nasiriyah"]="An Nasiriyah",
|
||||||
["Abu_al_Duhur"]="Abu al-Duhur",
|
["Abu_al_Duhur"]="Abu al-Duhur",
|
||||||
|
["At_Tanf"]="At Tanf",
|
||||||
|
["H3"]="H3",
|
||||||
|
["H3_Northwest"]="H3 Northwest",
|
||||||
|
["H3_Southwest"]="H3 Southwest",
|
||||||
|
["Kharab_Ishk"]="Kharab Ishk",
|
||||||
|
["Raj_al_Issa_East"]="Raj al Issa East",
|
||||||
|
["Raj_al_Issa_West"]="Raj al Issa West",
|
||||||
|
["Ruwayshid"]="Ruwayshid",
|
||||||
|
["Sanliurfa"]="Sanliurfa",
|
||||||
|
["Tal_Siman"]="Tal Siman",
|
||||||
|
["Deir_ez_Zor"] = "Deir ez-Zor",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Airbases of the Mariana Islands map:
|
--- Airbases of the Mariana Islands map:
|
||||||
--
|
--
|
||||||
-- * AIRBASE.MarianaIslands.Rota_Intl
|
-- * AIRBASE.MarianaIslands.Rota_Intl
|
||||||
@@ -463,6 +486,39 @@ AIRBASE.MarianaIslands={
|
|||||||
["Olf_Orote"] = "Olf Orote",
|
["Olf_Orote"] = "Olf Orote",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Airbases of the South Atlantic map:
|
||||||
|
--
|
||||||
|
-- * AIRBASE.SouthAtlantic.Port_Stanley
|
||||||
|
-- * AIRBASE.SouthAtlantic.Mount_Pleasant
|
||||||
|
-- * AIRBASE.SouthAtlantic.San_Carlos_FOB
|
||||||
|
-- * AIRBASE.SouthAtlantic.Rio_Grande
|
||||||
|
-- * AIRBASE.SouthAtlantic.Rio_Gallegos
|
||||||
|
-- * AIRBASE.SouthAtlantic.Ushuaia
|
||||||
|
-- * AIRBASE.SouthAtlantic.Ushuaia_Helo_Port
|
||||||
|
-- * AIRBASE.SouthAtlantic.Punta_Arenas
|
||||||
|
-- * AIRBASE.SouthAtlantic.Pampa_Guanaco
|
||||||
|
-- * AIRBASE.SouthAtlantic.San_Julian
|
||||||
|
-- * AIRBASE.SouthAtlantic.Puerto_Williams
|
||||||
|
-- * AIRBASE.SouthAtlantic.Puerto_Natales
|
||||||
|
-- * AIRBASE.SouthAtlantic.El_Calafate
|
||||||
|
--
|
||||||
|
--@field MarianaIslands
|
||||||
|
AIRBASE.SouthAtlantic={
|
||||||
|
["Port_Stanley"]="Port Stanley",
|
||||||
|
["Mount_Pleasant"]="Mount Pleasant",
|
||||||
|
["San_Carlos_FOB"]="San Carlos FOB",
|
||||||
|
["Rio_Grande"]="Rio Grande",
|
||||||
|
["Rio_Gallegos"]="Rio Gallegos",
|
||||||
|
["Ushuaia"]="Ushuaia",
|
||||||
|
["Ushuaia_Helo_Port"]="Ushuaia Helo Port",
|
||||||
|
["Punta_Arenas"]="Punta Arenas",
|
||||||
|
["Pampa_Guanaco"]="Pampa Guanaco",
|
||||||
|
["San_Julian"]="San Julian",
|
||||||
|
["Puerto_Williams"]="Puerto Williams",
|
||||||
|
["Puerto_Natales"]="Puerto Natales",
|
||||||
|
["El_Calafate"]="El Calafate",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||||
-- @type AIRBASE.ParkingSpot
|
-- @type AIRBASE.ParkingSpot
|
||||||
@@ -772,7 +828,6 @@ function AIRBASE:SetParkingSpotBlacklist(TerminalIdBlacklist)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get category of airbase.
|
--- Get category of airbase.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @return #number Category of airbase from GetDesc().category.
|
-- @return #number Category of airbase from GetDesc().category.
|
||||||
@@ -1112,8 +1167,7 @@ function AIRBASE:MarkParkingSpots(termtype, mark)
|
|||||||
for _, _spot in pairs( parkingdata ) do
|
for _, _spot in pairs( parkingdata ) do
|
||||||
|
|
||||||
-- Mark text.
|
-- Mark text.
|
||||||
local _text=string.format("Term Index=%d, Term Type=%d, Free=%s, TOAC=%s, Term ID0=%d, Dist2Rwy=%.1f m",
|
local _text = string.format( "Term Index=%d, Term Type=%d, Free=%s, TOAC=%s, Term ID0=%d, Dist2Rwy=%.1f m", _spot.TerminalID, _spot.TerminalType, tostring( _spot.Free ), tostring( _spot.TOAC ), _spot.TerminalID0, _spot.DistToRwy )
|
||||||
_spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy)
|
|
||||||
|
|
||||||
-- Create mark on the F10 map.
|
-- Create mark on the F10 map.
|
||||||
if mark then
|
if mark then
|
||||||
@@ -1121,8 +1175,7 @@ function AIRBASE:MarkParkingSpots(termtype, mark)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Info to DCS.log file.
|
-- Info to DCS.log file.
|
||||||
local _text=string.format("%s, Term Index=%3d, Term Type=%03d, Free=%5s, TOAC=%5s, Term ID0=%3d, Dist2Rwy=%.1f m",
|
local _text = string.format( "%s, Term Index=%3d, Term Type=%03d, Free=%5s, TOAC=%5s, Term ID0=%3d, Dist2Rwy=%.1f m", airbasename, _spot.TerminalID, _spot.TerminalType, tostring( _spot.Free ), tostring( _spot.TOAC ), _spot.TerminalID0, _spot.DistToRwy )
|
||||||
airbasename, _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy)
|
|
||||||
self:E( _text )
|
self:E( _text )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1197,7 +1250,6 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
|||||||
az = 17 -- width
|
az = 17 -- width
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Number of spots we are looking for. Note that, e.g. grouping can require a number different from the group size!
|
-- Number of spots we are looking for. Note that, e.g. grouping can require a number different from the group size!
|
||||||
local _nspots = nspots or group:GetSize()
|
local _nspots = nspots or group:GetSize()
|
||||||
|
|
||||||
@@ -1344,7 +1396,6 @@ function AIRBASE:_CheckParkingLists(TerminalID)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Check if a whitelist was defined.
|
-- Check if a whitelist was defined.
|
||||||
if self.parkingWhitelist and #self.parkingWhitelist > 0 then
|
if self.parkingWhitelist and #self.parkingWhitelist > 0 then
|
||||||
for _, terminalID in pairs( self.parkingWhitelist or {} ) do
|
for _, terminalID in pairs( self.parkingWhitelist or {} ) do
|
||||||
@@ -1447,7 +1498,6 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
-- Airbase name.
|
-- Airbase name.
|
||||||
local name = self:GetName()
|
local name = self:GetName()
|
||||||
|
|
||||||
|
|
||||||
-- Exceptions
|
-- Exceptions
|
||||||
if name == AIRBASE.Nevada.Jean_Airport or
|
if name == AIRBASE.Nevada.Jean_Airport or
|
||||||
name == AIRBASE.Nevada.Creech_AFB or
|
name == AIRBASE.Nevada.Creech_AFB or
|
||||||
@@ -1535,7 +1585,6 @@ function AIRBASE:GetRunwayData(magvar, mark)
|
|||||||
return j
|
return j
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
for i = 1, N do
|
for i = 1, N do
|
||||||
|
|
||||||
-- Get the other spawn point coordinate.
|
-- Get the other spawn point coordinate.
|
||||||
|
|||||||
@@ -11,14 +11,11 @@
|
|||||||
-- @module Wrapper.Controllable
|
-- @module Wrapper.Controllable
|
||||||
-- @image Wrapper_Controllable.JPG
|
-- @image Wrapper_Controllable.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type CONTROLLABLE
|
--- @type CONTROLLABLE
|
||||||
-- @field DCS#Controllable DCSControllable The DCS controllable class.
|
-- @field DCS#Controllable DCSControllable The DCS controllable class.
|
||||||
-- @field #string ControllableName The name of the controllable.
|
-- @field #string ControllableName The name of the controllable.
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Wrapper class to handle the "DCS Controllable objects", which are Groups and Units:
|
--- Wrapper class to handle the "DCS Controllable objects", which are Groups and Units:
|
||||||
--
|
--
|
||||||
-- * Support all DCS Controllable APIs.
|
-- * Support all DCS Controllable APIs.
|
||||||
@@ -62,10 +59,10 @@
|
|||||||
-- * @{#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the controllable.
|
-- * @{#CONTROLLABLE.TaskHoldPosition}: (AIR) Hold position at the current position of the first unit of the controllable.
|
||||||
-- * @{#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only.
|
-- * @{#CONTROLLABLE.TaskLand}: (AIR HELICOPTER) Landing at the ground. For helicopters only.
|
||||||
-- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS).
|
-- * @{#CONTROLLABLE.TaskLandAtZone}: (AIR) Land the controllable at a @{Core.Zone#ZONE_RADIUS).
|
||||||
-- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude.
|
-- * @{#CONTROLLABLE.TaskOrbitCircle}: (AIR) Orbit at the current position of the first unit of the controllable at a specified altitude.
|
||||||
-- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed.
|
-- * @{#CONTROLLABLE.TaskOrbitCircleAtVec2}: (AIR) Orbit at a specified position at a specified altitude during a specified duration with a specified speed.
|
||||||
-- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters.
|
-- * @{#CONTROLLABLE.TaskRefueling}: (AIR) Refueling from the nearest tanker. No parameters.
|
||||||
-- * @{#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Misson task to follow a given route defined by Points.
|
-- * @{#CONTROLLABLE.TaskRoute}: (AIR + GROUND) Return a Mission task to follow a given route defined by Points.
|
||||||
-- * @{#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Controllable move to a given point.
|
-- * @{#CONTROLLABLE.TaskRouteToVec2}: (AIR + GROUND) Make the Controllable move to a given point.
|
||||||
-- * @{#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Controllable move to a given point.
|
-- * @{#CONTROLLABLE.TaskRouteToVec3}: (AIR + GROUND) Make the Controllable move to a given point.
|
||||||
-- * @{#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the controllable to a given zone.
|
-- * @{#CONTROLLABLE.TaskRouteToZone}: (AIR + GROUND) Route the controllable to a given zone.
|
||||||
@@ -86,7 +83,7 @@
|
|||||||
--
|
--
|
||||||
-- ## 2.3) Task preparation
|
-- ## 2.3) Task preparation
|
||||||
--
|
--
|
||||||
-- There are certain task methods that allow to tailor the task behaviour:
|
-- There are certain task methods that allow to tailor the task behavior:
|
||||||
--
|
--
|
||||||
-- * @{#CONTROLLABLE.TaskWrappedAction}: Return a WrappedAction Task taking a Command.
|
-- * @{#CONTROLLABLE.TaskWrappedAction}: Return a WrappedAction Task taking a Command.
|
||||||
-- * @{#CONTROLLABLE.TaskCombo}: Return a Combo Task taking an array of Tasks.
|
-- * @{#CONTROLLABLE.TaskCombo}: Return a Combo Task taking an array of Tasks.
|
||||||
@@ -133,7 +130,7 @@
|
|||||||
--
|
--
|
||||||
-- # 5) Option methods
|
-- # 5) Option methods
|
||||||
--
|
--
|
||||||
-- Controllable **Option methods** change the behaviour of the Controllable while being alive.
|
-- Controllable **Option methods** change the behavior of the Controllable while being alive.
|
||||||
--
|
--
|
||||||
-- ## 5.1) Rule of Engagement:
|
-- ## 5.1) Rule of Engagement:
|
||||||
--
|
--
|
||||||
@@ -215,7 +212,6 @@ end
|
|||||||
|
|
||||||
-- Get methods
|
-- Get methods
|
||||||
|
|
||||||
|
|
||||||
--- Returns the health. Dead controllables have health <= 1.0.
|
--- Returns the health. Dead controllables have health <= 1.0.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #number The controllable health value (unit or group average).
|
-- @return #number The controllable health value (unit or group average).
|
||||||
@@ -274,7 +270,7 @@ function CONTROLLABLE:GetLife0()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Returns relative minimum amount of fuel (from 0.0 to 1.0) a unit or group has in its internal tanks.
|
--- Returns relative minimum amount of fuel (from 0.0 to 1.0) a unit or group has in its internal tanks.
|
||||||
-- This method returns nil to ensure polymorphic behaviour! This method needs to be overridden by GROUP or UNIT.
|
-- This method returns nil to ensure polymorphic behavior! This method needs to be overridden by GROUP or UNIT.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #nil The CONTROLLABLE is not existing or alive.
|
-- @return #nil The CONTROLLABLE is not existing or alive.
|
||||||
function CONTROLLABLE:GetFuelMin()
|
function CONTROLLABLE:GetFuelMin()
|
||||||
@@ -284,7 +280,7 @@ function CONTROLLABLE:GetFuelMin()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Returns relative average amount of fuel (from 0.0 to 1.0) a unit or group has in its internal tanks.
|
--- Returns relative average amount of fuel (from 0.0 to 1.0) a unit or group has in its internal tanks.
|
||||||
-- This method returns nil to ensure polymorphic behaviour! This method needs to be overridden by GROUP or UNIT.
|
-- This method returns nil to ensure polymorphic behavior! This method needs to be overridden by GROUP or UNIT.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #nil The CONTROLLABLE is not existing or alive.
|
-- @return #nil The CONTROLLABLE is not existing or alive.
|
||||||
function CONTROLLABLE:GetFuelAve()
|
function CONTROLLABLE:GetFuelAve()
|
||||||
@@ -294,7 +290,7 @@ function CONTROLLABLE:GetFuelAve()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks.
|
--- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks.
|
||||||
-- This method returns nil to ensure polymorphic behaviour! This method needs to be overridden by GROUP or UNIT.
|
-- This method returns nil to ensure polymorphic behavior! This method needs to be overridden by GROUP or UNIT.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #nil The CONTROLLABLE is not existing or alive.
|
-- @return #nil The CONTROLLABLE is not existing or alive.
|
||||||
function CONTROLLABLE:GetFuel()
|
function CONTROLLABLE:GetFuel()
|
||||||
@@ -302,7 +298,6 @@ function CONTROLLABLE:GetFuel()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Tasks
|
-- Tasks
|
||||||
|
|
||||||
--- Clear all tasks from the controllable.
|
--- Clear all tasks from the controllable.
|
||||||
@@ -321,7 +316,6 @@ function CONTROLLABLE:ClearTasks()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Popping current Task from the controllable.
|
--- Popping current Task from the controllable.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return Wrapper.Controllable#CONTROLLABLE self
|
-- @return Wrapper.Controllable#CONTROLLABLE self
|
||||||
@@ -440,7 +434,6 @@ function CONTROLLABLE:HasTask() --R2.2
|
|||||||
return HasTaskResult
|
return HasTaskResult
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return a condition section for a controlled task.
|
--- Return a condition section for a controlled task.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Time time DCS mission time.
|
-- @param DCS#Time time DCS mission time.
|
||||||
@@ -485,8 +478,8 @@ function CONTROLLABLE:TaskControlled( DCSTask, DCSStopCondition )
|
|||||||
id = 'ControlledTask',
|
id = 'ControlledTask',
|
||||||
params = {
|
params = {
|
||||||
task = DCSTask,
|
task = DCSTask,
|
||||||
stopCondition = DCSStopCondition
|
stopCondition = DCSStopCondition,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTaskControlled
|
return DCSTaskControlled
|
||||||
@@ -501,8 +494,8 @@ function CONTROLLABLE:TaskCombo( DCSTasks )
|
|||||||
local DCSTaskCombo = {
|
local DCSTaskCombo = {
|
||||||
id = 'ComboTask',
|
id = 'ComboTask',
|
||||||
params = {
|
params = {
|
||||||
tasks = DCSTasks
|
tasks = DCSTasks,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTaskCombo
|
return DCSTaskCombo
|
||||||
@@ -540,9 +533,6 @@ function CONTROLLABLE:SetTaskWaypoint( Waypoint, Task )
|
|||||||
return Waypoint.task
|
return Waypoint.task
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Executes a command action for the CONTROLLABLE.
|
--- Executes a command action for the CONTROLLABLE.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Command DCSCommand The command to be executed.
|
-- @param DCS#Command DCSCommand The command to be executed.
|
||||||
@@ -567,10 +557,11 @@ end
|
|||||||
-- @param #number ToWayPoint
|
-- @param #number ToWayPoint
|
||||||
-- @return DCS#Task
|
-- @return DCS#Task
|
||||||
-- @usage
|
-- @usage
|
||||||
-- --- This test demonstrates the use(s) of the SwitchWayPoint method of the GROUP class.
|
--
|
||||||
|
-- -- This test demonstrates the use(s) of the SwitchWayPoint method of the GROUP class.
|
||||||
-- HeliGroup = GROUP:FindByName( "Helicopter" )
|
-- HeliGroup = GROUP:FindByName( "Helicopter" )
|
||||||
--
|
--
|
||||||
-- --- Route the helicopter back to the FARP after 60 seconds.
|
-- -- Route the helicopter back to the FARP after 60 seconds.
|
||||||
-- -- We use the SCHEDULER class to do this.
|
-- -- We use the SCHEDULER class to do this.
|
||||||
-- SCHEDULER:New( nil,
|
-- SCHEDULER:New( nil,
|
||||||
-- function( HeliGroup )
|
-- function( HeliGroup )
|
||||||
@@ -619,7 +610,6 @@ function CONTROLLABLE:CommandStopRoute( StopRoute )
|
|||||||
return CommandStopRoute
|
return CommandStopRoute
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Give an uncontrolled air controllable the start command.
|
--- Give an uncontrolled air controllable the start command.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number delay (Optional) Delay before start command in seconds.
|
-- @param #number delay (Optional) Delay before start command in seconds.
|
||||||
@@ -640,7 +630,7 @@ end
|
|||||||
-- @param Core.Radio#BEACON.Type Type Beacon type (VOR, DME, TACAN, RSBN, ILS etc).
|
-- @param Core.Radio#BEACON.Type Type Beacon type (VOR, DME, TACAN, RSBN, ILS etc).
|
||||||
-- @param Core.Radio#BEACON.System System Beacon system (VOR, DME, TACAN, RSBN, ILS etc).
|
-- @param Core.Radio#BEACON.System System Beacon system (VOR, DME, TACAN, RSBN, ILS etc).
|
||||||
-- @param #number Frequency Frequency in Hz the beacon is running on. Use @{#UTILS.TACANToFrequency} to generate a frequency for TACAN beacons.
|
-- @param #number Frequency Frequency in Hz the beacon is running on. Use @{#UTILS.TACANToFrequency} to generate a frequency for TACAN beacons.
|
||||||
-- @param #number UnitID The ID of the unit the beacon is attached to. Usefull if more units are in one group.
|
-- @param #number UnitID The ID of the unit the beacon is attached to. Useful if more units are in one group.
|
||||||
-- @param #number Channel Channel the beacon is using. For, e.g. TACAN beacons.
|
-- @param #number Channel Channel the beacon is using. For, e.g. TACAN beacons.
|
||||||
-- @param #string ModeChannel The TACAN mode of the beacon, i.e. "X" or "Y".
|
-- @param #string ModeChannel The TACAN mode of the beacon, i.e. "X" or "Y".
|
||||||
-- @param #boolean AA If true, create and Air-Air beacon. IF nil, automatically set if CONTROLLABLE depending on whether unit is and aircraft or not.
|
-- @param #boolean AA If true, create and Air-Air beacon. IF nil, automatically set if CONTROLLABLE depending on whether unit is and aircraft or not.
|
||||||
@@ -666,7 +656,7 @@ function CONTROLLABLE:CommandActivateBeacon(Type, System, Frequency, UnitID, Cha
|
|||||||
["AA"] = AA,
|
["AA"] = AA,
|
||||||
["callsign"] = Callsign,
|
["callsign"] = Callsign,
|
||||||
["bearing"] = Bearing,
|
["bearing"] = Bearing,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if Delay and Delay > 0 then
|
if Delay and Delay > 0 then
|
||||||
@@ -695,7 +685,7 @@ function CONTROLLABLE:CommandActivateICLS(Channel, UnitID, Callsign, Delay)
|
|||||||
["channel"] = Channel,
|
["channel"] = Channel,
|
||||||
["unitId"] = UnitID,
|
["unitId"] = UnitID,
|
||||||
["callsign"] = Callsign,
|
["callsign"] = Callsign,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if Delay and Delay > 0 then
|
if Delay and Delay > 0 then
|
||||||
@@ -707,6 +697,33 @@ function CONTROLLABLE:CommandActivateICLS(Channel, UnitID, Callsign, Delay)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Activate LINK4 system of the CONTROLLABLE. The controllable should be an aircraft carrier!
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number Frequency Link4 Frequency in MHz, e.g. 336
|
||||||
|
-- @param #number UnitID The DCS UNIT ID of the unit the LINK4 system is attached to. Useful if more units are in one group.
|
||||||
|
-- @param #string Callsign Morse code identification callsign.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds before the LINK4 is deactivated.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
|
||||||
|
|
||||||
|
-- Command to activate Link4 system.
|
||||||
|
local CommandActivateLink4= {
|
||||||
|
id = "ActivateLink4",
|
||||||
|
params= {
|
||||||
|
["frequency "] = Frequency*1000,
|
||||||
|
["unitId"] = UnitID,
|
||||||
|
["name"] = Callsign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
SCHEDULER:New(nil, self.CommandActivateLink4, {self}, Delay)
|
||||||
|
else
|
||||||
|
self:SetCommand(CommandActivateLink4)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Deactivate the active beacon of the CONTROLLABLE.
|
--- Deactivate the active beacon of the CONTROLLABLE.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
@@ -718,7 +735,7 @@ function CONTROLLABLE:CommandDeactivateBeacon(Delay)
|
|||||||
local CommandDeactivateBeacon = { id = 'DeactivateBeacon', params = {} }
|
local CommandDeactivateBeacon = { id = 'DeactivateBeacon', params = {} }
|
||||||
|
|
||||||
if Delay and Delay > 0 then
|
if Delay and Delay > 0 then
|
||||||
SCHEDULER:New(nil, self.CommandActivateBeacon, {self}, Delay)
|
SCHEDULER:New( nil, self.CommandDeactivateBeacon, { self }, Delay )
|
||||||
else
|
else
|
||||||
self:SetCommand( CommandDeactivateBeacon )
|
self:SetCommand( CommandDeactivateBeacon )
|
||||||
end
|
end
|
||||||
@@ -744,6 +761,24 @@ function CONTROLLABLE:CommandDeactivateICLS(Delay)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Deactivate the active Link4 of the CONTROLLABLE.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds before the Link4 is deactivated.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:CommandDeactivateLink4(Delay)
|
||||||
|
|
||||||
|
-- Command to deactivate
|
||||||
|
local CommandDeactivateLink4={id='DeactivateLink4', params={}}
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
SCHEDULER:New(nil, self.CommandDeactivateLink4, {self}, Delay)
|
||||||
|
else
|
||||||
|
self:SetCommand(CommandDeactivateLink4)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set callsign of the CONTROLLABLE. See [DCS command setCallsign](https://wiki.hoggitworld.com/view/DCS_command_setCallsign)
|
--- Set callsign of the CONTROLLABLE. See [DCS command setCallsign](https://wiki.hoggitworld.com/view/DCS_command_setCallsign)
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#CALLSIGN CallName Number corresponding the the callsign identifier you wish this group to be called.
|
-- @param DCS#CALLSIGN CallName Number corresponding the the callsign identifier you wish this group to be called.
|
||||||
@@ -780,8 +815,8 @@ function CONTROLLABLE:CommandEPLRS(SwitchOnOff, Delay)
|
|||||||
id = 'EPLRS',
|
id = 'EPLRS',
|
||||||
params = {
|
params = {
|
||||||
value = SwitchOnOff,
|
value = SwitchOnOff,
|
||||||
groupId=self:GetID()
|
groupId = self:GetID(),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if Delay and Delay > 0 then
|
if Delay and Delay > 0 then
|
||||||
@@ -798,7 +833,7 @@ end
|
|||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Frequency Radio frequency in MHz.
|
-- @param #number Frequency Radio frequency in MHz.
|
||||||
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
|
-- @param #number Modulation Radio modulation. Default `radio.modulation.AM`.
|
||||||
-- @param #number Delay (Optional) Delay in seconds before the frequncy is set. Default is immediately.
|
-- @param #number Delay (Optional) Delay in seconds before the frequency is set. Default is immediately.
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Delay )
|
function CONTROLLABLE:CommandSetFrequency( Frequency, Modulation, Delay )
|
||||||
|
|
||||||
@@ -807,7 +842,7 @@ function CONTROLLABLE:CommandSetFrequency(Frequency, Modulation, Delay)
|
|||||||
params = {
|
params = {
|
||||||
frequency = Frequency * 1000000,
|
frequency = Frequency * 1000000,
|
||||||
modulation = Modulation or radio.modulation.AM,
|
modulation = Modulation or radio.modulation.AM,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if Delay and Delay > 0 then
|
if Delay and Delay > 0 then
|
||||||
@@ -819,7 +854,6 @@ function CONTROLLABLE:CommandSetFrequency(Frequency, Modulation, Delay)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set EPLRS data link on/off.
|
--- Set EPLRS data link on/off.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #boolean SwitchOnOff If true (or nil) switch EPLRS on. If false switch off.
|
-- @param #boolean SwitchOnOff If true (or nil) switch EPLRS on. If false switch off.
|
||||||
@@ -836,14 +870,13 @@ function CONTROLLABLE:TaskEPLRS(SwitchOnOff, idx)
|
|||||||
id = 'EPLRS',
|
id = 'EPLRS',
|
||||||
params = {
|
params = {
|
||||||
value = SwitchOnOff,
|
value = SwitchOnOff,
|
||||||
groupId=self:GetID()
|
groupId = self:GetID(),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return self:TaskWrappedAction( CommandEPLRS, idx or 1 )
|
return self:TaskWrappedAction( CommandEPLRS, idx or 1 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- TASKS FOR AIR CONTROLLABLES
|
-- TASKS FOR AIR CONTROLLABLES
|
||||||
|
|
||||||
--- (AIR) Attack a Controllable.
|
--- (AIR) Attack a Controllable.
|
||||||
@@ -851,7 +884,7 @@ end
|
|||||||
-- @param Wrapper.Group#GROUP AttackGroup The Group to be attacked.
|
-- @param Wrapper.Group#GROUP AttackGroup The Group to be attacked.
|
||||||
-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.
|
-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.
|
||||||
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aircraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aircraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
-- @param DCS#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude.
|
-- @param DCS#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude.
|
||||||
-- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.
|
-- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.
|
||||||
@@ -899,7 +932,7 @@ end
|
|||||||
-- @param Wrapper.Unit#UNIT AttackUnit The UNIT to be attacked
|
-- @param Wrapper.Unit#UNIT AttackUnit The UNIT to be attacked
|
||||||
-- @param #boolean GroupAttack (Optional) If true, all units in the group will attack the Unit when found. Default false.
|
-- @param #boolean GroupAttack (Optional) If true, all units in the group will attack the Unit when found. Default false.
|
||||||
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (Optional) Determines how many weapons will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (Optional) Determines how many weapons will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- @param #number AttackQty (Optional) Limits maximal quantity of attack. The aicraft/controllable will not make more attacks than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number AttackQty (Optional) Limits maximal quantity of attack. The aircraft/controllable will not make more attacks than allowed even if the target controllable not destroyed and the aircraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param DCS#Azimuth Direction (Optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction.
|
-- @param DCS#Azimuth Direction (Optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction.
|
||||||
-- @param #number Altitude (Optional) The (minimum) altitude in meters from where to attack. Default is altitude of unit to attack but at least 1000 m.
|
-- @param #number Altitude (Optional) The (minimum) altitude in meters from where to attack. Default is altitude of unit to attack but at least 1000 m.
|
||||||
-- @param #number WeaponType (optional) The WeaponType. See [DCS Enumerator Weapon Type](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) on Hoggit.
|
-- @param #number WeaponType (optional) The WeaponType. See [DCS Enumerator Weapon Type](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) on Hoggit.
|
||||||
@@ -919,19 +952,18 @@ function CONTROLLABLE:TaskAttackUnit(AttackUnit, GroupAttack, WeaponExpend, Atta
|
|||||||
attackQtyLimit = AttackQty and true or false,
|
attackQtyLimit = AttackQty and true or false,
|
||||||
attackQty = AttackQty,
|
attackQty = AttackQty,
|
||||||
weaponType = WeaponType or 1073741822,
|
weaponType = WeaponType or 1073741822,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Delivering weapon at the point on the ground.
|
--- (AIR) Delivering weapon at the point on the ground.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at.
|
-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at.
|
||||||
-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found.
|
-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found.
|
||||||
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aircraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aircraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
-- @param #number Altitude (optional) The altitude from where to attack.
|
-- @param #number Altitude (optional) The altitude from where to attack.
|
||||||
-- @param #number WeaponType (optional) The WeaponType.
|
-- @param #number WeaponType (optional) The WeaponType.
|
||||||
@@ -966,7 +998,7 @@ end
|
|||||||
-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at.
|
-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at.
|
||||||
-- @param #boolean GroupAttack (Optional) If true, all units in the group will attack the Unit when found.
|
-- @param #boolean GroupAttack (Optional) If true, all units in the group will attack the Unit when found.
|
||||||
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (Optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (Optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit will choose expend on its own discretion.
|
||||||
-- @param #number AttackQty (Optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number AttackQty (Optional) This parameter limits maximal quantity of attack. The aircraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aircraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param DCS#Azimuth Direction (Optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth Direction (Optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
-- @param #number Altitude (Optional) The altitude [meters] from where to attack. Default 30 m.
|
-- @param #number Altitude (Optional) The altitude [meters] from where to attack. Default 30 m.
|
||||||
-- @param #number WeaponType (Optional) The WeaponType. Default Auto=1073741822.
|
-- @param #number WeaponType (Optional) The WeaponType. Default Auto=1073741822.
|
||||||
@@ -994,13 +1026,12 @@ function CONTROLLABLE:TaskAttackMapObject( Vec2, GroupAttack, WeaponExpend, Atta
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Delivering weapon via CarpetBombing (all bombers in formation release at same time) at the point on the ground.
|
--- (AIR) Delivering weapon via CarpetBombing (all bombers in formation release at same time) at the point on the ground.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at.
|
-- @param DCS#Vec2 Vec2 2D-coordinates of the point to deliver weapon at.
|
||||||
-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found.
|
-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found.
|
||||||
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit will choose expend on its own discretion.
|
||||||
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aircraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aircraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
-- @param #number Altitude (optional) The altitude from where to attack.
|
-- @param #number Altitude (optional) The altitude from where to attack.
|
||||||
-- @param #number WeaponType (optional) The WeaponType.
|
-- @param #number WeaponType (optional) The WeaponType.
|
||||||
@@ -1025,14 +1056,12 @@ function CONTROLLABLE:TaskCarpetBombing(Vec2, GroupAttack, WeaponExpend, AttackQ
|
|||||||
direction = Direction and math.rad(Direction) or 0,
|
direction = Direction and math.rad(Direction) or 0,
|
||||||
altitudeEnabled = Altitude and true or false,
|
altitudeEnabled = Altitude and true or false,
|
||||||
altitude = Altitude,
|
altitude = Altitude,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Following another airborne controllable.
|
--- (AIR) Following another airborne controllable.
|
||||||
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
|
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
|
||||||
-- Used to support CarpetBombing Task
|
-- Used to support CarpetBombing Task
|
||||||
@@ -1049,14 +1078,13 @@ function CONTROLLABLE:TaskFollowBigFormation(FollowControllable, Vec3, LastWaypo
|
|||||||
groupId = FollowControllable:GetID(),
|
groupId = FollowControllable:GetID(),
|
||||||
pos = Vec3,
|
pos = Vec3,
|
||||||
lastWptIndexFlag = LastWaypointIndex and true or false,
|
lastWptIndexFlag = LastWaypointIndex and true or false,
|
||||||
lastWptIndex = LastWaypointIndex
|
lastWptIndex = LastWaypointIndex,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR HELICOPTER) Move the controllable to a Vec2 Point, wait for a defined duration and embark infantry groups.
|
--- (AIR HELICOPTER) Move the controllable to a Vec2 Point, wait for a defined duration and embark infantry groups.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param Core.Point#COORDINATE Coordinate The point where to pickup the troops.
|
-- @param Core.Point#COORDINATE Coordinate The point where to pickup the troops.
|
||||||
@@ -1099,13 +1127,12 @@ function CONTROLLABLE:TaskEmbarking(Coordinate, GroupSetForEmbarking, Duration,
|
|||||||
duration = Duration,
|
duration = Duration,
|
||||||
distributionFlag = Distribution and true or false,
|
distributionFlag = Distribution and true or false,
|
||||||
distribution = Distribution,
|
distribution = Distribution,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Used in conjunction with the embarking task for a transport helicopter group. The Ground units will move to the specified location and wait to be picked up by a helicopter.
|
--- Used in conjunction with the embarking task for a transport helicopter group. The Ground units will move to the specified location and wait to be picked up by a helicopter.
|
||||||
-- The helicopter will then fly them to their dropoff point defined by another task for the ground forces; DisembarkFromTransport task.
|
-- The helicopter will then fly them to their dropoff point defined by another task for the ground forces; DisembarkFromTransport task.
|
||||||
-- The controllable has to be an infantry group!
|
-- The controllable has to be an infantry group!
|
||||||
@@ -1123,13 +1150,12 @@ function CONTROLLABLE:TaskEmbarkToTransport(Coordinate, Radius, UnitType)
|
|||||||
y = Coordinate.z,
|
y = Coordinate.z,
|
||||||
zoneRadius = Radius or 200,
|
zoneRadius = Radius or 200,
|
||||||
selectedType = UnitType,
|
selectedType = UnitType,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return EmbarkToTransport
|
return EmbarkToTransport
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Specifies the location infantry groups that is being transported by helicopters will be unloaded at. Used in conjunction with the EmbarkToTransport task.
|
--- Specifies the location infantry groups that is being transported by helicopters will be unloaded at. Used in conjunction with the EmbarkToTransport task.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param Core.Point#COORDINATE Coordinate Coordinates where AI is expecting to be picked up.
|
-- @param Core.Point#COORDINATE Coordinate Coordinates where AI is expecting to be picked up.
|
||||||
@@ -1155,14 +1181,13 @@ function CONTROLLABLE:TaskDisembarking(Coordinate, GroupSetToDisembark)
|
|||||||
x = Coordinate.x,
|
x = Coordinate.x,
|
||||||
y = Coordinate.z,
|
y = Coordinate.z,
|
||||||
groupsForEmbarking = g4e, -- This is no bug, the entry is really "groupsForEmbarking" even if we disembark the troops.
|
groupsForEmbarking = g4e, -- This is no bug, the entry is really "groupsForEmbarking" even if we disembark the troops.
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return Disembarking
|
return Disembarking
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (AIR) Orbit at a specified position at a specified altitude during a specified duration with a specified speed.
|
||||||
--- (AIR) Orbit at a specified position at a specified alititude during a specified duration with a specified speed.
|
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Vec2 Point The point to hold the position.
|
-- @param DCS#Vec2 Point The point to hold the position.
|
||||||
-- @param #number Altitude The altitude AGL in meters to hold the position.
|
-- @param #number Altitude The altitude AGL in meters to hold the position.
|
||||||
@@ -1177,8 +1202,8 @@ function CONTROLLABLE:TaskOrbitCircleAtVec2( Point, Altitude, Speed )
|
|||||||
pattern = AI.Task.OrbitPattern.CIRCLE,
|
pattern = AI.Task.OrbitPattern.CIRCLE,
|
||||||
point = Point,
|
point = Point,
|
||||||
speed = Speed,
|
speed = Speed,
|
||||||
altitude = Altitude + land.getHeight( Point )
|
altitude = Altitude + land.getHeight( Point ),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
@@ -1210,13 +1235,13 @@ function CONTROLLABLE:TaskOrbit(Coord, Altitude, Speed, CoordRaceTrack)
|
|||||||
point2 = P2,
|
point2 = P2,
|
||||||
speed = Speed or UTILS.KnotsToMps(250),
|
speed = Speed or UTILS.KnotsToMps(250),
|
||||||
altitude = Altitude or Coord.y,
|
altitude = Altitude or Coord.y,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task
|
return Task
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (AIR) Orbit at the current position of the first unit of the controllable at a specified alititude.
|
--- (AIR) Orbit at the current position of the first unit of the controllable at a specified altitude.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Altitude The altitude [m] to hold the position.
|
-- @param #number Altitude The altitude [m] to hold the position.
|
||||||
-- @param #number Speed The speed [m/s] flying when holding the position.
|
-- @param #number Speed The speed [m/s] flying when holding the position.
|
||||||
@@ -1235,8 +1260,6 @@ function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed, Coordinate )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Hold position at the current position of the first unit of the controllable.
|
--- (AIR) Hold position at the current position of the first unit of the controllable.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Duration The maximum duration in seconds to hold the position.
|
-- @param #number Duration The maximum duration in seconds to hold the position.
|
||||||
@@ -1247,7 +1270,6 @@ function CONTROLLABLE:TaskHoldPosition()
|
|||||||
return self:TaskOrbitCircle( 30, 10 )
|
return self:TaskOrbitCircle( 30, 10 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Delivering weapon on the runway. See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_bombingRunway)
|
--- (AIR) Delivering weapon on the runway. See [hoggit](https://wiki.hoggitworld.com/view/DCS_task_bombingRunway)
|
||||||
--
|
--
|
||||||
-- Make sure the aircraft has the following role:
|
-- Make sure the aircraft has the following role:
|
||||||
@@ -1284,7 +1306,6 @@ function CONTROLLABLE:TaskBombingRunway(Airbase, WeaponType, WeaponExpend, Attac
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Refueling from the nearest tanker. No parameters.
|
--- (AIR) Refueling from the nearest tanker. No parameters.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return DCS#Task The DCS task structure.
|
-- @return DCS#Task The DCS task structure.
|
||||||
@@ -1292,13 +1313,12 @@ function CONTROLLABLE:TaskRefueling()
|
|||||||
|
|
||||||
local DCSTask = {
|
local DCSTask = {
|
||||||
id = 'Refueling',
|
id = 'Refueling',
|
||||||
params={}
|
params = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR HELICOPTER) Landing at the ground. For helicopters only.
|
--- (AIR HELICOPTER) Landing at the ground. For helicopters only.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Vec2 Vec2 The point where to land.
|
-- @param DCS#Vec2 Vec2 The point where to land.
|
||||||
@@ -1333,8 +1353,6 @@ function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint )
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Following another airborne controllable.
|
--- (AIR) Following another airborne controllable.
|
||||||
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
|
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
|
||||||
-- If another controllable is on land the unit / controllable will orbit around.
|
-- If another controllable is on land the unit / controllable will orbit around.
|
||||||
@@ -1371,14 +1389,13 @@ function CONTROLLABLE:TaskFollow( FollowControllable, Vec3, LastWaypointIndex )
|
|||||||
lastWptIndexFlag = LastWaypointIndexFlag,
|
lastWptIndexFlag = LastWaypointIndexFlag,
|
||||||
lastWptIndex = LastWaypointIndex,
|
lastWptIndex = LastWaypointIndex,
|
||||||
lastWptIndexFlagChangedManually = lastWptIndexFlagChangedManually,
|
lastWptIndexFlagChangedManually = lastWptIndexFlagChangedManually,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self:T3( { DCSTask } )
|
self:T3( { DCSTask } )
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Escort another airborne controllable.
|
--- (AIR) Escort another airborne controllable.
|
||||||
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
|
-- The unit / controllable will follow lead unit of another controllable, wingmens of both controllables will continue following their leaders.
|
||||||
-- The unit / controllable will also protect that controllable from threats of specified types.
|
-- The unit / controllable will also protect that controllable from threats of specified types.
|
||||||
@@ -1419,7 +1436,6 @@ function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, E
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- GROUND TASKS
|
-- GROUND TASKS
|
||||||
|
|
||||||
--- (GROUND) Fire at a VEC2 point until ammunition is finished.
|
--- (GROUND) Fire at a VEC2 point until ammunition is finished.
|
||||||
@@ -1443,8 +1459,8 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType, Alti
|
|||||||
radius = Radius,
|
radius = Radius,
|
||||||
expendQty = 100, -- dummy value
|
expendQty = 100, -- dummy value
|
||||||
expendQtyEnabled = false,
|
expendQtyEnabled = false,
|
||||||
alt_type = ASL and 0 or 1
|
alt_type = ASL and 0 or 1,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if AmmoCount then
|
if AmmoCount then
|
||||||
@@ -1473,7 +1489,6 @@ function CONTROLLABLE:TaskHold()
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- TASKS FOR AIRBORNE AND GROUND UNITS/CONTROLLABLES
|
-- TASKS FOR AIRBORNE AND GROUND UNITS/CONTROLLABLES
|
||||||
|
|
||||||
--- (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction.
|
--- (AIR + GROUND) The task makes the controllable/unit a FAC and orders the FAC to control the target (enemy ground controllable) destruction.
|
||||||
@@ -1503,7 +1518,7 @@ function CONTROLLABLE:TaskFAC_AttackGroup( AttackGroup, WeaponType, Designation,
|
|||||||
modulation = Modulation or radio.modulation.AM,
|
modulation = Modulation or radio.modulation.AM,
|
||||||
callname = CallsignName,
|
callname = CallsignName,
|
||||||
number = CallsignNumber,
|
number = CallsignNumber,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
@@ -1526,14 +1541,12 @@ function CONTROLLABLE:EnRouteTaskEngageTargets( Distance, TargetTypes, Priority
|
|||||||
maxDist = Distance,
|
maxDist = Distance,
|
||||||
targetTypes = TargetTypes or {"Air"},
|
targetTypes = TargetTypes or {"Air"},
|
||||||
priority = Priority or 0,
|
priority = Priority or 0,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Engaging a targets of defined types at circle-shaped zone.
|
--- (AIR) Engaging a targets of defined types at circle-shaped zone.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param DCS#Vec2 Vec2 2D-coordinates of the zone.
|
-- @param DCS#Vec2 Vec2 2D-coordinates of the zone.
|
||||||
@@ -1550,20 +1563,19 @@ function CONTROLLABLE:EnRouteTaskEngageTargetsInZone( Vec2, Radius, TargetTypes,
|
|||||||
zoneRadius = Radius,
|
zoneRadius = Radius,
|
||||||
targetTypes = TargetTypes or {"Air"},
|
targetTypes = TargetTypes or {"Air"},
|
||||||
priority = Priority or 0
|
priority = Priority or 0
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets.
|
--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked.
|
-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked.
|
||||||
-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first.
|
-- @param #number Priority All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first.
|
||||||
-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.
|
-- @param #number WeaponType (optional) Bitmask of weapon types those allowed to use. If parameter is not defined that means no limits on weapon usage.
|
||||||
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aircraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aircraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
-- @param DCS#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude.
|
-- @param DCS#Distance Altitude (optional) Desired attack start altitude. Controllable/aircraft will make its attacks from the altitude. If the altitude is too low or too high to use weapon aircraft/controllable will choose closest altitude to the desired attack start altitude. If the desired altitude is defined controllable/aircraft will not attack from safe altitude.
|
||||||
-- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.
|
-- @param #boolean AttackQtyLimit (optional) The flag determines how to interpret attackQty parameter. If the flag is true then attackQty is a limit on maximal attack quantity for "AttackGroup" and "AttackUnit" tasks. If the flag is false then attackQty is a desired attack quantity for "Bombing" and "BombingRunway" tasks.
|
||||||
@@ -1605,14 +1617,13 @@ function CONTROLLABLE:EnRouteTaskEngageGroup( AttackGroup, Priority, WeaponType,
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Search and attack the Unit.
|
--- (AIR) Search and attack the Unit.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param Wrapper.Unit#UNIT EngageUnit The UNIT.
|
-- @param Wrapper.Unit#UNIT EngageUnit The UNIT.
|
||||||
-- @param #number Priority (optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first.
|
-- @param #number Priority (optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first.
|
||||||
-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found.
|
-- @param #boolean GroupAttack (optional) If true, all units in the group will attack the Unit when found.
|
||||||
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
-- @param DCS#AI.Task.WeaponExpend WeaponExpend (optional) Determines how much weapon will be released at each attack. If parameter is not defined the unit / controllable will choose expend on its own discretion.
|
||||||
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aicraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aicraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
-- @param #number AttackQty (optional) This parameter limits maximal quantity of attack. The aircraft/controllable will not make more attack than allowed even if the target controllable not destroyed and the aircraft/controllable still have ammo. If not defined the aircraft/controllable will attack target until it will be destroyed or until the aircraft/controllable will run out of ammo.
|
||||||
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
-- @param DCS#Azimuth Direction (optional) Desired ingress direction from the target to the attacking aircraft. Controllable/aircraft will make its attacks from the direction. Of course if there is no way to attack from the direction due the terrain controllable/aircraft will choose another direction.
|
||||||
-- @param DCS#Distance Altitude (optional) Desired altitude to perform the unit engagement.
|
-- @param DCS#Distance Altitude (optional) Desired altitude to perform the unit engagement.
|
||||||
-- @param #boolean Visible (optional) Unit must be visible.
|
-- @param #boolean Visible (optional) Unit must be visible.
|
||||||
@@ -1641,8 +1652,6 @@ function CONTROLLABLE:EnRouteTaskEngageUnit( EngageUnit, Priority, GroupAttack,
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters.
|
--- (AIR) Aircraft will act as an AWACS for friendly units (will provide them with information about contacts). No parameters.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return DCS#Task The DCS task structure.
|
-- @return DCS#Task The DCS task structure.
|
||||||
@@ -1656,7 +1665,6 @@ function CONTROLLABLE:EnRouteTaskAWACS( )
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Aircraft will act as a tanker for friendly units. No parameters.
|
--- (AIR) Aircraft will act as a tanker for friendly units. No parameters.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return DCS#Task The DCS task structure.
|
-- @return DCS#Task The DCS task structure.
|
||||||
@@ -1670,7 +1678,6 @@ function CONTROLLABLE:EnRouteTaskTanker( )
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- En-route tasks for ground units/controllables
|
-- En-route tasks for ground units/controllables
|
||||||
|
|
||||||
--- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters.
|
--- (GROUND) Ground unit (EW-radar) will act as an EWR for friendly units (will provide them with information about contacts). No parameters.
|
||||||
@@ -1686,7 +1693,6 @@ function CONTROLLABLE:EnRouteTaskEWR( )
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- En-route tasks for airborne and ground units/controllables
|
-- En-route tasks for airborne and ground units/controllables
|
||||||
|
|
||||||
--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets.
|
--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose the target (enemy ground controllable) as well as other assigned targets.
|
||||||
@@ -1709,13 +1715,12 @@ function CONTROLLABLE:EnRouteTaskFAC_EngageGroup( AttackGroup, Priority, WeaponT
|
|||||||
designation = Designation,
|
designation = Designation,
|
||||||
datalink = Datalink and Datalink or false,
|
datalink = Datalink and Datalink or false,
|
||||||
priority = Priority or 0,
|
priority = Priority or 0,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets.
|
--- (AIR + GROUND) The task makes the controllable/unit a FAC and lets the FAC to choose a targets (enemy ground controllable) around as well as other assigned targets.
|
||||||
-- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC.
|
-- The killer is player-controlled allied CAS-aircraft that is in contact with the FAC.
|
||||||
-- If the task is assigned to the controllable lead unit will be a FAC.
|
-- If the task is assigned to the controllable lead unit will be a FAC.
|
||||||
@@ -1744,7 +1749,6 @@ function CONTROLLABLE:EnRouteTaskFAC( Radius, Priority )
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- This creates a Task element, with an action to call a function as part of a Wrapped Task.
|
--- This creates a Task element, with an action to call a function as part of a Wrapped Task.
|
||||||
-- This Task can then be embedded at a Waypoint by calling the method @{#CONTROLLABLE.SetTaskWaypoint}.
|
-- This Task can then be embedded at a Waypoint by calling the method @{#CONTROLLABLE.SetTaskWaypoint}.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
@@ -1813,8 +1817,6 @@ function CONTROLLABLE:TaskFunction( FunctionString, ... )
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- (AIR + GROUND) Return a mission task from a mission template.
|
--- (AIR + GROUND) Return a mission task from a mission template.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #table TaskMission A table containing the mission task.
|
-- @param #table TaskMission A table containing the mission task.
|
||||||
@@ -1823,13 +1825,14 @@ function CONTROLLABLE:TaskMission( TaskMission )
|
|||||||
|
|
||||||
local DCSTask = {
|
local DCSTask = {
|
||||||
id = 'Mission',
|
id = 'Mission',
|
||||||
params = { TaskMission, },
|
params = {
|
||||||
|
TaskMission,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
do -- Patrol methods
|
do -- Patrol methods
|
||||||
|
|
||||||
--- (GROUND) Patrol iteratively using the waypoints the for the (parent) group.
|
--- (GROUND) Patrol iteratively using the waypoints the for the (parent) group.
|
||||||
@@ -1863,7 +1866,6 @@ do -- Patrol methods
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local Waypoint = Waypoints[1]
|
local Waypoint = Waypoints[1]
|
||||||
local Speed = Waypoint.speed or (20 / 3.6)
|
local Speed = Waypoint.speed or (20 / 3.6)
|
||||||
local From = FromCoord:WaypointGround( Speed )
|
local From = FromCoord:WaypointGround( Speed )
|
||||||
@@ -1922,7 +1924,7 @@ do -- Patrol methods
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Loop until a waypoint has been found that is not the same as the current waypoint.
|
-- Loop until a waypoint has been found that is not the same as the current waypoint.
|
||||||
-- Otherwise the object zon't move or drive in circles and the algorithm would not do exactly
|
-- Otherwise the object won't move, or drive in circles, and the algorithm would not do exactly
|
||||||
-- what it is supposed to do, which is making groups drive around.
|
-- what it is supposed to do, which is making groups drive around.
|
||||||
local ToWaypoint
|
local ToWaypoint
|
||||||
repeat
|
repeat
|
||||||
@@ -2021,8 +2023,7 @@ do -- Patrol methods
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Return a Mission task to follow a given route defined by Points.
|
||||||
--- Return a Misson task to follow a given route defined by Points.
|
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #table Points A table of route points.
|
-- @param #table Points A table of route points.
|
||||||
-- @return DCS#Task
|
-- @return DCS#Task
|
||||||
@@ -2068,7 +2069,6 @@ do -- Route methods
|
|||||||
["steer"] = 2,
|
["steer"] = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
local PointTo = {}
|
local PointTo = {}
|
||||||
PointTo.x = Point.x
|
PointTo.x = Point.x
|
||||||
PointTo.y = Point.y
|
PointTo.y = Point.y
|
||||||
@@ -2084,7 +2084,6 @@ do -- Route methods
|
|||||||
["steer"] = 2,
|
["steer"] = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
local Points = { PointFrom, PointTo }
|
local Points = { PointFrom, PointTo }
|
||||||
|
|
||||||
self:T3( Points )
|
self:T3( Points )
|
||||||
@@ -2121,7 +2120,6 @@ do -- Route methods
|
|||||||
["steer"] = 2,
|
["steer"] = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
local PointTo = {}
|
local PointTo = {}
|
||||||
PointTo.x = Point.x
|
PointTo.x = Point.x
|
||||||
PointTo.y = Point.z
|
PointTo.y = Point.z
|
||||||
@@ -2139,7 +2137,6 @@ do -- Route methods
|
|||||||
["steer"] = 2,
|
["steer"] = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
local Points = { PointFrom, PointTo }
|
local Points = { PointFrom, PointTo }
|
||||||
|
|
||||||
self:T3( Points )
|
self:T3( Points )
|
||||||
@@ -2149,8 +2146,6 @@ do -- Route methods
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Make the controllable to follow a given route.
|
--- Make the controllable to follow a given route.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #table Route A table of Route Points.
|
-- @param #table Route A table of Route Points.
|
||||||
@@ -2187,7 +2182,6 @@ do -- Route methods
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Stops the movement of the vehicle on the route.
|
--- Stops the movement of the vehicle on the route.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE
|
-- @return #CONTROLLABLE
|
||||||
@@ -2292,8 +2286,6 @@ do -- Route methods
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Make a task for a GROUND Controllable to drive towards a specific point using (mostly) roads.
|
--- Make a task for a GROUND Controllable to drive towards a specific point using (mostly) roads.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||||
@@ -2456,7 +2448,6 @@ do -- Route methods
|
|||||||
waypointfunction( controllable, n, N, ... )
|
waypointfunction( controllable, n, N, ... )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Make the AIR Controllable fly towards a specific point.
|
--- Make the AIR Controllable fly towards a specific point.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||||
@@ -2478,7 +2469,6 @@ do -- Route methods
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR + GROUND) Route the controllable to a given zone.
|
--- (AIR + GROUND) Route the controllable to a given zone.
|
||||||
-- The controllable final destination point can be randomized.
|
-- The controllable final destination point can be randomized.
|
||||||
-- A speed can be given in km/h.
|
-- A speed can be given in km/h.
|
||||||
@@ -2504,7 +2494,6 @@ do -- Route methods
|
|||||||
PointFrom.action = Formation or "Cone"
|
PointFrom.action = Formation or "Cone"
|
||||||
PointFrom.speed = 20 / 3.6
|
PointFrom.speed = 20 / 3.6
|
||||||
|
|
||||||
|
|
||||||
local PointTo = {}
|
local PointTo = {}
|
||||||
local ZonePoint
|
local ZonePoint
|
||||||
|
|
||||||
@@ -2564,7 +2553,6 @@ do -- Route methods
|
|||||||
PointFrom.action = Formation or "Cone"
|
PointFrom.action = Formation or "Cone"
|
||||||
PointFrom.speed = 20 / 3.6
|
PointFrom.speed = 20 / 3.6
|
||||||
|
|
||||||
|
|
||||||
local PointTo = {}
|
local PointTo = {}
|
||||||
|
|
||||||
PointTo.x = Vec2.x
|
PointTo.x = Vec2.x
|
||||||
@@ -2616,7 +2604,6 @@ function CONTROLLABLE:CommandDoScript( DoScript )
|
|||||||
return DCSDoScript
|
return DCSDoScript
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return the mission template of the controllable.
|
--- Return the mission template of the controllable.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #table The MissionTemplate
|
-- @return #table The MissionTemplate
|
||||||
@@ -2636,8 +2623,6 @@ function CONTROLLABLE:GetTaskRoute()
|
|||||||
return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template.route.points )
|
return routines.utils.deepCopy( _DATABASE.Templates.Controllables[self.ControllableName].Template.route.points )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Return the route of a controllable by using the @{Core.Database#DATABASE} class.
|
--- Return the route of a controllable by using the @{Core.Database#DATABASE} class.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Begin The route point from where the copy will start. The base route point is 0.
|
-- @param #number Begin The route point from where the copy will start. The base route point is 0.
|
||||||
@@ -2689,7 +2674,6 @@ function CONTROLLABLE:CopyRoute( Begin, End, Randomize, Radius )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return the detected targets of the controllable.
|
--- Return the detected targets of the controllable.
|
||||||
-- The optional parametes specify the detection methods that can be applied.
|
-- The optional parametes specify the detection methods that can be applied.
|
||||||
-- If no detection method is given, the detection will use all the available methods by default.
|
-- If no detection method is given, the detection will use all the available methods by default.
|
||||||
@@ -2715,7 +2699,6 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
|
|||||||
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
|
local DetectionRWR = (DetectRWR and DetectRWR == true) and Controller.Detection.RWR or nil
|
||||||
local DetectionDLINK = (DetectDLINK and DetectDLINK == true) and Controller.Detection.DLINK or nil
|
local DetectionDLINK = (DetectDLINK and DetectDLINK == true) and Controller.Detection.DLINK or nil
|
||||||
|
|
||||||
|
|
||||||
local Params = {}
|
local Params = {}
|
||||||
if DetectionVisual then
|
if DetectionVisual then
|
||||||
Params[#Params + 1] = DetectionVisual
|
Params[#Params + 1] = DetectionVisual
|
||||||
@@ -2736,7 +2719,6 @@ function CONTROLLABLE:GetDetectedTargets( DetectVisual, DetectOptical, DetectRad
|
|||||||
Params[#Params + 1] = DetectionDLINK
|
Params[#Params + 1] = DetectionDLINK
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
self:T2( { DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK } )
|
self:T2( { DetectionVisual, DetectionOptical, DetectionRadar, DetectionIRST, DetectionRWR, DetectionDLINK } )
|
||||||
|
|
||||||
return self:_GetController():getDetectedTargets( Params[1], Params[2], Params[3], Params[4], Params[5], Params[6] )
|
return self:_GetController():getDetectedTargets( Params[1], Params[2], Params[3], Params[4], Params[5], Params[6] )
|
||||||
@@ -2853,7 +2835,6 @@ function CONTROLLABLE:IsGroupDetected( Group, DetectVisual, DetectOptical, Detec
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return the detected targets of the controllable.
|
--- Return the detected targets of the controllable.
|
||||||
-- The optional parametes specify the detection methods that can be applied.
|
-- The optional parametes specify the detection methods that can be applied.
|
||||||
-- If **no** detection method is given, the detection will use **all** the available methods by default.
|
-- If **no** detection method is given, the detection will use **all** the available methods by default.
|
||||||
@@ -2930,7 +2911,6 @@ function CONTROLLABLE:GetDetectedGroupSet(DetectVisual, DetectOptical, DetectRad
|
|||||||
return groupset
|
return groupset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Options
|
-- Options
|
||||||
|
|
||||||
--- Set option.
|
--- Set option.
|
||||||
@@ -3199,7 +3179,6 @@ function CONTROLLABLE:OptionROTNoReactionPossible()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- No evasion on enemy threats.
|
--- No evasion on enemy threats.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -3297,7 +3276,6 @@ function CONTROLLABLE:OptionROTEvadeFirePossible()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Evade on fire.
|
--- Evade on fire.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -3336,7 +3314,6 @@ function CONTROLLABLE:OptionROTVerticalPossible()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Evade on fire using vertical manoeuvres.
|
--- Evade on fire using vertical manoeuvres.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -3427,7 +3404,6 @@ function CONTROLLABLE:OptionAlarmStateRed()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set RTB on bingo fuel.
|
--- Set RTB on bingo fuel.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #boolean RTB true if RTB on bingo fuel (default), false if no RTB on bingo fuel.
|
-- @param #boolean RTB true if RTB on bingo fuel (default), false if no RTB on bingo fuel.
|
||||||
@@ -3455,7 +3431,6 @@ function CONTROLLABLE:OptionRTBBingoFuel( RTB ) --R2.2
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set RTB on ammo.
|
--- Set RTB on ammo.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #boolean WeaponsFlag Weapons.flag enumerator.
|
-- @param #boolean WeaponsFlag Weapons.flag enumerator.
|
||||||
@@ -3477,7 +3452,6 @@ function CONTROLLABLE:OptionRTBAmmo( WeaponsFlag )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Allow to Jettison of weapons upon threat.
|
--- Allow to Jettison of weapons upon threat.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -3498,7 +3472,6 @@ function CONTROLLABLE:OptionAllowJettisonWeaponsOnThreat()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Keep weapons upon threat.
|
--- Keep weapons upon threat.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -3563,7 +3536,6 @@ function CONTROLLABLE:OptionECM_OnlyLockByRadar()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Defines the usage of Electronic Counter Measures by airborne forces. If the AI is being detected by a radar they will enable their ECM.
|
--- Defines the usage of Electronic Counter Measures by airborne forces. If the AI is being detected by a radar they will enable their ECM.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -3636,7 +3608,6 @@ function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunctio
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Executes the WayPoint plan.
|
--- Executes the WayPoint plan.
|
||||||
-- The function gets a WayPoint parameter, that you can use to restart the mission at a specific WayPoint.
|
-- The function gets a WayPoint parameter, that you can use to restart the mission at a specific WayPoint.
|
||||||
-- Note that when the WayPoint parameter is used, the new start mission waypoint of the controllable will be 1!
|
-- Note that when the WayPoint parameter is used, the new start mission waypoint of the controllable will be 1!
|
||||||
@@ -3845,3 +3816,44 @@ function POSITIONABLE:IsSubmarine()
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sets the controlled group to go at the specified speed in meters per second.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number Speed Speed in meters per second.
|
||||||
|
-- @param #boolean Keep (Optional) When set to true, will maintain the speed on passing waypoints. If not present or false, the controlled group will return to the speed as defined by their route.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:SetSpeed(Speed, Keep)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
-- Set default if not specified.
|
||||||
|
local speed = Speed or 5
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local Controller = self:_GetController()
|
||||||
|
if Controller then
|
||||||
|
Controller:setSpeed(speed, Keep)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- [AIR] Sets the controlled aircraft group to fly at the specified altitude in meters.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number Altitude Altitude in meters.
|
||||||
|
-- @param #boolean Keep (Optional) When set to true, will maintain the altitude on passing waypoints. If not present or false, the controlled group will return to the altitude as defined by their route.
|
||||||
|
-- @param #string AltType (Optional) Specifies the altitude type used. If nil, the altitude type of the current waypoint will be used. Accepted values are "BARO" and "RADIO".
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:SetAltitude(Altitude, Keep, AltType)
|
||||||
|
self:F2( { self.ControllableName } )
|
||||||
|
-- Set default if not specified.
|
||||||
|
local altitude = Altitude or 1000
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local Controller = self:_GetController()
|
||||||
|
if Controller then
|
||||||
|
if self:IsAir() then
|
||||||
|
Controller:setAltitude(altitude, Keep, AltType)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
@@ -384,7 +384,7 @@ end
|
|||||||
-- So all event listeners will catch the destroy event of this group for each unit in the group.
|
-- So all event listeners will catch the destroy event of this group for each unit in the group.
|
||||||
-- To raise these events, provide the `GenerateEvent` parameter.
|
-- To raise these events, provide the `GenerateEvent` parameter.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @param #boolean GenerateEvent If true, a crash or dead event for each unit is generated. If false, if no event is triggered. If nil, a RemoveUnit event is triggered.
|
-- @param #boolean GenerateEvent If true, a crash [AIR] or dead [GROUND] event for each unit is generated. If false, if no event is triggered. If nil, a RemoveUnit event is triggered.
|
||||||
-- @param #number delay Delay in seconds before despawning the group.
|
-- @param #number delay Delay in seconds before despawning the group.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Air unit example: destroy the Helicopter and generate a S_EVENT_CRASH for each unit in the Helicopter group.
|
-- -- Air unit example: destroy the Helicopter and generate a S_EVENT_CRASH for each unit in the Helicopter group.
|
||||||
@@ -622,7 +622,7 @@ function GROUP:GetUnits()
|
|||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local DCSUnits = DCSGroup:getUnits()
|
local DCSUnits = DCSGroup:getUnits() or {}
|
||||||
local Units = {}
|
local Units = {}
|
||||||
for Index, UnitData in pairs( DCSUnits ) do
|
for Index, UnitData in pairs( DCSUnits ) do
|
||||||
Units[#Units+1] = UNIT:Find( UnitData )
|
Units[#Units+1] = UNIT:Find( UnitData )
|
||||||
@@ -680,6 +680,30 @@ function GROUP:GetUnit( UnitNumber )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if an (air) group is a client or player slot. Information is retrieved from the group template.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @return #boolean If true, group is associated with a client or player slot.
|
||||||
|
function GROUP:IsPlayer()
|
||||||
|
|
||||||
|
-- Get group.
|
||||||
|
-- local group=self:GetGroup()
|
||||||
|
|
||||||
|
-- Units of template group.
|
||||||
|
local units=self:GetTemplate().units
|
||||||
|
|
||||||
|
-- Get numbers.
|
||||||
|
for _,unit in pairs(units) do
|
||||||
|
|
||||||
|
-- Check if unit name matach and skill is Client or Player.
|
||||||
|
if unit.name==self:GetName() and (unit.skill=="Client" or unit.skill=="Player") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the DCS Unit with number UnitNumber.
|
--- Returns the DCS Unit with number UnitNumber.
|
||||||
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
@@ -690,8 +714,21 @@ function GROUP:GetDCSUnit( UnitNumber )
|
|||||||
local DCSGroup = self:GetDCSObject()
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
local DCSUnitFound=DCSGroup:getUnit( UnitNumber )
|
|
||||||
return DCSUnitFound
|
if DCSGroup.getUnit and DCSGroup:getUnit( UnitNumber ) then
|
||||||
|
return DCSGroup:getUnit( UnitNumber )
|
||||||
|
else
|
||||||
|
|
||||||
|
local UnitFound = nil
|
||||||
|
-- 2.7.1 dead event bug, return the first alive unit instead
|
||||||
|
local units = DCSGroup:getUnits() or {}
|
||||||
|
|
||||||
|
for _,_unit in pairs(units) do
|
||||||
|
if _unit and _unit:isExist() then
|
||||||
|
return _unit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -765,8 +802,7 @@ end
|
|||||||
|
|
||||||
--- Returns the average velocity Vec3 vector.
|
--- Returns the average velocity Vec3 vector.
|
||||||
-- @param Wrapper.Group#GROUP self
|
-- @param Wrapper.Group#GROUP self
|
||||||
-- @return DCS#Vec3 The velocity Vec3 vector
|
-- @return DCS#Vec3 The velocity Vec3 vector or `#nil` if the GROUP is not existing or alive.
|
||||||
-- @return #nil The GROUP is not existing or alive.
|
|
||||||
function GROUP:GetVelocityVec3()
|
function GROUP:GetVelocityVec3()
|
||||||
self:F2( self.GroupName )
|
self:F2( self.GroupName )
|
||||||
|
|
||||||
@@ -797,11 +833,19 @@ function GROUP:GetVelocityVec3()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the average group altitude in meters.
|
||||||
|
-- @param Wrapper.Group#GROUP self
|
||||||
|
-- @param #boolean FromGround Measure from the ground or from sea level (ASL). Provide **true** for measuring from the ground (AGL). **false** or **nil** if you measure from sea level.
|
||||||
|
-- @return #number The altitude of the group or nil if is not existing or alive.
|
||||||
|
function GROUP:GetAltitude(FromGround)
|
||||||
|
self:F2( self.GroupName )
|
||||||
|
return self:GetHeight(FromGround)
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the average group height in meters.
|
--- Returns the average group height in meters.
|
||||||
-- @param Wrapper.Group#GROUP self
|
-- @param Wrapper.Group#GROUP self
|
||||||
-- @param #boolean FromGround Measure from the ground or from sea level. Provide **true** for measuring from the ground. **false** or **nil** if you measure from sea level.
|
-- @param #boolean FromGround Measure from the ground or from sea level (ASL). Provide **true** for measuring from the ground (AGL). **false** or **nil** if you measure from sea level.
|
||||||
-- @return DCS#Vec3 The height of the group or nil if is not existing or alive.
|
-- @return #number The height of the group or nil if is not existing or alive.
|
||||||
function GROUP:GetHeight( FromGround )
|
function GROUP:GetHeight( FromGround )
|
||||||
self:F2( self.GroupName )
|
self:F2( self.GroupName )
|
||||||
|
|
||||||
@@ -901,6 +945,24 @@ function GROUP:GetTypeName()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [AIRPLANE] Get the NATO reporting name (platform, e.g. "Flanker") of a GROUP (note - first unit the group). "Bogey" if not found. Currently airplanes only!
|
||||||
|
--@param #GROUP self
|
||||||
|
--@return #string NatoReportingName or "Bogey" if unknown.
|
||||||
|
function GROUP:GetNatoReportingName()
|
||||||
|
self:F2( self.GroupName )
|
||||||
|
|
||||||
|
local DCSGroup = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSGroup then
|
||||||
|
local GroupTypeName = DCSGroup:getUnit(1):getTypeName()
|
||||||
|
self:T3( GroupTypeName )
|
||||||
|
return UTILS.GetReportingName(GroupTypeName)
|
||||||
|
end
|
||||||
|
|
||||||
|
return "Bogey"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Gets the player name of the group.
|
--- Gets the player name of the group.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return #string The player name of the group.
|
-- @return #string The player name of the group.
|
||||||
@@ -994,24 +1056,32 @@ end
|
|||||||
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
||||||
function GROUP:GetCoordinate()
|
function GROUP:GetCoordinate()
|
||||||
|
|
||||||
local FirstUnit = self:GetUnit(1)
|
local Units = self:GetUnits() or {}
|
||||||
|
|
||||||
|
for _,_unit in pairs(Units) do
|
||||||
|
local FirstUnit = _unit -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
if FirstUnit then
|
if FirstUnit then
|
||||||
|
|
||||||
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
local FirstUnitCoordinate = FirstUnit:GetCoordinate()
|
||||||
|
|
||||||
|
if FirstUnitCoordinate then
|
||||||
|
local Heading = self:GetHeading()
|
||||||
|
FirstUnitCoordinate.Heading = Heading
|
||||||
return FirstUnitCoordinate
|
return FirstUnitCoordinate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
BASE:E( { "Cannot GetCoordinate", Group = self, Alive = self:IsAlive() } )
|
BASE:E( { "Cannot GetCoordinate", Group = self, Alive = self:IsAlive() } )
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns a random @{DCS#Vec3} vector (point in 3D of the UNIT within the mission) within a range around the first UNIT of the GROUP.
|
--- Returns a random @{DCS#Vec3} vector (point in 3D of the UNIT within the mission) within a range around the first UNIT of the GROUP.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @param #number Radius
|
-- @param #number Radius Radius in meters.
|
||||||
-- @return DCS#Vec3 The random 3D point vector around the first UNIT of the GROUP.
|
-- @return DCS#Vec3 The random 3D point vector around the first UNIT of the GROUP or #nil The GROUP is invalid or empty.
|
||||||
-- @return #nil The GROUP is invalid or empty
|
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- If Radius is ignored, returns the DCS#Vec3 of first UNIT of the GROUP
|
-- -- If Radius is ignored, returns the DCS#Vec3 of first UNIT of the GROUP
|
||||||
function GROUP:GetRandomVec3(Radius)
|
function GROUP:GetRandomVec3(Radius)
|
||||||
@@ -1032,18 +1102,19 @@ end
|
|||||||
|
|
||||||
--- Returns the mean heading of every UNIT in the GROUP in degrees
|
--- Returns the mean heading of every UNIT in the GROUP in degrees
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return #number mean heading of the GROUP
|
-- @return #number Mean heading of the GROUP in degrees or #nil The first UNIT is not existing or alive.
|
||||||
-- @return #nil The first UNIT is not existing or alive.
|
|
||||||
function GROUP:GetHeading()
|
function GROUP:GetHeading()
|
||||||
self:F2(self.GroupName)
|
self:F2(self.GroupName)
|
||||||
|
|
||||||
|
self:F2(self.GroupName)
|
||||||
|
|
||||||
local GroupSize = self:GetSize()
|
local GroupSize = self:GetSize()
|
||||||
local HeadingAccumulator = 0
|
local HeadingAccumulator = 0
|
||||||
|
|
||||||
local n=0
|
local n=0
|
||||||
|
local Units = self:GetUnits()
|
||||||
|
|
||||||
if GroupSize then
|
if GroupSize then
|
||||||
for i = 1, GroupSize do
|
for _,unit in pairs(Units) do
|
||||||
local unit=self:GetUnit(i)
|
|
||||||
if unit and unit:IsAlive() then
|
if unit and unit:IsAlive() then
|
||||||
HeadingAccumulator = HeadingAccumulator + unit:GetHeading()
|
HeadingAccumulator = HeadingAccumulator + unit:GetHeading()
|
||||||
n=n+1
|
n=n+1
|
||||||
@@ -1061,8 +1132,8 @@ end
|
|||||||
--- Return the fuel state and unit reference for the unit with the least
|
--- Return the fuel state and unit reference for the unit with the least
|
||||||
-- amount of fuel in the group.
|
-- amount of fuel in the group.
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
-- @return #number The fuel state of the unit with the least amount of fuel
|
-- @return #number The fuel state of the unit with the least amount of fuel.
|
||||||
-- @return #Unit reference to #Unit object for further processing
|
-- @return Wrapper.Unit#UNIT reference to #Unit object for further processing.
|
||||||
function GROUP:GetFuelMin()
|
function GROUP:GetFuelMin()
|
||||||
self:F3(self.ControllableName)
|
self:F3(self.ControllableName)
|
||||||
|
|
||||||
@@ -1104,7 +1175,7 @@ function GROUP:GetFuelAvg()
|
|||||||
local TotalFuel = 0
|
local TotalFuel = 0
|
||||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||||
local UnitFuel = Unit:GetFuel()
|
local UnitFuel = Unit:GetFuel() or 0
|
||||||
self:F( { Fuel = UnitFuel } )
|
self:F( { Fuel = UnitFuel } )
|
||||||
TotalFuel = TotalFuel + UnitFuel
|
TotalFuel = TotalFuel + UnitFuel
|
||||||
end
|
end
|
||||||
@@ -1181,13 +1252,14 @@ function GROUP:IsInZone( Zone )
|
|||||||
for UnitID, UnitData in pairs(self:GetUnits()) do
|
for UnitID, UnitData in pairs(self:GetUnits()) do
|
||||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
local vec2 = nil
|
||||||
|
if Unit then
|
||||||
-- Get 2D vector. That's all we need for the zone check.
|
-- Get 2D vector. That's all we need for the zone check.
|
||||||
local vec2=Unit:GetVec2()
|
vec2=Unit:GetVec2()
|
||||||
|
end
|
||||||
|
|
||||||
if Zone:IsVec2InZone(vec2) then
|
if vec2 and Zone:IsVec2InZone(vec2) then
|
||||||
return true -- At least one unit is in the zone. That is enough.
|
return true -- At least one unit is in the zone. That is enough.
|
||||||
else
|
|
||||||
-- This one is not but another could be.
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -2609,6 +2681,41 @@ function GROUP:GetSkill()
|
|||||||
return skill
|
return skill
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Get the unit in the group with the highest threat level, which is still alive.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @return Wrapper.Unit#UNIT The most dangerous unit in the group.
|
||||||
|
-- @return #number Threat level of the unit.
|
||||||
|
function GROUP:GetHighestThreat()
|
||||||
|
|
||||||
|
-- Get units of the group.
|
||||||
|
local units=self:GetUnits()
|
||||||
|
|
||||||
|
if units then
|
||||||
|
|
||||||
|
local threat=nil ; local maxtl=0
|
||||||
|
for _,_unit in pairs(units or {}) do
|
||||||
|
local unit=_unit --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
if unit and unit:IsAlive() then
|
||||||
|
|
||||||
|
-- Threat level of group.
|
||||||
|
local tl=unit:GetThreatLevel()
|
||||||
|
|
||||||
|
-- Check if greater the current threat.
|
||||||
|
if tl>maxtl then
|
||||||
|
maxtl=tl
|
||||||
|
threat=unit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return threat, maxtl
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
--do -- Smoke
|
--do -- Smoke
|
||||||
--
|
--
|
||||||
----- Signal a flare at the position of the GROUP.
|
----- Signal a flare at the position of the GROUP.
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ function IDENTIFIABLE:GetCoalitionName()
|
|||||||
|
|
||||||
if DCSIdentifiable then
|
if DCSIdentifiable then
|
||||||
|
|
||||||
-- Get coaliton ID.
|
-- Get coalition ID.
|
||||||
local IdentifiableCoalition = DCSIdentifiable:getCoalition()
|
local IdentifiableCoalition = DCSIdentifiable:getCoalition()
|
||||||
self:T3( IdentifiableCoalition )
|
self:T3( IdentifiableCoalition )
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
-- @module Wrapper.Marker
|
-- @module Wrapper.Marker
|
||||||
-- @image Wrapper_Marker.png
|
-- @image Wrapper_Marker.png
|
||||||
|
|
||||||
|
|
||||||
--- Marker class.
|
--- Marker class.
|
||||||
-- @type MARKER
|
-- @type MARKER
|
||||||
-- @field #string ClassName Name of the class.
|
-- @field #string ClassName Name of the class.
|
||||||
@@ -24,7 +23,7 @@
|
|||||||
-- @field #number mid Marker ID.
|
-- @field #number mid Marker ID.
|
||||||
-- @field Core.Point#COORDINATE coordinate Coordinate of the mark.
|
-- @field Core.Point#COORDINATE coordinate Coordinate of the mark.
|
||||||
-- @field #string text Text displayed in the mark panel.
|
-- @field #string text Text displayed in the mark panel.
|
||||||
-- @field #string message Message dispayed when the mark is added.
|
-- @field #string message Message displayed when the mark is added.
|
||||||
-- @field #boolean readonly Marker is read-only.
|
-- @field #boolean readonly Marker is read-only.
|
||||||
-- @field #number coalition Coalition to which the marker is displayed.
|
-- @field #number coalition Coalition to which the marker is displayed.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
@@ -45,8 +44,8 @@
|
|||||||
-- local Coordinate = AIRBASE:FindByName( "Batumi" ):GetCoordinate()
|
-- local Coordinate = AIRBASE:FindByName( "Batumi" ):GetCoordinate()
|
||||||
-- mymarker = MARKER:New( Coordinate, "I am Batumi Airfield" )
|
-- mymarker = MARKER:New( Coordinate, "I am Batumi Airfield" )
|
||||||
--
|
--
|
||||||
-- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e.
|
-- Now this does **not** show the marker yet. We still need to specify to whom it is shown. There are several options, i.e.
|
||||||
-- show the marker to everyone, to a speficic coaliton only, or only to a specific group.
|
-- show the marker to everyone, to a specific coalition only, or only to a specific group.
|
||||||
--
|
--
|
||||||
-- ## For Everyone
|
-- ## For Everyone
|
||||||
--
|
--
|
||||||
@@ -54,17 +53,17 @@
|
|||||||
--
|
--
|
||||||
-- mymarker = MARKER:New( Coordinate, "I am Batumi Airfield" ):ToAll()
|
-- mymarker = MARKER:New( Coordinate, "I am Batumi Airfield" ):ToAll()
|
||||||
--
|
--
|
||||||
-- ## For a Coaliton
|
-- ## For a Coalition
|
||||||
--
|
--
|
||||||
-- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function.
|
-- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function.
|
||||||
--
|
--
|
||||||
-- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToCoaliton(coaliton.side.BLUE)
|
-- mymarker = MARKER:New( Coordinate , "I am Batumi Airfield" ):ToCoalition( coalition.side.BLUE )
|
||||||
--
|
--
|
||||||
-- ### To Blue Coaliton
|
-- ### To Blue Coalition
|
||||||
--
|
--
|
||||||
-- ### To Red Coalition
|
-- ### To Red Coalition
|
||||||
--
|
--
|
||||||
-- This would show the marker only to the Blue coaliton.
|
-- This would show the marker only to the Blue coalition.
|
||||||
--
|
--
|
||||||
-- ## For a Group
|
-- ## For a Group
|
||||||
--
|
--
|
||||||
@@ -76,12 +75,12 @@
|
|||||||
--
|
--
|
||||||
-- The marker text and coordinate can be updated easily as shown below.
|
-- The marker text and coordinate can be updated easily as shown below.
|
||||||
--
|
--
|
||||||
-- However, note that **updateing involves to remove and recreate the marker if either text or its coordinate is changed**.
|
-- However, note that **updating involves to remove and recreate the marker if either text or its coordinate is changed**.
|
||||||
-- *This is a DCS scripting engine limitation.*
|
-- *This is a DCS scripting engine limitation.*
|
||||||
--
|
--
|
||||||
-- ## Update Text
|
-- ## Update Text
|
||||||
--
|
--
|
||||||
-- If you created a marker "mymarker" as shown above, you can update the dispayed test by
|
-- If you created a marker "mymarker" as shown above, you can update the displayed test by
|
||||||
--
|
--
|
||||||
-- mymarker:UpdateText( "I am the new text at Batumi" )
|
-- mymarker:UpdateText( "I am the new text at Batumi" )
|
||||||
--
|
--
|
||||||
@@ -116,7 +115,7 @@
|
|||||||
--
|
--
|
||||||
-- # FSM Events
|
-- # FSM Events
|
||||||
--
|
--
|
||||||
-- Moose creates addditonal events, so called FSM event, when markers are added, changed, removed, and text or the coordianteis updated.
|
-- Moose creates additional events, so called FSM event, when markers are added, changed, removed, and text or the coordinate is updated.
|
||||||
--
|
--
|
||||||
-- These events can be captured and used for processing via OnAfter functions as shown below.
|
-- These events can be captured and used for processing via OnAfter functions as shown below.
|
||||||
--
|
--
|
||||||
@@ -133,7 +132,6 @@
|
|||||||
--
|
--
|
||||||
-- # Examples
|
-- # Examples
|
||||||
--
|
--
|
||||||
--
|
|
||||||
-- @field #MARKER
|
-- @field #MARKER
|
||||||
MARKER = {
|
MARKER = {
|
||||||
ClassName = "MARKER",
|
ClassName = "MARKER",
|
||||||
@@ -223,7 +221,6 @@ function MARKER:New(Coordinate, Text)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Event#EVENTDATA EventData Event data table.
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
|
||||||
--- Triggers the FSM event "Removed".
|
--- Triggers the FSM event "Removed".
|
||||||
-- @function [parent=#MARKER] Removed
|
-- @function [parent=#MARKER] Removed
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
@@ -242,7 +239,6 @@ function MARKER:New(Coordinate, Text)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Event#EVENTDATA EventData Event data table.
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
|
||||||
--- Triggers the FSM event "Changed".
|
--- Triggers the FSM event "Changed".
|
||||||
-- @function [parent=#MARKER] Changed
|
-- @function [parent=#MARKER] Changed
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
@@ -261,7 +257,6 @@ function MARKER:New(Coordinate, Text)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Event#EVENTDATA EventData Event data table.
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
|
|
||||||
|
|
||||||
--- Triggers the FSM event "TextUpdate".
|
--- Triggers the FSM event "TextUpdate".
|
||||||
-- @function [parent=#MARKER] TextUpdate
|
-- @function [parent=#MARKER] TextUpdate
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
@@ -280,7 +275,6 @@ function MARKER:New(Coordinate, Text)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #string Text The new text.
|
-- @param #string Text The new text.
|
||||||
|
|
||||||
|
|
||||||
--- Triggers the FSM event "CoordUpdate".
|
--- Triggers the FSM event "CoordUpdate".
|
||||||
-- @function [parent=#MARKER] CoordUpdate
|
-- @function [parent=#MARKER] CoordUpdate
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
@@ -299,7 +293,6 @@ function MARKER:New(Coordinate, Text)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Point#COORDINATE Coordinate The updated Coordinate.
|
-- @param Core.Point#COORDINATE Coordinate The updated Coordinate.
|
||||||
|
|
||||||
|
|
||||||
-- Handle events.
|
-- Handle events.
|
||||||
self:HandleEvent( EVENTS.MarkAdded )
|
self:HandleEvent( EVENTS.MarkAdded )
|
||||||
self:HandleEvent( EVENTS.MarkRemoved )
|
self:HandleEvent( EVENTS.MarkRemoved )
|
||||||
@@ -344,7 +337,7 @@ function MARKER:ToAll(Delay)
|
|||||||
else
|
else
|
||||||
|
|
||||||
self.toall = true
|
self.toall = true
|
||||||
self.tocoaliton=nil
|
self.tocoalition = nil
|
||||||
self.coalition = nil
|
self.coalition = nil
|
||||||
self.togroup = nil
|
self.togroup = nil
|
||||||
self.groupname = nil
|
self.groupname = nil
|
||||||
@@ -367,7 +360,7 @@ end
|
|||||||
|
|
||||||
--- Place marker visible for a specific coalition only.
|
--- Place marker visible for a specific coalition only.
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
-- @param #number Coalition Coalition 1=Red, 2=Blue, 0=Neutral. See `coaliton.side.RED`.
|
-- @param #number Coalition Coalition 1=Red, 2=Blue, 0=Neutral. See `coalition.side.RED`.
|
||||||
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
-- @param #number Delay (Optional) Delay in seconds, before the marker is created.
|
||||||
-- @return #MARKER self
|
-- @return #MARKER self
|
||||||
function MARKER:ToCoalition( Coalition, Delay )
|
function MARKER:ToCoalition( Coalition, Delay )
|
||||||
@@ -378,7 +371,7 @@ function MARKER:ToCoalition(Coalition, Delay)
|
|||||||
|
|
||||||
self.coalition = Coalition
|
self.coalition = Coalition
|
||||||
|
|
||||||
self.tocoaliton=true
|
self.tocoalition = true
|
||||||
self.toall = false
|
self.toall = false
|
||||||
self.togroup = false
|
self.togroup = false
|
||||||
self.groupname = nil
|
self.groupname = nil
|
||||||
@@ -426,7 +419,6 @@ function MARKER:ToNeutral(Delay)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Place marker visible for a specific group only.
|
--- Place marker visible for a specific group only.
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
-- @param Wrapper.Group#GROUP Group The group to which the marker is displayed.
|
-- @param Wrapper.Group#GROUP Group The group to which the marker is displayed.
|
||||||
@@ -448,7 +440,7 @@ function MARKER:ToGroup(Group, Delay)
|
|||||||
self.groupname = Group:GetName()
|
self.groupname = Group:GetName()
|
||||||
|
|
||||||
self.togroup = true
|
self.togroup = true
|
||||||
self.tocoaliton=nil
|
self.tocoalition = nil
|
||||||
self.coalition = nil
|
self.coalition = nil
|
||||||
self.toall = nil
|
self.toall = nil
|
||||||
|
|
||||||
@@ -531,7 +523,7 @@ function MARKER:Refresh(Delay)
|
|||||||
|
|
||||||
self:ToAll()
|
self:ToAll()
|
||||||
|
|
||||||
elseif self.tocoaliton then
|
elseif self.tocoalition then
|
||||||
|
|
||||||
self:ToCoalition( self.coalition )
|
self:ToCoalition( self.coalition )
|
||||||
|
|
||||||
@@ -595,7 +587,6 @@ function MARKER:SetText(Text)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check if marker is currently visible on the F10 map.
|
--- Check if marker is currently visible on the F10 map.
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
-- @return #boolean True if the marker is currently visible.
|
-- @return #boolean True if the marker is currently visible.
|
||||||
@@ -770,7 +761,3 @@ function MARKER:onafterCoordUpdate(From, Event, To, Coordinate)
|
|||||||
self:T( self.lid .. string.format( "New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS() ) )
|
self:T( self.lid .. string.format( "New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS() ) )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -382,7 +382,8 @@ function POSITIONABLE:GetCoordinate()
|
|||||||
local PositionableVec3 = self:GetVec3()
|
local PositionableVec3 = self:GetVec3()
|
||||||
|
|
||||||
local coord = COORDINATE:NewFromVec3( PositionableVec3 )
|
local coord = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||||
|
local heading = self:GetHeading()
|
||||||
|
coord.Heading = heading
|
||||||
-- Return a new coordinate object.
|
-- Return a new coordinate object.
|
||||||
return coord
|
return coord
|
||||||
|
|
||||||
@@ -536,7 +537,7 @@ function POSITIONABLE:GetBoundingRadius( MinDist )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the altitude of the POSITIONABLE.
|
--- Returns the altitude above sea level of the POSITIONABLE.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return DCS#Distance The altitude of the POSITIONABLE.
|
-- @return DCS#Distance The altitude of the POSITIONABLE.
|
||||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||||
@@ -778,7 +779,7 @@ function POSITIONABLE:GetRelativeVelocity( Positionable )
|
|||||||
return UTILS.VecNorm( vtot )
|
return UTILS.VecNorm( vtot )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the POSITIONABLE height in meters.
|
--- Returns the POSITIONABLE height above sea level in meters.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return DCS#Vec3 The height of the POSITIONABLE in meters.
|
-- @return DCS#Vec3 The height of the POSITIONABLE in meters.
|
||||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||||
@@ -1176,6 +1177,30 @@ function POSITIONABLE:MessageToClient( Message, Duration, Client, Name )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Send a message to a @{Wrapper.Unit}.
|
||||||
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @param #string Message The message text
|
||||||
|
-- @param DCS#Duration Duration The duration of the message.
|
||||||
|
-- @param Wrapper.Unit#UNIT MessageUnit The UNIT object receiving the message.
|
||||||
|
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||||
|
function POSITIONABLE:MessageToUnit( Message, Duration, MessageUnit, Name )
|
||||||
|
self:F2( { Message, Duration } )
|
||||||
|
|
||||||
|
local DCSObject = self:GetDCSObject()
|
||||||
|
if DCSObject then
|
||||||
|
if DCSObject:isExist() then
|
||||||
|
if MessageUnit:IsAlive() then
|
||||||
|
self:GetMessage( Message, Duration, Name ):ToUnit( MessageUnit )
|
||||||
|
else
|
||||||
|
BASE:E( { "Message not sent to Unit; Unit is not alive...", Message = Message, MessageUnit = MessageUnit } )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
BASE:E( { "Message not sent to Unit; Positionable is not alive ...", Message = Message, Positionable = self, MessageUnit = MessageUnit } )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Send a message to a @{Wrapper.Group}.
|
--- Send a message to a @{Wrapper.Group}.
|
||||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
@@ -1249,6 +1274,30 @@ function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Nam
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Send a message to a @{Core.Set#SET_UNIT}.
|
||||||
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @param #string Message The message text
|
||||||
|
-- @param DCS#Duration Duration The duration of the message.
|
||||||
|
-- @param Core.Set#SET_UNIT MessageSetUnit The SET_UNIT collection receiving the message.
|
||||||
|
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||||
|
function POSITIONABLE:MessageToSetUnit( Message, Duration, MessageSetUnit, Name )
|
||||||
|
self:F2( { Message, Duration } )
|
||||||
|
|
||||||
|
local DCSObject = self:GetDCSObject()
|
||||||
|
if DCSObject then
|
||||||
|
if DCSObject:isExist() then
|
||||||
|
MessageSetUnit:ForEachUnit(
|
||||||
|
function( MessageGroup )
|
||||||
|
self:GetMessage( Message, Duration, Name ):ToUnit( MessageGroup )
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Send a message to the players in the @{Wrapper.Group}.
|
--- Send a message to the players in the @{Wrapper.Group}.
|
||||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
@@ -1551,7 +1600,11 @@ do -- Cargo
|
|||||||
["Ural-4320 APA-5D"] = 10,
|
["Ural-4320 APA-5D"] = 10,
|
||||||
["Ural-4320T"] = 14,
|
["Ural-4320T"] = 14,
|
||||||
["ZBD04A"] = 7, -- new by kappa
|
["ZBD04A"] = 7, -- new by kappa
|
||||||
["VAB_Mephisto"] = 8 -- new by Apple
|
["VAB_Mephisto"] = 8, -- new by Apple
|
||||||
|
["tt_KORD"] = 6, -- 2.7.1 HL/TT
|
||||||
|
["tt_DSHK"] = 6,
|
||||||
|
["HL_KORD"] = 6,
|
||||||
|
["HL_DSHK"] = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
local CargoBayWeightLimit = (Weights[Desc.typeName] or 0) * 95
|
local CargoBayWeightLimit = (Weights[Desc.typeName] or 0) * 95
|
||||||
|
|||||||
@@ -10,8 +10,11 @@
|
|||||||
--
|
--
|
||||||
-- @module Wrapper.Static
|
-- @module Wrapper.Static
|
||||||
-- @image Wrapper_Static.JPG
|
-- @image Wrapper_Static.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type STATIC
|
--- @type STATIC
|
||||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||||
|
|
||||||
--- Wrapper class to handle Static objects.
|
--- Wrapper class to handle Static objects.
|
||||||
--
|
--
|
||||||
-- Note that Statics are almost the same as Units, but they don't have a controller.
|
-- Note that Statics are almost the same as Units, but they don't have a controller.
|
||||||
@@ -37,10 +40,13 @@
|
|||||||
--
|
--
|
||||||
-- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name.
|
-- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name.
|
||||||
--
|
--
|
||||||
-- IMPORTANT: ONE SHOULD NEVER SANITIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil).
|
-- IMPORTANT: ONE SHOULD NEVER SANATIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil).
|
||||||
--
|
--
|
||||||
-- @field #STATIC
|
-- @field #STATIC
|
||||||
STATIC = { ClassName = "STATIC" }
|
STATIC = {
|
||||||
|
ClassName = "STATIC",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
--- Register a static object.
|
--- Register a static object.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
@@ -52,6 +58,7 @@ function STATIC:Register( StaticName )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Finds a STATIC from the _DATABASE using a DCSStatic object.
|
--- Finds a STATIC from the _DATABASE using a DCSStatic object.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
|
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
|
||||||
@@ -90,9 +97,8 @@ end
|
|||||||
|
|
||||||
--- Destroys the STATIC.
|
--- Destroys the STATIC.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param #boolean GenerateEvent (Optional) true to generate a crash or dead event, false to not generate any event. `nil` (default) creates a remove event.
|
-- @param #boolean GenerateEvent (Optional) true if you want to generate a crash or dead event for the static.
|
||||||
-- @return #nil The DCS StaticObject is not existing or alive.
|
-- @return #nil The DCS StaticObject is not existing or alive.
|
||||||
--
|
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Air static example: destroy the static Helicopter and generate a S_EVENT_CRASH.
|
-- -- Air static example: destroy the static Helicopter and generate a S_EVENT_CRASH.
|
||||||
-- Helicopter = STATIC:FindByName( "Helicopter" )
|
-- Helicopter = STATIC:FindByName( "Helicopter" )
|
||||||
@@ -111,7 +117,7 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- -- Destroy without event generation example.
|
-- -- Destroy without event generation example.
|
||||||
-- Ship = STATIC:FindByName( "Boat" )
|
-- Ship = STATIC:FindByName( "Boat" )
|
||||||
-- Ship:Destroy( false ) -- Don't generate any event upon destruction.
|
-- Ship:Destroy( false ) -- Don't generate an event upon destruction.
|
||||||
--
|
--
|
||||||
function STATIC:Destroy( GenerateEvent )
|
function STATIC:Destroy( GenerateEvent )
|
||||||
self:F2( self.ObjectName )
|
self:F2( self.ObjectName )
|
||||||
@@ -142,6 +148,7 @@ function STATIC:Destroy( GenerateEvent )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get DCS object of static of static.
|
--- Get DCS object of static of static.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @return DCS static object
|
-- @return DCS static object
|
||||||
@@ -173,6 +180,7 @@ function STATIC:GetUnits()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get threat level of static.
|
--- Get threat level of static.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @return #number Threat level 1.
|
-- @return #number Threat level 1.
|
||||||
@@ -203,6 +211,7 @@ function STATIC:SpawnAt( Coordinate, Heading, Delay )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Unit} at the same location with the same properties.
|
--- Respawn the @{Wrapper.Unit} at the same location with the same properties.
|
||||||
-- This is useful to respawn a cargo after it has been destroyed.
|
-- This is useful to respawn a cargo after it has been destroyed.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
@@ -225,11 +234,12 @@ function STATIC:ReSpawn( CountryID, Delay )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading.
|
--- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading.
|
||||||
-- @param #STATIC self
|
-- @param #STATIC self
|
||||||
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
||||||
-- @param #number Heading (Optional) The heading of the static respawn in degrees. Default is the current heading.
|
-- @param #number Heading (Optional) The heading of the static respawn in degrees. Default the current heading.
|
||||||
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default is now.
|
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now.
|
||||||
function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
||||||
|
|
||||||
--Heading=Heading or 0
|
--Heading=Heading or 0
|
||||||
@@ -237,11 +247,12 @@ function STATIC:ReSpawnAt( Coordinate, Heading, Delay )
|
|||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay)
|
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay)
|
||||||
else
|
else
|
||||||
|
|
||||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
||||||
|
|
||||||
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
UNIT = {
|
UNIT = {
|
||||||
ClassName="UNIT",
|
ClassName="UNIT",
|
||||||
UnitName=nil,
|
UnitName=nil,
|
||||||
|
GroupName=nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -110,11 +111,20 @@ UNIT = {
|
|||||||
function UNIT:Register( UnitName )
|
function UNIT:Register( UnitName )
|
||||||
|
|
||||||
-- Inherit CONTROLLABLE.
|
-- Inherit CONTROLLABLE.
|
||||||
local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) )
|
local self = BASE:Inherit( self, CONTROLLABLE:New( UnitName ) ) --#UNIT
|
||||||
|
|
||||||
-- Set unit name.
|
-- Set unit name.
|
||||||
self.UnitName = UnitName
|
self.UnitName = UnitName
|
||||||
|
|
||||||
|
local unit=Unit.getByName(self.UnitName)
|
||||||
|
|
||||||
|
if unit then
|
||||||
|
local group = unit:getGroup()
|
||||||
|
if group then
|
||||||
|
self.GroupName=group:getName()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Set event prio.
|
-- Set event prio.
|
||||||
self:SetEventPriority( 3 )
|
self:SetEventPriority( 3 )
|
||||||
|
|
||||||
@@ -168,6 +178,29 @@ function UNIT:GetDCSObject()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the unit altitude above sea level in meters.
|
||||||
|
-- @param Wrapper.Unit#UNIT self
|
||||||
|
-- @param #boolean FromGround Measure from the ground or from sea level (ASL). Provide **true** for measuring from the ground (AGL). **false** or **nil** if you measure from sea level.
|
||||||
|
-- @return #number The height of the group or nil if is not existing or alive.
|
||||||
|
function UNIT:GetAltitude(FromGround)
|
||||||
|
|
||||||
|
local DCSUnit = Unit.getByName( self.UnitName )
|
||||||
|
|
||||||
|
if DCSUnit then
|
||||||
|
local altitude = 0
|
||||||
|
local point = DCSUnit:getPoint() --DCS#Vec3
|
||||||
|
altitude = point.y
|
||||||
|
if FromGround then
|
||||||
|
local land = land.getHeight( { x = point.x, y = point.z } ) or 0
|
||||||
|
altitude = altitude - land
|
||||||
|
end
|
||||||
|
return altitude
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group.
|
--- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group.
|
||||||
--
|
--
|
||||||
-- This function will:
|
-- This function will:
|
||||||
@@ -260,6 +293,8 @@ function UNIT:ReSpawnAt( Coordinate, Heading )
|
|||||||
_DATABASE:Spawn( SpawnGroupTemplate )
|
_DATABASE:Spawn( SpawnGroupTemplate )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Returns if the unit is activated.
|
--- Returns if the unit is activated.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive.
|
-- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive.
|
||||||
@@ -296,6 +331,8 @@ function UNIT:IsAlive()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Returns the Unit's callsign - the localized string.
|
--- Returns the Unit's callsign - the localized string.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #string The Callsign of the Unit.
|
-- @return #string The Callsign of the Unit.
|
||||||
@@ -401,6 +438,17 @@ function UNIT:GetClient()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [AIRPLANE] Get the NATO reporting name of a UNIT. Currently airplanes only!
|
||||||
|
--@param #UNIT self
|
||||||
|
--@return #string NatoReportingName or "Bogey" if unknown.
|
||||||
|
function UNIT:GetNatoReportingName()
|
||||||
|
|
||||||
|
local typename = self:GetTypeName()
|
||||||
|
return UTILS.GetReportingName(typename)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the unit's number in the group.
|
--- Returns the unit's number in the group.
|
||||||
-- The number is the same number the unit has in ME.
|
-- The number is the same number the unit has in ME.
|
||||||
-- It may not be changed during the mission.
|
-- It may not be changed during the mission.
|
||||||
@@ -517,6 +565,63 @@ function UNIT:IsTanker()
|
|||||||
return tanker, system
|
return tanker, system
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if the unit can supply ammo. Currently, we have
|
||||||
|
--
|
||||||
|
-- * M 818
|
||||||
|
-- * Ural-375
|
||||||
|
-- * ZIL-135
|
||||||
|
--
|
||||||
|
-- This list needs to be extended, if DCS adds other units capable of supplying ammo.
|
||||||
|
--
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @return #boolean If `true`, unit can supply ammo.
|
||||||
|
function UNIT:IsAmmoSupply()
|
||||||
|
|
||||||
|
-- Type name is the only thing we can check. There is no attribute (Sep. 2021) which would tell us.
|
||||||
|
local typename=self:GetTypeName()
|
||||||
|
|
||||||
|
if typename=="M 818" then
|
||||||
|
-- Blue ammo truck.
|
||||||
|
return true
|
||||||
|
elseif typename=="Ural-375" then
|
||||||
|
-- Red ammo truck.
|
||||||
|
return true
|
||||||
|
elseif typename=="ZIL-135" then
|
||||||
|
-- Red ammo truck. Checked that it can also provide ammo.
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the unit can supply fuel. Currently, we have
|
||||||
|
--
|
||||||
|
-- * M978 HEMTT Tanker
|
||||||
|
-- * ATMZ-5
|
||||||
|
-- * ATMZ-10
|
||||||
|
-- * ATZ-5
|
||||||
|
--
|
||||||
|
-- This list needs to be extended, if DCS adds other units capable of supplying fuel.
|
||||||
|
--
|
||||||
|
-- @param #UNIT self
|
||||||
|
-- @return #boolean If `true`, unit can supply fuel.
|
||||||
|
function UNIT:IsFuelSupply()
|
||||||
|
|
||||||
|
-- Type name is the only thing we can check. There is no attribute (Sep. 2021) which would tell us.
|
||||||
|
local typename=self:GetTypeName()
|
||||||
|
|
||||||
|
if typename=="M978 HEMTT Tanker" then
|
||||||
|
return true
|
||||||
|
elseif typename=="ATMZ-5" then
|
||||||
|
return true
|
||||||
|
elseif typename=="ATMZ-10" then
|
||||||
|
return true
|
||||||
|
elseif typename=="ATZ-5" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the unit's group if it exist and nil otherwise.
|
--- Returns the unit's group if it exist and nil otherwise.
|
||||||
-- @param Wrapper.Unit#UNIT self
|
-- @param Wrapper.Unit#UNIT self
|
||||||
@@ -676,8 +781,6 @@ function UNIT:GetAmmunition()
|
|||||||
return nammo, nshells, nrockets, nbombs, nmissiles
|
return nammo, nshells, nrockets, nbombs, nmissiles
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Returns the unit sensors.
|
--- Returns the unit sensors.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return DCS#Unit.Sensors Table of sensors.
|
-- @return DCS#Unit.Sensors Table of sensors.
|
||||||
@@ -954,6 +1057,7 @@ end
|
|||||||
-- @return #string Some text.
|
-- @return #string Some text.
|
||||||
function UNIT:GetThreatLevel()
|
function UNIT:GetThreatLevel()
|
||||||
|
|
||||||
|
|
||||||
local ThreatLevel = 0
|
local ThreatLevel = 0
|
||||||
local ThreatText = ""
|
local ThreatText = ""
|
||||||
|
|
||||||
@@ -979,6 +1083,7 @@ function UNIT:GetThreatLevel()
|
|||||||
"LR SAMs"
|
"LR SAMs"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if Attributes["LR SAM"] then ThreatLevel = 10
|
if Attributes["LR SAM"] then ThreatLevel = 10
|
||||||
elseif Attributes["MR SAM"] then ThreatLevel = 9
|
elseif Attributes["MR SAM"] then ThreatLevel = 9
|
||||||
elseif Attributes["SR SAM"] and
|
elseif Attributes["SR SAM"] and
|
||||||
@@ -992,7 +1097,7 @@ function UNIT:GetThreatLevel()
|
|||||||
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
||||||
not Attributes["ATGM"] then ThreatLevel = 3
|
not Attributes["ATGM"] then ThreatLevel = 3
|
||||||
elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2
|
elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2
|
||||||
elseif Attributes["Infantry"] then ThreatLevel = 1
|
elseif Attributes["Infantry"] or Attributes["EWR"] then ThreatLevel = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
ThreatText = ThreatLevels[ThreatLevel+1]
|
ThreatText = ThreatLevels[ThreatLevel+1]
|
||||||
@@ -1014,6 +1119,7 @@ function UNIT:GetThreatLevel()
|
|||||||
"Fighter"
|
"Fighter"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if Attributes["Fighters"] then ThreatLevel = 10
|
if Attributes["Fighters"] then ThreatLevel = 10
|
||||||
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
||||||
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
||||||
@@ -1131,6 +1237,12 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Returns if the unit is a friendly unit.
|
--- Returns if the unit is a friendly unit.
|
||||||
-- @param #UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean IsFriendly evaluation result.
|
-- @return #boolean IsFriendly evaluation result.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Utilities/Enums.lua
|
|||||||
Utilities/Profiler.lua
|
Utilities/Profiler.lua
|
||||||
Utilities/Templates.lua
|
Utilities/Templates.lua
|
||||||
Utilities/STTS.lua
|
Utilities/STTS.lua
|
||||||
|
Utilities/FiFo.lua
|
||||||
|
|
||||||
Core/Base.lua
|
Core/Base.lua
|
||||||
Core/Beacon.lua
|
Core/Beacon.lua
|
||||||
|
|||||||
@@ -61,9 +61,10 @@ Documentation on the MOOSE class hierarchy, usage guides and background informat
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [MOOSE Youtube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg)
|
## [MOOSE Youtube Tutorials](https://youtube.com/playlist?list=PLLkY2GByvtC2ME0Q9wrKRDE6qnXJYV3iT)
|
||||||
|
|
||||||
MOOSE has a [broadcast and training channel on YouTube](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg) with various channels that you can watch.
|
Pene has kindly created a [tutorial series for MOOSE](https://youtube.com/playlist?list=PLLkY2GByvtC2ME0Q9wrKRDE6qnXJYV3iT)
|
||||||
|
with various videos that you can watch.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user