mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4a89d62e3 | ||
|
|
a36e39205b | ||
|
|
3789674666 | ||
|
|
a22774b278 | ||
|
|
81bb8dd65f | ||
|
|
9d3796b605 | ||
|
|
3e3dfc83aa | ||
|
|
e062db9411 | ||
|
|
023eae825d | ||
|
|
1a4baeafb6 | ||
|
|
b754972490 | ||
|
|
0c36e4e40d | ||
|
|
1f97495fdd | ||
|
|
c164c0f9e3 | ||
|
|
f0b5ec1025 | ||
|
|
b72ea2d02c | ||
|
|
238fcf1176 | ||
|
|
c354fecc6d | ||
|
|
4434d1da21 | ||
|
|
17ffc7cef9 | ||
|
|
006fd25e56 | ||
|
|
f2eafe0302 | ||
|
|
52069cc1d0 | ||
|
|
d9374f0389 | ||
|
|
19520f9688 | ||
|
|
1eda5af7df | ||
|
|
2ea8487e04 | ||
|
|
b0885ada00 | ||
|
|
1c6c0c4d81 | ||
|
|
3011b0ac8e | ||
|
|
e4334cccb3 | ||
|
|
645ca570a8 | ||
|
|
fd30da2f95 | ||
|
|
b378ad2885 | ||
|
|
9c45031a33 | ||
|
|
e4606b4d05 | ||
|
|
07e690caf0 | ||
|
|
223de9d1aa | ||
|
|
a22b9e925a | ||
|
|
90e7688cea | ||
|
|
9ecd48f523 | ||
|
|
ce9d1837a7 | ||
|
|
bbf83eca3e | ||
|
|
65c28d6628 | ||
|
|
7d7c521bce | ||
|
|
f0ac7818b3 | ||
|
|
07d666b030 | ||
|
|
baaee9f92e | ||
|
|
3a9be7a890 | ||
|
|
3c1547bd6c | ||
|
|
92bf8b59e6 | ||
|
|
4b39312c2c | ||
|
|
ea767650ae | ||
|
|
e0afd19a94 | ||
|
|
767bb58ac9 | ||
|
|
8a78308dbc | ||
|
|
d2db1e56cc | ||
|
|
5f8ebbaf6a | ||
|
|
52758b6900 | ||
|
|
3bb2405563 | ||
|
|
c6403325f5 | ||
|
|
e17b5356dd | ||
|
|
d87cb41b75 | ||
|
|
40154788d6 | ||
|
|
a8f42d61fa | ||
|
|
b923f66c56 | ||
|
|
a0355af13b | ||
|
|
112945b3f6 | ||
|
|
09c46595e5 | ||
|
|
003b0c875e | ||
|
|
ee2668ac65 | ||
|
|
f47bf4771f | ||
|
|
8551830517 | ||
|
|
8b78090a57 | ||
|
|
d2bdb2a791 | ||
|
|
f8f0114f06 | ||
|
|
8619d48c80 | ||
|
|
4171cc45f5 | ||
|
|
5bccd2c6c9 | ||
|
|
a60626468c | ||
|
|
f9cb5d5966 | ||
|
|
cad1c8c462 | ||
|
|
19e2af08e0 | ||
|
|
4386b19b06 | ||
|
|
da90826bd0 | ||
|
|
33509a49e0 | ||
|
|
514d9f3eb3 | ||
|
|
690805d7ca | ||
|
|
eda359e20f | ||
|
|
46882ed192 | ||
|
|
bbd5766688 | ||
|
|
ccf2f60068 | ||
|
|
fa4abed028 |
@@ -439,12 +439,13 @@ function AI_A2A:onafterStatus()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:Is( "Fuel" ) or self:Is( "Damaged" ) or self:Is( "LostControl" ) then
|
-- I think this code is not requirement anymore after release 2.5.
|
||||||
if DistanceFromHomeBase < 5000 then
|
-- if self:Is( "Fuel" ) or self:Is( "Damaged" ) or self:Is( "LostControl" ) then
|
||||||
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
-- if DistanceFromHomeBase < 5000 then
|
||||||
self:Home( "Destroy" )
|
-- self:E( self.Controllable:GetName() .. " is near the home base, RTB!" )
|
||||||
end
|
-- self:Home( "Destroy" )
|
||||||
end
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
|
|
||||||
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
|
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
|
||||||
@@ -481,9 +482,12 @@ function AI_A2A:onafterStatus()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Check if planes went RTB and are out of control.
|
-- Check if planes went RTB and are out of control.
|
||||||
|
-- We only check if planes are out of control, when they are in duty.
|
||||||
if self.Controllable:HasTask() == false then
|
if self.Controllable:HasTask() == false then
|
||||||
if not self:Is( "Started" ) and
|
if not self:Is( "Started" ) and
|
||||||
not self:Is( "Stopped" ) and
|
not self:Is( "Stopped" ) and
|
||||||
|
not self:Is( "Fuel" ) and
|
||||||
|
not self:Is( "Damaged" ) and
|
||||||
not self:Is( "Home" ) then
|
not self:Is( "Home" ) then
|
||||||
if self.IdleCount >= 2 then
|
if self.IdleCount >= 2 then
|
||||||
if Damage ~= InitialLife then
|
if Damage ~= InitialLife then
|
||||||
@@ -504,8 +508,11 @@ function AI_A2A:onafterStatus()
|
|||||||
self:__RTB( 0.5 )
|
self:__RTB( 0.5 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not self:Is("Home") then
|
||||||
self:__Status( 10 )
|
self:__Status( 10 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -635,7 +642,7 @@ end
|
|||||||
--- @param Wrapper.Group#GROUP AIGroup
|
--- @param Wrapper.Group#GROUP AIGroup
|
||||||
function AI_A2A.Resume( AIGroup, Fsm )
|
function AI_A2A.Resume( AIGroup, Fsm )
|
||||||
|
|
||||||
AIGroup:F( { "AI_A2A.Resume:", AIGroup:GetName() } )
|
AIGroup:I( { "AI_A2A.Resume:", AIGroup:GetName() } )
|
||||||
if AIGroup:IsAlive() then
|
if AIGroup:IsAlive() then
|
||||||
Fsm:__RTB( 0.5 )
|
Fsm:__RTB( 0.5 )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -476,13 +476,12 @@ function AI_A2A_CAP:OnEventDead( EventData )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AICap
|
--- @param Wrapper.Group#GROUP AICap
|
||||||
function AI_A2A_CAP.Resume( AICap )
|
function AI_A2A_CAP.Resume( AICap, Fsm )
|
||||||
|
|
||||||
AICap:F( { "AI_A2A_CAP.Resume:", AICap:GetName() } )
|
AICap:I( { "AI_A2A_CAP.Resume:", AICap:GetName() } )
|
||||||
if AICap:IsAlive() then
|
if AICap:IsAlive() then
|
||||||
local _AI_A2A = AICap:GetState( AICap, "AI_A2A" ) -- #AI_A2A
|
Fsm:__Reset( 1 )
|
||||||
_AI_A2A:__Reset( 1 )
|
Fsm:__Route( 5 )
|
||||||
_AI_A2A:__Route( 5 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
--- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
--- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
||||||
--
|
--
|
||||||
|
-- ===
|
||||||
--
|
--
|
||||||
-- Features:
|
-- Features:
|
||||||
--
|
--
|
||||||
@@ -18,6 +19,19 @@
|
|||||||
-- * Quickly setup an A2A defense system using @{#AI_A2A_GCICAP}.
|
-- * Quickly setup an A2A defense system using @{#AI_A2A_GCICAP}.
|
||||||
-- * Setup a more advanced defense system using @{#AI_A2A_DISPATCHER}.
|
-- * Setup a more advanced defense system using @{#AI_A2A_DISPATCHER}.
|
||||||
--
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Missions:
|
||||||
|
--
|
||||||
|
-- [AID-A2A - AI A2A Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-A2A%20-%20AI%20A2A%20Dispatching)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## YouTube Channel:
|
||||||
|
--
|
||||||
|
-- [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
--
|
--
|
||||||
-- # QUICK START GUIDE
|
-- # QUICK START GUIDE
|
||||||
--
|
--
|
||||||
@@ -183,18 +197,6 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
|
||||||
--
|
|
||||||
-- ### [AI\_A2A\_DISPATCHER Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching)
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- # YouTube Channel
|
|
||||||
--
|
|
||||||
-- ### [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx)
|
|
||||||
--
|
|
||||||
-- ===
|
|
||||||
--
|
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- It includes automatic spawning of Combat Air Patrol aircraft (CAP) and Ground Controlled Intercept aircraft (GCI) in response to enemy air movements that are detected by a ground based radar network.
|
-- It includes automatic spawning of Combat Air Patrol aircraft (CAP) and Ground Controlled Intercept aircraft (GCI) in response to enemy air movements that are detected by a ground based radar network.
|
||||||
@@ -796,10 +798,17 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- Use the method @{#AI_A2A_DISPATCHER.SetDisengageRadius}() to modify the default Disengage Radius to another distance setting.
|
-- Use the method @{#AI_A2A_DISPATCHER.SetDisengageRadius}() to modify the default Disengage Radius to another distance setting.
|
||||||
--
|
--
|
||||||
|
-- ## 11. Airbase capture:
|
||||||
--
|
--
|
||||||
-- ## 11. Q & A:
|
-- Different squadrons can be located at one airbase.
|
||||||
|
-- If the airbase gets captured, that is, when there is an enemy unit near the airbase, and there aren't anymore friendlies at the airbase, the airbase will change coalition ownership.
|
||||||
|
-- As a result, the GCI and CAP will stop!
|
||||||
|
-- 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.
|
||||||
--
|
--
|
||||||
-- ### 11.1. Which countries will be selected for each coalition?
|
-- ## 12. Q & A:
|
||||||
|
--
|
||||||
|
-- ### 12.1. Which countries will be selected for each coalition?
|
||||||
--
|
--
|
||||||
-- Which countries are assigned to a coalition influences which units are available to the coalition.
|
-- Which countries are assigned to a coalition influences which units are available to the coalition.
|
||||||
-- For example because the mission calls for a EWR radar on the blue side the Ukraine might be chosen as a blue country
|
-- For example because the mission calls for a EWR radar on the blue side the Ukraine might be chosen as a blue country
|
||||||
@@ -807,7 +816,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- Some countries assign different tasking to aircraft, for example Germany assigns the CAP task to F-4E Phantoms but the USA does not.
|
-- Some countries assign different tasking to aircraft, for example Germany assigns the CAP task to F-4E Phantoms but the USA does not.
|
||||||
-- Therefore if F4s are wanted as a coalition's CAP or GCI aircraft Germany will need to be assigned to that coalition.
|
-- Therefore if F4s are wanted as a coalition's CAP or GCI aircraft Germany will need to be assigned to that coalition.
|
||||||
--
|
--
|
||||||
-- ### 11.2. Country, type, load out, skill and skins for CAP and GCI aircraft?
|
-- ### 12.2. Country, type, load out, skill and skins for CAP and GCI aircraft?
|
||||||
--
|
--
|
||||||
-- * Note these can be from any countries within the coalition but must be an aircraft with one of the main tasks being "CAP".
|
-- * Note these can be from any countries within the coalition but must be an aircraft with one of the main tasks being "CAP".
|
||||||
-- * Obviously skins which are selected must be available to all players that join the mission otherwise they will see a default skin.
|
-- * Obviously skins which are selected must be available to all players that join the mission otherwise they will see a default skin.
|
||||||
@@ -995,16 +1004,73 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead )
|
self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead )
|
||||||
--self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCrashOrDead )
|
--self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCrashOrDead )
|
||||||
|
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Land )
|
self:HandleEvent( EVENTS.Land )
|
||||||
self:HandleEvent( EVENTS.EngineShutdown )
|
self:HandleEvent( EVENTS.EngineShutdown )
|
||||||
|
|
||||||
|
-- Handle the situation where the airbases are captured.
|
||||||
|
self:HandleEvent( EVENTS.BaseCaptured )
|
||||||
|
|
||||||
self:SetTacticalDisplay( false )
|
self:SetTacticalDisplay( false )
|
||||||
|
|
||||||
|
self.DefenderCAPIndex = 0
|
||||||
|
|
||||||
self:__Start( 5 )
|
self:__Start( 5 )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
|
function AI_A2A_DISPATCHER:onafterStart( From, Event, To )
|
||||||
|
|
||||||
|
self:GetParent( self ).onafterStart( self, From, Event, To )
|
||||||
|
|
||||||
|
-- Spawn the resources.
|
||||||
|
for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons ) do
|
||||||
|
DefenderSquadron.Resource = {}
|
||||||
|
for Resource = 1, DefenderSquadron.ResourceCount do
|
||||||
|
self:ParkDefender( DefenderSquadron )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
|
function AI_A2A_DISPATCHER:ParkDefender( DefenderSquadron )
|
||||||
|
local TemplateID = math.random( 1, #DefenderSquadron.Spawn )
|
||||||
|
local Spawn = DefenderSquadron.Spawn[ TemplateID ] -- Core.Spawn#SPAWN
|
||||||
|
Spawn:InitGrouping( 1 )
|
||||||
|
local SpawnGroup
|
||||||
|
if self:IsSquadronVisible( DefenderSquadron.Name ) then
|
||||||
|
SpawnGroup = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, SPAWN.Takeoff.Cold )
|
||||||
|
local GroupName = SpawnGroup:GetName()
|
||||||
|
DefenderSquadron.Resources = DefenderSquadron.Resources or {}
|
||||||
|
DefenderSquadron.Resources[TemplateID] = DefenderSquadron.Resources[TemplateID] or {}
|
||||||
|
DefenderSquadron.Resources[TemplateID][GroupName] = {}
|
||||||
|
DefenderSquadron.Resources[TemplateID][GroupName] = SpawnGroup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function AI_A2A_DISPATCHER:OnEventBaseCaptured( EventData )
|
||||||
|
|
||||||
|
local AirbaseName = EventData.PlaceName -- The name of the airbase that was captured.
|
||||||
|
|
||||||
|
self:I( "Captured " .. AirbaseName )
|
||||||
|
|
||||||
|
-- Now search for all squadrons located at the airbase, and sanatize them.
|
||||||
|
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||||
|
if Squadron.AirbaseName == AirbaseName then
|
||||||
|
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||||
|
Squadron.Captured = true
|
||||||
|
self:I( "Squadron " .. SquadronName .. " captured." )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- @param #AI_A2A_DISPATCHER self
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function AI_A2A_DISPATCHER:OnEventCrashOrDead( EventData )
|
function AI_A2A_DISPATCHER:OnEventCrashOrDead( EventData )
|
||||||
@@ -1027,6 +1093,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
end
|
end
|
||||||
DefenderUnit:Destroy()
|
DefenderUnit:Destroy()
|
||||||
|
self:ParkDefender( Squadron, Defender )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
if DefenderUnit:GetLife() ~= DefenderUnit:GetLife0() then
|
||||||
@@ -1053,6 +1120,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
self:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
end
|
end
|
||||||
DefenderUnit:Destroy()
|
DefenderUnit:Destroy()
|
||||||
|
self:ParkDefender( Squadron, Defender )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1442,7 +1510,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- Just remember that your template (groups late activated) need to start with the prefix you have specified in your code.
|
-- Just remember that your template (groups late activated) need to start with the prefix you have specified in your code.
|
||||||
-- If you have only one prefix name for a squadron, you don't need to use the `{ }`, otherwise you need to use the brackets.
|
-- If you have only one prefix name for a squadron, you don't need to use the `{ }`, otherwise you need to use the brackets.
|
||||||
--
|
--
|
||||||
-- @param #number Resources (optional) A number that specifies how many resources are in stock of the squadron. If not specified, the squadron will have infinite resources available.
|
-- @param #number ResourceCount (optional) A number that specifies how many resources are in stock of the squadron. If not specified, the squadron will have infinite resources available.
|
||||||
--
|
--
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- Now Setup the A2A dispatcher, and initialize it using the Detection object.
|
-- -- Now Setup the A2A dispatcher, and initialize it using the Detection object.
|
||||||
@@ -1465,13 +1533,13 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- @usage
|
-- @usage
|
||||||
-- -- This is an example like the previous, but now with infinite resources.
|
-- -- This is an example like the previous, but now with infinite resources.
|
||||||
-- -- The Resources parameter is not given in the SetSquadron method.
|
-- -- The ResourceCount parameter is not given in the SetSquadron method.
|
||||||
-- A2ADispatcher:SetSquadron( "104th", "Batumi", "Mig-29" )
|
-- A2ADispatcher:SetSquadron( "104th", "Batumi", "Mig-29" )
|
||||||
-- A2ADispatcher:SetSquadron( "23th", "Batumi", "Su-27" )
|
-- A2ADispatcher:SetSquadron( "23th", "Batumi", "Su-27" )
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- @return #AI_A2A_DISPATCHER
|
-- @return #AI_A2A_DISPATCHER
|
||||||
function AI_A2A_DISPATCHER:SetSquadron( SquadronName, AirbaseName, TemplatePrefixes, Resources )
|
function AI_A2A_DISPATCHER:SetSquadron( SquadronName, AirbaseName, TemplatePrefixes, ResourceCount )
|
||||||
|
|
||||||
|
|
||||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||||
@@ -1480,6 +1548,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
DefenderSquadron.Name = SquadronName
|
DefenderSquadron.Name = SquadronName
|
||||||
DefenderSquadron.Airbase = AIRBASE:FindByName( AirbaseName )
|
DefenderSquadron.Airbase = AIRBASE:FindByName( AirbaseName )
|
||||||
|
DefenderSquadron.AirbaseName = DefenderSquadron.Airbase:GetName()
|
||||||
if not DefenderSquadron.Airbase then
|
if not DefenderSquadron.Airbase then
|
||||||
error( "Cannot find airbase with name:" .. AirbaseName )
|
error( "Cannot find airbase with name:" .. AirbaseName )
|
||||||
end
|
end
|
||||||
@@ -1495,10 +1564,11 @@ do -- AI_A2A_DISPATCHER
|
|||||||
DefenderSquadron.Spawn[#DefenderSquadron.Spawn+1] = self.DefenderSpawns[SpawnTemplate]
|
DefenderSquadron.Spawn[#DefenderSquadron.Spawn+1] = self.DefenderSpawns[SpawnTemplate]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
DefenderSquadron.Resources = Resources
|
DefenderSquadron.ResourceCount = ResourceCount
|
||||||
DefenderSquadron.TemplatePrefixes = TemplatePrefixes
|
DefenderSquadron.TemplatePrefixes = TemplatePrefixes
|
||||||
|
DefenderSquadron.Captured = false -- Not captured. This flag will be set to true, when the airbase where the squadron is located, is captured.
|
||||||
|
|
||||||
self:F( { Squadron = {SquadronName, AirbaseName, TemplatePrefixes, Resources } } )
|
self:F( { Squadron = {SquadronName, AirbaseName, TemplatePrefixes, ResourceCount } } )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1517,6 +1587,54 @@ do -- AI_A2A_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set the Squadron visible before startup of the dispatcher.
|
||||||
|
-- All planes will be spawned as uncontrolled on the parking spot.
|
||||||
|
-- They will lock the parking spot.
|
||||||
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
|
-- @param #string SquadronName The squadron name.
|
||||||
|
-- @return #AI_A2A_DISPATCHER
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Set the Squadron visible before startup of dispatcher.
|
||||||
|
-- A2ADispatcher:SetSquadronVisible( "Mineralnye" )
|
||||||
|
--
|
||||||
|
function AI_A2A_DISPATCHER:SetSquadronVisible( SquadronName )
|
||||||
|
|
||||||
|
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||||
|
|
||||||
|
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||||
|
|
||||||
|
DefenderSquadron.Uncontrolled = true
|
||||||
|
|
||||||
|
for SpawnTemplate, DefenderSpawn in pairs( self.DefenderSpawns ) do
|
||||||
|
DefenderSpawn:InitUnControlled()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the Squadron is visible before startup of the dispatcher.
|
||||||
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
|
-- @param #string SquadronName The squadron name.
|
||||||
|
-- @return #bool true if visible.
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- -- Set the Squadron visible before startup of dispatcher.
|
||||||
|
-- local IsVisible = A2ADispatcher:IsSquadronVisible( "Mineralnye" )
|
||||||
|
--
|
||||||
|
function AI_A2A_DISPATCHER:IsSquadronVisible( SquadronName )
|
||||||
|
|
||||||
|
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||||
|
|
||||||
|
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||||
|
|
||||||
|
if DefenderSquadron then
|
||||||
|
return DefenderSquadron.Uncontrolled == true
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Set a CAP for a Squadron.
|
--- Set a CAP for a Squadron.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
@@ -1663,7 +1781,9 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||||
|
|
||||||
if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 0 ) then
|
if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured.
|
||||||
|
|
||||||
|
if ( not DefenderSquadron.ResourceCount ) or ( DefenderSquadron.ResourceCount and DefenderSquadron.ResourceCount > 0 ) then -- And, if there are sufficient resources.
|
||||||
|
|
||||||
local Cap = DefenderSquadron.Cap
|
local Cap = DefenderSquadron.Cap
|
||||||
if Cap then
|
if Cap then
|
||||||
@@ -1677,6 +1797,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1693,12 +1814,15 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
local DefenderSquadron = self:GetSquadron( SquadronName )
|
local DefenderSquadron = self:GetSquadron( SquadronName )
|
||||||
|
|
||||||
if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 0 ) then
|
if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured.
|
||||||
|
|
||||||
|
if ( not DefenderSquadron.ResourceCount ) or ( DefenderSquadron.ResourceCount and DefenderSquadron.ResourceCount > 0 ) then -- And, if there are sufficient resources.
|
||||||
local Gci = DefenderSquadron.Gci
|
local Gci = DefenderSquadron.Gci
|
||||||
if Gci then
|
if Gci then
|
||||||
return DefenderSquadron
|
return DefenderSquadron
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2450,21 +2574,21 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self.Defenders = self.Defenders or {}
|
self.Defenders = self.Defenders or {}
|
||||||
local DefenderName = Defender:GetName()
|
local DefenderName = Defender:GetName()
|
||||||
self.Defenders[ DefenderName ] = Squadron
|
self.Defenders[ DefenderName ] = Squadron
|
||||||
if Squadron.Resources then
|
if Squadron.ResourceCount then
|
||||||
Squadron.Resources = Squadron.Resources - Size
|
Squadron.ResourceCount = Squadron.ResourceCount - Size
|
||||||
end
|
end
|
||||||
self:F( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } )
|
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_A2A_DISPATCHER self
|
--- @param #AI_A2A_DISPATCHER self
|
||||||
function AI_A2A_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
function AI_A2A_DISPATCHER:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
self.Defenders = self.Defenders or {}
|
self.Defenders = self.Defenders or {}
|
||||||
local DefenderName = Defender:GetName()
|
local DefenderName = Defender:GetName()
|
||||||
if Squadron.Resources then
|
if Squadron.ResourceCount then
|
||||||
Squadron.Resources = Squadron.Resources + Defender:GetSize()
|
Squadron.ResourceCount = Squadron.ResourceCount + Defender:GetSize()
|
||||||
end
|
end
|
||||||
self.Defenders[ DefenderName ] = nil
|
self.Defenders[ DefenderName ] = nil
|
||||||
self:F( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } )
|
self:F( { DefenderName = DefenderName, SquadronResourceCount = Squadron.ResourceCount } )
|
||||||
end
|
end
|
||||||
|
|
||||||
function AI_A2A_DISPATCHER:GetSquadronFromDefender( Defender )
|
function AI_A2A_DISPATCHER:GetSquadronFromDefender( Defender )
|
||||||
@@ -2607,6 +2731,79 @@ do -- AI_A2A_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
|
function AI_A2A_DISPATCHER:ResourceActivate( DefenderSquadron, DefendersNeeded )
|
||||||
|
|
||||||
|
local SquadronName = DefenderSquadron.Name
|
||||||
|
DefendersNeeded = DefendersNeeded or 4
|
||||||
|
local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping
|
||||||
|
DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded
|
||||||
|
|
||||||
|
if self:IsSquadronVisible( SquadronName ) then
|
||||||
|
|
||||||
|
-- Here we CAP the new planes.
|
||||||
|
-- The Resources table is filled in advance.
|
||||||
|
local TemplateID = math.random( 1, #DefenderSquadron.Spawn ) -- Choose the template.
|
||||||
|
|
||||||
|
-- We determine the grouping based on the parameters set.
|
||||||
|
self:F( { DefenderGrouping = DefenderGrouping } )
|
||||||
|
|
||||||
|
-- New we will form the group to spawn in.
|
||||||
|
-- We search for the first free resource matching the template.
|
||||||
|
local DefenderUnitIndex = 1
|
||||||
|
local DefenderCAPTemplate = nil
|
||||||
|
local DefenderName = nil
|
||||||
|
for GroupName, DefenderGroup in pairs( DefenderSquadron.Resources[TemplateID] or {} ) do
|
||||||
|
self:F( { GroupName = GroupName } )
|
||||||
|
local DefenderTemplate = _DATABASE:GetGroupTemplate( GroupName )
|
||||||
|
if DefenderUnitIndex == 1 then
|
||||||
|
DefenderCAPTemplate = UTILS.DeepCopy( DefenderTemplate )
|
||||||
|
self.DefenderCAPIndex = self.DefenderCAPIndex + 1
|
||||||
|
DefenderCAPTemplate.name = SquadronName .. "#" .. self.DefenderCAPIndex .. "#" .. GroupName
|
||||||
|
DefenderName = DefenderCAPTemplate.name
|
||||||
|
else
|
||||||
|
-- Add the unit in the template to the DefenderCAPTemplate.
|
||||||
|
local DefenderUnitTemplate = DefenderTemplate.units[1]
|
||||||
|
DefenderCAPTemplate.units[DefenderUnitIndex] = DefenderUnitTemplate
|
||||||
|
end
|
||||||
|
DefenderUnitIndex = DefenderUnitIndex + 1
|
||||||
|
DefenderSquadron.Resources[TemplateID][GroupName] = nil
|
||||||
|
if DefenderUnitIndex > DefenderGrouping then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if DefenderCAPTemplate then
|
||||||
|
local TakeoffMethod = self:GetSquadronTakeoff( SquadronName )
|
||||||
|
local SpawnGroup = GROUP:Register( DefenderName )
|
||||||
|
DefenderCAPTemplate.lateActivation = nil
|
||||||
|
DefenderCAPTemplate.uncontrolled = nil
|
||||||
|
local Takeoff = self:GetSquadronTakeoff( SquadronName )
|
||||||
|
DefenderCAPTemplate.route.points[1].type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
||||||
|
DefenderCAPTemplate.route.points[1].action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
||||||
|
local Defender = _DATABASE:Spawn( DefenderCAPTemplate )
|
||||||
|
|
||||||
|
self:AddDefenderToSquadron( DefenderSquadron, Defender, DefenderGrouping )
|
||||||
|
return Defender, DefenderGrouping
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Core.Spawn#SPAWN
|
||||||
|
if DefenderGrouping then
|
||||||
|
Spawn:InitGrouping( DefenderGrouping )
|
||||||
|
else
|
||||||
|
Spawn:InitGrouping()
|
||||||
|
end
|
||||||
|
|
||||||
|
local TakeoffMethod = self:GetSquadronTakeoff( SquadronName )
|
||||||
|
local Defender = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP
|
||||||
|
self:AddDefenderToSquadron( DefenderSquadron, Defender, DefenderGrouping )
|
||||||
|
return Defender, DefenderGrouping
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
@@ -2624,13 +2821,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
if Cap then
|
if Cap then
|
||||||
|
|
||||||
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Core.Spawn#SPAWN
|
local DefenderCAP, DefenderGrouping = self:ResourceActivate( DefenderSquadron )
|
||||||
local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping
|
|
||||||
Spawn:InitGrouping( DefenderGrouping )
|
|
||||||
|
|
||||||
local TakeoffMethod = self:GetSquadronTakeoff( SquadronName )
|
|
||||||
local DefenderCAP = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude )
|
|
||||||
self:AddDefenderToSquadron( DefenderSquadron, DefenderCAP, DefenderGrouping )
|
|
||||||
|
|
||||||
if DefenderCAP then
|
if DefenderCAP then
|
||||||
|
|
||||||
@@ -2646,7 +2837,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", Fsm )
|
self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", Fsm )
|
||||||
|
|
||||||
function Fsm:onafterTakeoff( Defender, From, Event, To )
|
function Fsm:onafterTakeoff( Defender, From, Event, To )
|
||||||
self:F({"GCI Birth", Defender:GetName()})
|
self:F({"CAP Birth", Defender:GetName()})
|
||||||
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
|
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
|
||||||
|
|
||||||
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER
|
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
@@ -2680,9 +2871,9 @@ do -- AI_A2A_DISPATCHER
|
|||||||
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then
|
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
Defender:Destroy()
|
Defender:Destroy()
|
||||||
|
self:ParkDefender( Squadron, Defender )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2788,31 +2979,19 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self:F( { Grouping = DefenderGrouping, SquadronGrouping = DefenderSquadron.Grouping, DefaultGrouping = self.DefenderDefault.Grouping } )
|
self:F( { Grouping = DefenderGrouping, SquadronGrouping = DefenderSquadron.Grouping, DefaultGrouping = self.DefenderDefault.Grouping } )
|
||||||
self:F( { DefendersCount = DefenderCount, DefendersNeeded = DefendersNeeded } )
|
self:F( { DefendersCount = DefenderCount, DefendersNeeded = DefendersNeeded } )
|
||||||
|
|
||||||
-- DefenderSquadron.Resources can have the value nil, which expresses unlimited resources.
|
-- DefenderSquadron.ResourceCount can have the value nil, which expresses unlimited resources.
|
||||||
-- DefendersNeeded cannot exceed DefenderSquadron.Resources!
|
-- DefendersNeeded cannot exceed DefenderSquadron.ResourceCount!
|
||||||
if DefenderSquadron.Resources and DefendersNeeded > DefenderSquadron.Resources then
|
if DefenderSquadron.ResourceCount and DefendersNeeded > DefenderSquadron.ResourceCount then
|
||||||
DefendersNeeded = DefenderSquadron.Resources
|
DefendersNeeded = DefenderSquadron.ResourceCount
|
||||||
BreakLoop = true
|
BreakLoop = true
|
||||||
end
|
end
|
||||||
|
|
||||||
while ( DefendersNeeded > 0 ) do
|
while ( DefendersNeeded > 0 ) do
|
||||||
|
|
||||||
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Core.Spawn#SPAWN
|
local DefenderGCI, DefenderGrouping = self:ResourceActivate( DefenderSquadron, DefendersNeeded )
|
||||||
local DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded
|
|
||||||
if DefenderGrouping then
|
|
||||||
Spawn:InitGrouping( DefenderGrouping )
|
|
||||||
else
|
|
||||||
Spawn:InitGrouping()
|
|
||||||
end
|
|
||||||
|
|
||||||
local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName )
|
|
||||||
local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP
|
|
||||||
self:F( { GCIDefender = DefenderGCI:GetName() } )
|
|
||||||
|
|
||||||
DefendersNeeded = DefendersNeeded - DefenderGrouping
|
DefendersNeeded = DefendersNeeded - DefenderGrouping
|
||||||
|
|
||||||
self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI, DefenderGrouping )
|
|
||||||
|
|
||||||
if DefenderGCI then
|
if DefenderGCI then
|
||||||
|
|
||||||
DefenderCount = DefenderCount - DefenderGrouping / DefenderOverhead
|
DefenderCount = DefenderCount - DefenderGrouping / DefenderOverhead
|
||||||
@@ -2879,6 +3058,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then
|
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender )
|
||||||
Defender:Destroy()
|
Defender:Destroy()
|
||||||
|
self:ParkDefender( Squadron, Defender )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end -- if DefenderGCI then
|
end -- if DefenderGCI then
|
||||||
@@ -3460,7 +3640,7 @@ do
|
|||||||
-- For airplanes, 6000 (6km) is recommended, and is also the default value of this parameter.
|
-- For airplanes, 6000 (6km) is recommended, and is also the default value of this parameter.
|
||||||
-- @param #number EngageRadius The radius in meters wherein detected airplanes will be engaged by airborne defenders without a task.
|
-- @param #number EngageRadius The radius in meters wherein detected airplanes will be engaged by airborne defenders without a task.
|
||||||
-- @param #number GciRadius The radius in meters wherein detected airplanes will GCI.
|
-- @param #number GciRadius The radius in meters wherein detected airplanes will GCI.
|
||||||
-- @param #number Resources The amount of resources that will be allocated to each squadron.
|
-- @param #number ResourceCount The amount of resources that will be allocated to each squadron.
|
||||||
-- @return #AI_A2A_GCICAP
|
-- @return #AI_A2A_GCICAP
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -3535,7 +3715,7 @@ do
|
|||||||
--
|
--
|
||||||
-- A2ADispatcher = AI_A2A_GCICAP:New( { "DF CCCP" }, { "SQ CCCP" }, nil, nil, nil, nil, nil, 30 )
|
-- A2ADispatcher = AI_A2A_GCICAP:New( { "DF CCCP" }, { "SQ CCCP" }, nil, nil, nil, nil, nil, 30 )
|
||||||
--
|
--
|
||||||
function AI_A2A_GCICAP:New( EWRPrefixes, TemplatePrefixes, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, Resources )
|
function AI_A2A_GCICAP:New( EWRPrefixes, TemplatePrefixes, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||||
|
|
||||||
local EWRSetGroup = SET_GROUP:New()
|
local EWRSetGroup = SET_GROUP:New()
|
||||||
EWRSetGroup:FilterPrefixes( EWRPrefixes )
|
EWRSetGroup:FilterPrefixes( EWRPrefixes )
|
||||||
@@ -3589,7 +3769,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if Templates then
|
if Templates then
|
||||||
self:SetSquadron( AirbaseName, AirbaseName, Templates, Resources )
|
self:SetSquadron( AirbaseName, AirbaseName, Templates, ResourceCount )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3666,7 +3846,7 @@ do
|
|||||||
-- For airplanes, 6000 (6km) is recommended, and is also the default value of this parameter.
|
-- For airplanes, 6000 (6km) is recommended, and is also the default value of this parameter.
|
||||||
-- @param #number EngageRadius The radius in meters wherein detected airplanes will be engaged by airborne defenders without a task.
|
-- @param #number EngageRadius The radius in meters wherein detected airplanes will be engaged by airborne defenders without a task.
|
||||||
-- @param #number GciRadius The radius in meters wherein detected airplanes will GCI.
|
-- @param #number GciRadius The radius in meters wherein detected airplanes will GCI.
|
||||||
-- @param #number Resources The amount of resources that will be allocated to each squadron.
|
-- @param #number ResourceCount The amount of resources that will be allocated to each squadron.
|
||||||
-- @return #AI_A2A_GCICAP
|
-- @return #AI_A2A_GCICAP
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -3750,9 +3930,9 @@ do
|
|||||||
--
|
--
|
||||||
-- A2ADispatcher = AI_A2A_GCICAP:NewWithBorder( { "DF CCCP" }, { "SQ CCCP" }, "Border", nil, nil, nil, nil, nil, 30 )
|
-- A2ADispatcher = AI_A2A_GCICAP:NewWithBorder( { "DF CCCP" }, { "SQ CCCP" }, "Border", nil, nil, nil, nil, nil, 30 )
|
||||||
--
|
--
|
||||||
function AI_A2A_GCICAP:NewWithBorder( EWRPrefixes, TemplatePrefixes, BorderPrefix, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, Resources )
|
function AI_A2A_GCICAP:NewWithBorder( EWRPrefixes, TemplatePrefixes, BorderPrefix, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||||
|
|
||||||
local self = AI_A2A_GCICAP:New( EWRPrefixes, TemplatePrefixes, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, Resources )
|
local self = AI_A2A_GCICAP:New( EWRPrefixes, TemplatePrefixes, CapPrefixes, CapLimit, GroupingRadius, EngageRadius, GciRadius, ResourceCount )
|
||||||
|
|
||||||
if BorderPrefix then
|
if BorderPrefix then
|
||||||
self:SetBorderZone( ZONE_POLYGON:New( BorderPrefix, GROUP:FindByName( BorderPrefix ) ) )
|
self:SetBorderZone( ZONE_POLYGON:New( BorderPrefix, GROUP:FindByName( BorderPrefix ) ) )
|
||||||
|
|||||||
@@ -351,13 +351,12 @@ function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIPatrol
|
--- @param Wrapper.Group#GROUP AIPatrol
|
||||||
function AI_A2A_PATROL.Resume( AIPatrol )
|
function AI_A2A_PATROL.Resume( AIPatrol, Fsm )
|
||||||
|
|
||||||
AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } )
|
AIPatrol:I( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } )
|
||||||
if AIPatrol:IsAlive() then
|
if AIPatrol:IsAlive() then
|
||||||
local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- AI.AI_A2A#AI_A2A
|
Fsm:__Reset( 1 )
|
||||||
_AI_A2A:__Reset( 1 )
|
Fsm:__Route( 5 )
|
||||||
_AI_A2A:__Route( 5 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -213,8 +213,8 @@ function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone )
|
|||||||
|
|
||||||
local Boarding = false
|
local Boarding = false
|
||||||
|
|
||||||
local LoadInterval = 5
|
local LoadInterval = 2
|
||||||
local LoadDelay = 0
|
local LoadDelay = 1
|
||||||
local Carrier_List = {}
|
local Carrier_List = {}
|
||||||
local Carrier_Weight = {}
|
local Carrier_Weight = {}
|
||||||
|
|
||||||
@@ -262,9 +262,10 @@ function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone )
|
|||||||
Carrier:RouteStop()
|
Carrier:RouteStop()
|
||||||
--Cargo:Ungroup()
|
--Cargo:Ungroup()
|
||||||
Cargo:__Board( -LoadDelay, CarrierUnit )
|
Cargo:__Board( -LoadDelay, CarrierUnit )
|
||||||
LoadDelay = LoadDelay + Cargo:GetCount() * LoadInterval
|
|
||||||
self:__Board( LoadDelay, Cargo, CarrierUnit, PickupZone )
|
self:__Board( LoadDelay, Cargo, CarrierUnit, PickupZone )
|
||||||
|
|
||||||
|
LoadDelay = LoadDelay + Cargo:GetCount() * LoadInterval
|
||||||
|
|
||||||
-- So now this CarrierUnit has Cargo that is being loaded.
|
-- So now this CarrierUnit has Cargo that is being loaded.
|
||||||
-- This will be used further in the logic to follow and to check cargo status.
|
-- This will be used further in the logic to follow and to check cargo status.
|
||||||
self.Carrier_Cargo[Cargo] = CarrierUnit
|
self.Carrier_Cargo[Cargo] = CarrierUnit
|
||||||
@@ -280,6 +281,79 @@ function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if not Loaded == true then
|
||||||
|
-- No loading happened, so we need to pickup something else.
|
||||||
|
self.Relocating = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Boarding
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On before Reload event.
|
||||||
|
-- @param #AI_CARGO self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param Core.Zone#ZONE PickupZone (optional) The zone where the cargo will be picked up. The PickupZone can be nil, if there wasn't any PickupZoneSet provided.
|
||||||
|
function AI_CARGO:onbeforeReload( Carrier, From, Event, To )
|
||||||
|
self:F( { Carrier, From, Event, To } )
|
||||||
|
|
||||||
|
local Boarding = false
|
||||||
|
|
||||||
|
local LoadInterval = 2
|
||||||
|
local LoadDelay = 1
|
||||||
|
local Carrier_List = {}
|
||||||
|
local Carrier_Weight = {}
|
||||||
|
|
||||||
|
if Carrier and Carrier:IsAlive() then
|
||||||
|
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||||
|
local CarrierUnit = CarrierUnit -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
Carrier_List[#Carrier_List+1] = CarrierUnit
|
||||||
|
end
|
||||||
|
|
||||||
|
local Carrier_Count = #Carrier_List
|
||||||
|
local Carrier_Index = 1
|
||||||
|
|
||||||
|
local Loaded = false
|
||||||
|
|
||||||
|
for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do
|
||||||
|
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||||
|
|
||||||
|
self:F( { IsUnLoaded = Cargo:IsUnLoaded(), IsDeployed = Cargo:IsDeployed(), Cargo:GetName(), Carrier:GetName() } )
|
||||||
|
|
||||||
|
-- Try all Carriers, but start from the one according the Carrier_Index
|
||||||
|
for Carrier_Loop = 1, #Carrier_List do
|
||||||
|
|
||||||
|
local CarrierUnit = Carrier_List[Carrier_Index] -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
-- This counters loop through the available Carriers.
|
||||||
|
Carrier_Index = Carrier_Index + 1
|
||||||
|
if Carrier_Index > Carrier_Count then
|
||||||
|
Carrier_Index = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
|
||||||
|
Carrier:RouteStop()
|
||||||
|
Cargo:__Board( -LoadDelay, CarrierUnit )
|
||||||
|
self:__Board( LoadDelay, Cargo, CarrierUnit )
|
||||||
|
|
||||||
|
LoadDelay = LoadDelay + Cargo:GetCount() * LoadInterval
|
||||||
|
|
||||||
|
-- So now this CarrierUnit has Cargo that is being loaded.
|
||||||
|
-- This will be used further in the logic to follow and to check cargo status.
|
||||||
|
self.Carrier_Cargo[Cargo] = CarrierUnit
|
||||||
|
Boarding = true
|
||||||
|
Loaded = true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -307,7 +381,7 @@ function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, Pi
|
|||||||
|
|
||||||
if Carrier and Carrier:IsAlive() then
|
if Carrier and Carrier:IsAlive() then
|
||||||
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
|
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
|
||||||
if not Cargo:IsLoaded() then
|
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
|
||||||
self:__Board( -10, Cargo, CarrierUnit, PickupZone )
|
self:__Board( -10, Cargo, CarrierUnit, PickupZone )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -368,6 +442,7 @@ function AI_CARGO:onafterPickedUp( Carrier, From, Event, To, PickupZone )
|
|||||||
|
|
||||||
self.Relocating = false
|
self.Relocating = false
|
||||||
if HasCargo then
|
if HasCargo then
|
||||||
|
self:F( "Transporting" )
|
||||||
self.Transporting = true
|
self.Transporting = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -383,11 +458,11 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
function AI_CARGO:onafterUnload( Carrier, From, Event, To, DeployZone )
|
function AI_CARGO:onafterUnload( Carrier, From, Event, To, DeployZone, Defend )
|
||||||
self:F( { Carrier, From, Event, To, DeployZone } )
|
self:F( { Carrier, From, Event, To, DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
local UnboardInterval = 10
|
local UnboardInterval = 5
|
||||||
local UnboardDelay = 10
|
local UnboardDelay = 5
|
||||||
|
|
||||||
if Carrier and Carrier:IsAlive() then
|
if Carrier and Carrier:IsAlive() then
|
||||||
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
for _, CarrierUnit in pairs( Carrier:GetUnits() ) do
|
||||||
@@ -398,8 +473,10 @@ function AI_CARGO:onafterUnload( Carrier, From, Event, To, DeployZone )
|
|||||||
if Cargo:IsLoaded() then
|
if Cargo:IsLoaded() then
|
||||||
Cargo:__UnBoard( UnboardDelay )
|
Cargo:__UnBoard( UnboardDelay )
|
||||||
UnboardDelay = UnboardDelay + Cargo:GetCount() * UnboardInterval
|
UnboardDelay = UnboardDelay + Cargo:GetCount() * UnboardInterval
|
||||||
|
self:__Unboard( UnboardDelay, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
|
if not Defend == true then
|
||||||
Cargo:SetDeployed( true )
|
Cargo:SetDeployed( true )
|
||||||
self:__Unboard( UnboardDelay, Cargo, CarrierUnit, DeployZone )
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -415,17 +492,17 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
|
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
|
||||||
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
function AI_CARGO:onafterUnboard( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
|
function AI_CARGO:onafterUnboard( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
self:F( { Carrier, From, Event, To, Cargo:GetName() } )
|
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
if Carrier and Carrier:IsAlive() then
|
if Carrier and Carrier:IsAlive() then
|
||||||
if not Cargo:IsUnLoaded() then
|
if not Cargo:IsUnLoaded() then
|
||||||
self:__Unboard( 10, Cargo, CarrierUnit, DeployZone )
|
self:__Unboard( 10, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:Unloaded( Cargo, CarrierUnit, DeployZone )
|
self:Unloaded( Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -438,8 +515,8 @@ end
|
|||||||
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
|
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
|
||||||
-- @param #boolean Deployed Cargo is deployed.
|
-- @param #boolean Deployed Cargo is deployed.
|
||||||
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
function AI_CARGO:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
|
function AI_CARGO:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone } )
|
self:F( { Carrier, From, Event, To, Cargo:GetName(), DeployZone = DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
local AllUnloaded = true
|
local AllUnloaded = true
|
||||||
|
|
||||||
@@ -465,7 +542,7 @@ function AI_CARGO:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit,
|
|||||||
end
|
end
|
||||||
|
|
||||||
if AllUnloaded == true then
|
if AllUnloaded == true then
|
||||||
self:__Deployed( 5, DeployZone )
|
self:__Deployed( 5, DeployZone, Defend )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -477,10 +554,15 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
function AI_CARGO:onafterDeployed( Carrier, From, Event, To, DeployZone )
|
function AI_CARGO:onafterDeployed( Carrier, From, Event, To, DeployZone, Defend )
|
||||||
self:F( { Carrier, From, Event, To, DeployZone = DeployZone } )
|
self:F( { Carrier, From, Event, To, DeployZone = DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
|
if not Defend == true then
|
||||||
self.Transporting = false
|
self.Transporting = false
|
||||||
|
else
|
||||||
|
self:F( "Defending" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
|
|||||||
self:AddTransition( "*", "Follow", "Following" )
|
self:AddTransition( "*", "Follow", "Following" )
|
||||||
self:AddTransition( "*", "Guard", "Unloaded" )
|
self:AddTransition( "*", "Guard", "Unloaded" )
|
||||||
self:AddTransition( "*", "Home", "*" )
|
self:AddTransition( "*", "Home", "*" )
|
||||||
|
self:AddTransition( "*", "Reload", "Boarding" )
|
||||||
|
|
||||||
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||||
|
|
||||||
@@ -118,7 +119,6 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
|||||||
self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self )
|
self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self )
|
||||||
|
|
||||||
CargoCarrier:HandleEvent( EVENTS.Dead )
|
CargoCarrier:HandleEvent( EVENTS.Dead )
|
||||||
CargoCarrier:HandleEvent( EVENTS.Hit )
|
|
||||||
|
|
||||||
function CargoCarrier:OnEventDead( EventData )
|
function CargoCarrier:OnEventDead( EventData )
|
||||||
self:F({"dead"})
|
self:F({"dead"})
|
||||||
@@ -133,17 +133,19 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function CargoCarrier:OnEventHit( EventData )
|
-- CargoCarrier:HandleEvent( EVENTS.Hit )
|
||||||
self:F({"hit"})
|
--
|
||||||
local AICargoTroops = self:GetState( self, "AI_CARGO_APC" )
|
-- function CargoCarrier:OnEventHit( EventData )
|
||||||
if AICargoTroops then
|
-- self:F({"hit"})
|
||||||
self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
|
-- local AICargoTroops = self:GetState( self, "AI_CARGO_APC" )
|
||||||
if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
|
-- if AICargoTroops then
|
||||||
-- There are enemies within combat radius. Unload the CargoCarrier.
|
-- self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
|
||||||
AICargoTroops:Unload( false )
|
-- if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
|
||||||
end
|
-- -- There are enemies within combat radius. Unload the CargoCarrier.
|
||||||
end
|
-- AICargoTroops:Unload( false )
|
||||||
end
|
-- end
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius )
|
self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius )
|
||||||
self.Coalition = self.CargoCarrier:GetCoalition()
|
self.Coalition = self.CargoCarrier:GetCoalition()
|
||||||
@@ -276,19 +278,20 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
|
|||||||
if self.CarrierCoordinate then
|
if self.CarrierCoordinate then
|
||||||
if self:IsTransporting() == true then
|
if self:IsTransporting() == true then
|
||||||
local Coordinate = APC:GetCoordinate()
|
local Coordinate = APC:GetCoordinate()
|
||||||
|
if self:Is( "Unloaded" ) or self:Is( "Loaded" ) then
|
||||||
self.Zone:Scan( { Object.Category.UNIT } )
|
self.Zone:Scan( { Object.Category.UNIT } )
|
||||||
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||||
if self:Is( "Unloaded" ) or self:Is( "Following" ) then
|
if self:Is( "Unloaded" ) then
|
||||||
-- There are no enemies within combat radius. Load the CargoCarrier.
|
-- There are no enemies within combat radius. Reload the CargoCarrier.
|
||||||
self:Load()
|
self:Reload()
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if self:Is( "Loaded" ) then
|
if self:Is( "Loaded" ) then
|
||||||
-- There are enemies within combat radius. Unload the CargoCarrier.
|
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||||
self:__Unload( 1 )
|
self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy!
|
||||||
else
|
else
|
||||||
if self:Is( "Unloaded" ) then
|
if self:Is( "Unloaded" ) then
|
||||||
self:Follow()
|
--self:Follow()
|
||||||
end
|
end
|
||||||
self:F( "I am here" .. self:GetCurrentState() )
|
self:F( "I am here" .. self:GetCurrentState() )
|
||||||
if self:Is( "Following" ) then
|
if self:Is( "Following" ) then
|
||||||
@@ -313,6 +316,7 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
self.CarrierCoordinate = APC:GetCoordinate()
|
self.CarrierCoordinate = APC:GetCoordinate()
|
||||||
@@ -442,6 +446,45 @@ function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, He
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- On after Unloaded event.
|
||||||
|
-- @param #AI_CARGO_APC self
|
||||||
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
|
||||||
|
-- @param #boolean Deployed Cargo is deployed.
|
||||||
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
|
function AI_CARGO_APC:onafterUnloaded( Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
|
self:F( { Carrier, From, Event, To, DeployZone = DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
|
|
||||||
|
self:GetParent( self, AI_CARGO_APC ).onafterUnloaded( self, Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone, Defend )
|
||||||
|
|
||||||
|
-- If Defend == true then we need to scan for possible enemies within combat zone and engage only ground forces.
|
||||||
|
if Defend == true then
|
||||||
|
self.Zone:Scan( { Object.Category.UNIT } )
|
||||||
|
if not self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||||
|
-- OK, enemies nearby, now find the enemies and attack them.
|
||||||
|
local AttackUnits = self.Zone:GetScannedUnits() -- #list<DCS#Unit>
|
||||||
|
local Move = {}
|
||||||
|
local CargoGroup = Cargo.CargoObject -- Wrapper.Group#GROUP
|
||||||
|
Move[#Move+1] = CargoGroup:GetCoordinate():WaypointGround( 70, "Custom" )
|
||||||
|
for UnitId, AttackUnit in pairs( AttackUnits ) do
|
||||||
|
local MooseUnit = UNIT:Find( AttackUnit )
|
||||||
|
if MooseUnit:GetCoalition() ~= CargoGroup:GetCoalition() then
|
||||||
|
Move[#Move+1] = MooseUnit:GetCoordinate():WaypointGround( 70, "Line abreast" )
|
||||||
|
--MoveTo.Task = CargoGroup:TaskCombo( CargoGroup:TaskAttackUnit( MooseUnit, true ) )
|
||||||
|
self:F( { MooseUnit = MooseUnit:GetName(), CargoGroup = CargoGroup:GetName() } )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
CargoGroup:RoutePush( Move, 0.1 )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- On after Deployed event.
|
--- On after Deployed event.
|
||||||
-- @param #AI_CARGO_APC self
|
-- @param #AI_CARGO_APC self
|
||||||
-- @param Wrapper.Group#GROUP Carrier
|
-- @param Wrapper.Group#GROUP Carrier
|
||||||
@@ -449,12 +492,12 @@ end
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
-- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone )
|
function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone, Defend )
|
||||||
self:F( { APC, From, Event, To, DeployZone = DeployZone } )
|
self:F( { APC, From, Event, To, DeployZone = DeployZone, Defend = Defend } )
|
||||||
|
|
||||||
self:__Guard( 0.1 )
|
self:__Guard( 0.1 )
|
||||||
|
|
||||||
self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone )
|
self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone, Defend )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -894,8 +894,12 @@ end
|
|||||||
-- @param #AI_CARGO_DISPATCHER self
|
-- @param #AI_CARGO_DISPATCHER self
|
||||||
function AI_CARGO_DISPATCHER:onafterMonitor()
|
function AI_CARGO_DISPATCHER:onafterMonitor()
|
||||||
|
|
||||||
|
self:F("Carriers")
|
||||||
|
self.SetCarrier:Flush()
|
||||||
|
|
||||||
for CarrierGroupName, Carrier in pairs( self.SetCarrier:GetSet() ) do
|
for CarrierGroupName, Carrier in pairs( self.SetCarrier:GetSet() ) do
|
||||||
local Carrier = Carrier -- Wrapper.Group#GROUP
|
local Carrier = Carrier -- Wrapper.Group#GROUP
|
||||||
|
if Carrier:IsAlive() ~= nil then
|
||||||
local AI_Cargo = self.AI_Cargo[Carrier]
|
local AI_Cargo = self.AI_Cargo[Carrier]
|
||||||
if not AI_Cargo then
|
if not AI_Cargo then
|
||||||
|
|
||||||
@@ -1108,7 +1112,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
|
|||||||
local PickupCargo = nil
|
local PickupCargo = nil
|
||||||
local PickupZone = nil
|
local PickupZone = nil
|
||||||
|
|
||||||
--self.SetCargo:Flush()
|
self.SetCargo:Flush()
|
||||||
for CargoName, Cargo in UTILS.spairs( self.SetCargo:GetSet(), function( t, a, b ) return t[a]:GetWeight() < t[b]:GetWeight() end ) do
|
for CargoName, Cargo in UTILS.spairs( self.SetCargo:GetSet(), function( t, a, b ) return t[a]:GetWeight() < t[b]:GetWeight() end ) do
|
||||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||||
self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Carrier] ~= nil } )
|
self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Carrier] ~= nil } )
|
||||||
@@ -1139,7 +1143,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
|
|||||||
LargestLoadCapacity = LoadCapacity
|
LargestLoadCapacity = LoadCapacity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- So if there is aa carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier.
|
-- So if there is a carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier.
|
||||||
-- Otherwise break and go to the next carrier.
|
-- Otherwise break and go to the next carrier.
|
||||||
-- This will skip cargo which is too large to be able to be loaded by carriers
|
-- This will skip cargo which is too large to be able to be loaded by carriers
|
||||||
-- and will secure an efficient dispatching scheme.
|
-- and will secure an efficient dispatching scheme.
|
||||||
@@ -1168,6 +1172,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self:__Monitor( self.MonitorTimeInterval )
|
self:__Monitor( self.MonitorTimeInterval )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
do -- CARGO_GROUP
|
do -- CARGO_GROUP
|
||||||
|
|
||||||
--- @type CARGO_GROUP
|
--- @type CARGO_GROUP
|
||||||
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
|
||||||
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
|
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
|
||||||
-- @field #string GroupName The name of the CargoGroup.
|
-- @field #string GroupName The name of the CargoGroup.
|
||||||
|
-- @extends Cargo.Cargo#CARGO_REPORTABLE
|
||||||
|
|
||||||
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
|
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
|
||||||
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
|
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
|
||||||
@@ -291,29 +291,29 @@ do -- CARGO_GROUP
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enter Boarding State.
|
--- After Board Event.
|
||||||
-- @param #CARGO_GROUP self
|
-- @param #CARGO_GROUP self
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||||
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
|
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
|
||||||
|
|
||||||
NearRadius = NearRadius or self.NearRadius
|
NearRadius = NearRadius or self.NearRadius
|
||||||
|
|
||||||
if From == "UnLoaded" then
|
|
||||||
|
|
||||||
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
|
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
|
||||||
self.CargoSet:ForEach(
|
self.CargoSet:ForEach(
|
||||||
function( Cargo, ... )
|
function( Cargo, ... )
|
||||||
|
self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
|
||||||
|
local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP
|
||||||
|
CargoGroup:OptionAlarmStateGreen()
|
||||||
Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
|
Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
|
||||||
end, ...
|
end, ...
|
||||||
)
|
)
|
||||||
|
|
||||||
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
|
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -323,15 +323,17 @@ do -- CARGO_GROUP
|
|||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||||
function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... )
|
function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... )
|
||||||
--self:F( { From, Event, To, CargoCarrier, ...} )
|
--self:F( { From, Event, To, CargoCarrier, ...} )
|
||||||
|
|
||||||
if From == "UnLoaded" then
|
if From == "UnLoaded" then
|
||||||
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
|
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
|
||||||
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
|
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||||
|
if not Cargo:IsDestroyed() then
|
||||||
Cargo:Load( CargoCarrier )
|
Cargo:Load( CargoCarrier )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--self.CargoObject:Destroy()
|
--self.CargoObject:Destroy()
|
||||||
self.CargoCarrier = CargoCarrier
|
self.CargoCarrier = CargoCarrier
|
||||||
@@ -400,7 +402,7 @@ do -- CARGO_GROUP
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||||
self:F( {From, Event, To, ToPointVec2, NearRadius } )
|
self:F( {From, Event, To, ToPointVec2, NearRadius } )
|
||||||
|
|
||||||
NearRadius = NearRadius or 25
|
NearRadius = NearRadius or 25
|
||||||
@@ -443,7 +445,7 @@ do -- CARGO_GROUP
|
|||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
||||||
function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
||||||
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
||||||
|
|
||||||
--local NearRadius = NearRadius or 25
|
--local NearRadius = NearRadius or 25
|
||||||
@@ -464,7 +466,7 @@ do -- CARGO_GROUP
|
|||||||
end
|
end
|
||||||
|
|
||||||
if UnBoarded then
|
if UnBoarded then
|
||||||
return true
|
self:__UnLoad( 1, ToPointVec2, ... )
|
||||||
else
|
else
|
||||||
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
|
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
|
||||||
end
|
end
|
||||||
@@ -474,30 +476,13 @@ do -- CARGO_GROUP
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- UnBoard Event.
|
|
||||||
-- @param #CARGO_GROUP self
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
|
||||||
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
|
|
||||||
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
|
|
||||||
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
|
|
||||||
|
|
||||||
--local NearRadius = NearRadius or 25
|
|
||||||
|
|
||||||
self:__UnLoad( 1, ToPointVec2, ... )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Enter UnLoaded State.
|
--- Enter UnLoaded State.
|
||||||
-- @param #CARGO_GROUP self
|
-- @param #CARGO_GROUP self
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
-- @param #string From
|
-- @param #string From
|
||||||
-- @param #string To
|
-- @param #string To
|
||||||
-- @param Core.Point#POINT_VEC2
|
-- @param Core.Point#POINT_VEC2
|
||||||
function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... )
|
function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
|
||||||
--self:F( { From, Event, To, ToPointVec2 } )
|
--self:F( { From, Event, To, ToPointVec2 } )
|
||||||
|
|
||||||
if From == "Loaded" then
|
if From == "Loaded" then
|
||||||
@@ -507,7 +492,7 @@ do -- CARGO_GROUP
|
|||||||
function( Cargo )
|
function( Cargo )
|
||||||
--Cargo:UnLoad( ToPointVec2 )
|
--Cargo:UnLoad( ToPointVec2 )
|
||||||
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
|
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
|
||||||
Cargo:UnLoad( RandomVec2 )
|
Cargo:UnBoard( RandomVec2 )
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ do -- CARGO_UNIT
|
|||||||
local MaxSpeed = Desc.speedMaxOffRoad
|
local MaxSpeed = Desc.speedMaxOffRoad
|
||||||
local TypeName = Desc.typeName
|
local TypeName = Desc.typeName
|
||||||
|
|
||||||
self:T( self.CargoInAir )
|
--self:F({Unit=self.CargoObject:GetName()})
|
||||||
|
|
||||||
|
-- A cargo unit can only be boarded if it is not dead
|
||||||
|
|
||||||
-- Only move the group to the carrier when the cargo is not in the air
|
-- Only move the group to the carrier when the cargo is not in the air
|
||||||
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
|
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
|
||||||
@@ -272,7 +274,6 @@ do -- CARGO_UNIT
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -286,12 +287,13 @@ do -- CARGO_UNIT
|
|||||||
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
||||||
self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
|
self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
|
||||||
|
|
||||||
|
self:F( { IsAlive=self.CargoObject:IsAlive() } )
|
||||||
|
|
||||||
if CargoCarrier and CargoCarrier:IsAlive() and self.CargoObject and self.CargoObject:IsAlive() then
|
if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then
|
||||||
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
|
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
|
||||||
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5
|
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5
|
||||||
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
|
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
|
||||||
self:__Load( 1, CargoCarrier, ... )
|
self:__Load( -1, CargoCarrier, ... )
|
||||||
else
|
else
|
||||||
if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
|
if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
|
||||||
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
|
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
|
||||||
@@ -306,6 +308,8 @@ do -- CARGO_UNIT
|
|||||||
local Angle = 180
|
local Angle = 180
|
||||||
local Distance = 0
|
local Distance = 0
|
||||||
|
|
||||||
|
--self:F({Unit=self.CargoObject:GetName()})
|
||||||
|
|
||||||
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
|
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
|
||||||
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
@@ -337,26 +341,6 @@ do -- CARGO_UNIT
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Enter Boarding State.
|
|
||||||
-- @param #CARGO_UNIT self
|
|
||||||
-- @param #string Event
|
|
||||||
-- @param #string From
|
|
||||||
-- @param #string To
|
|
||||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
|
||||||
-- @param #number NearRadius Default 25 m.
|
|
||||||
function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
|
|
||||||
--self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
|
|
||||||
|
|
||||||
local Speed = 90
|
|
||||||
local Angle = 180
|
|
||||||
local Distance = 5
|
|
||||||
|
|
||||||
if From == "UnLoaded" or From == "Boarding" then
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Loaded State.
|
--- Loaded State.
|
||||||
-- @param #CARGO_UNIT self
|
-- @param #CARGO_UNIT self
|
||||||
-- @param #string Event
|
-- @param #string Event
|
||||||
@@ -368,10 +352,11 @@ do -- CARGO_UNIT
|
|||||||
|
|
||||||
self.CargoCarrier = CargoCarrier
|
self.CargoCarrier = CargoCarrier
|
||||||
|
|
||||||
-- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects).
|
--self:F({Unit=self.CargoObject:GetName()})
|
||||||
|
|
||||||
|
-- Only destroy the CargoObject if there is a CargoObject (packages don't have CargoObjects).
|
||||||
if self.CargoObject then
|
if self.CargoObject then
|
||||||
self:T("Destroying")
|
self.CargoObject:Destroy( false )
|
||||||
self.CargoObject:Destroy()
|
|
||||||
--self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 )
|
--self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -768,6 +768,24 @@ do -- COORDINATE
|
|||||||
return direction, strength
|
return direction, strength
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the wind direction (from) and strength.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
|
||||||
|
-- @return Direction the wind is blowing from in degrees.
|
||||||
|
function COORDINATE:GetWindWithTurbulenceVec3(height)
|
||||||
|
|
||||||
|
-- AGL height if
|
||||||
|
local landheight=self:GetLandHeight()+0.1 -- we at 0.1 meters to be sure to be above ground since wind is zero below ground level.
|
||||||
|
|
||||||
|
-- Point at which the wind is evaluated.
|
||||||
|
local point={x=self.x, y=math.max(height or self.y, landheight), z=self.z}
|
||||||
|
|
||||||
|
-- Get wind velocity vector including turbulences.
|
||||||
|
local vec3 = atmosphere.getWindWithTurbulence(point)
|
||||||
|
|
||||||
|
return vec3
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Settings}.
|
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Settings}.
|
||||||
-- The text will reflect the wind like this:
|
-- The text will reflect the wind like this:
|
||||||
@@ -1767,7 +1785,8 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- Return a BR string from a COORDINATE to the COORDINATE.
|
--- Return a BR string from a COORDINATE to the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||||
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The BR text.
|
-- @return #string The BR text.
|
||||||
function COORDINATE:ToStringBR( FromCoordinate, Settings )
|
function COORDINATE:ToStringBR( FromCoordinate, Settings )
|
||||||
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
||||||
@@ -1778,7 +1797,8 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- Return a BRAA string from a COORDINATE to the COORDINATE.
|
--- Return a BRAA string from a COORDINATE to the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||||
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The BR text.
|
-- @return #string The BR text.
|
||||||
function COORDINATE:ToStringBRA( FromCoordinate, Settings )
|
function COORDINATE:ToStringBRA( FromCoordinate, Settings )
|
||||||
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
||||||
@@ -1791,6 +1811,7 @@ do -- COORDINATE
|
|||||||
--- Return a BULLS string out of the BULLS of the coalition to the COORDINATE.
|
--- Return a BULLS string out of the BULLS of the coalition to the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param DCS#coalition.side Coalition The coalition.
|
-- @param DCS#coalition.side Coalition The coalition.
|
||||||
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The BR text.
|
-- @return #string The BR text.
|
||||||
function COORDINATE:ToStringBULLS( Coalition, Settings )
|
function COORDINATE:ToStringBULLS( Coalition, Settings )
|
||||||
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
|
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
|
||||||
@@ -1830,7 +1851,7 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- Provides a Lat Lon string in Degree Minute Second format.
|
--- Provides a Lat Lon string in Degree Minute Second format.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The LL DMS Text
|
-- @return #string The LL DMS Text
|
||||||
function COORDINATE:ToStringLLDMS( Settings )
|
function COORDINATE:ToStringLLDMS( Settings )
|
||||||
|
|
||||||
@@ -1841,7 +1862,7 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- Provides a Lat Lon string in Degree Decimal Minute format.
|
--- Provides a Lat Lon string in Degree Decimal Minute format.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The LL DDM Text
|
-- @return #string The LL DDM Text
|
||||||
function COORDINATE:ToStringLLDDM( Settings )
|
function COORDINATE:ToStringLLDDM( Settings )
|
||||||
|
|
||||||
@@ -1852,7 +1873,7 @@ do -- COORDINATE
|
|||||||
|
|
||||||
--- Provides a MGRS string
|
--- Provides a MGRS string
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The MGRS Text
|
-- @return #string The MGRS Text
|
||||||
function COORDINATE:ToStringMGRS( Settings ) --R2.1 Fixes issue #424.
|
function COORDINATE:ToStringMGRS( Settings ) --R2.1 Fixes issue #424.
|
||||||
|
|
||||||
@@ -1866,10 +1887,12 @@ do -- COORDINATE
|
|||||||
-- * Uses default settings in COORDINATE.
|
-- * Uses default settings in COORDINATE.
|
||||||
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
|
-- @param #COORDINATE ReferenceCoord The refrence coordinate.
|
||||||
|
-- @param #string ReferenceName The refrence name.
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The coordinate Text in the configured coordinate system.
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings ) -- R2.2
|
function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings )
|
||||||
|
|
||||||
self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
|
self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
|
||||||
|
|
||||||
@@ -1896,9 +1919,9 @@ do -- COORDINATE
|
|||||||
--- Provides a coordinate string of the point, based on the A2G coordinate format system.
|
--- Provides a coordinate string of the point, based on the A2G coordinate format system.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The coordinate Text in the configured coordinate system.
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
function COORDINATE:ToStringA2G( Controllable, Settings ) -- R2.2
|
function COORDINATE:ToStringA2G( Controllable, Settings )
|
||||||
|
|
||||||
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
||||||
|
|
||||||
@@ -1931,7 +1954,7 @@ do -- COORDINATE
|
|||||||
--- Provides a coordinate string of the point, based on the A2A coordinate format system.
|
--- Provides a coordinate string of the point, based on the A2A coordinate format system.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The coordinate Text in the configured coordinate system.
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
function COORDINATE:ToStringA2A( Controllable, Settings ) -- R2.2
|
function COORDINATE:ToStringA2A( Controllable, Settings ) -- R2.2
|
||||||
|
|
||||||
@@ -1970,7 +1993,7 @@ do -- COORDINATE
|
|||||||
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @param Tasking.Task#TASK Task The task for which coordinates need to be calculated.
|
-- @param Tasking.Task#TASK Task The task for which coordinates need to be calculated.
|
||||||
-- @return #string The coordinate Text in the configured coordinate system.
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
function COORDINATE:ToString( Controllable, Settings, Task )
|
function COORDINATE:ToString( Controllable, Settings, Task )
|
||||||
@@ -2023,7 +2046,7 @@ do -- COORDINATE
|
|||||||
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The pressure text in the configured measurement system.
|
-- @return #string The pressure text in the configured measurement system.
|
||||||
function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3
|
function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3
|
||||||
|
|
||||||
@@ -2039,9 +2062,9 @@ do -- COORDINATE
|
|||||||
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The wind text in the configured measurement system.
|
-- @return #string The wind text in the configured measurement system.
|
||||||
function COORDINATE:ToStringWind( Controllable, Settings ) -- R2.3
|
function COORDINATE:ToStringWind( Controllable, Settings )
|
||||||
|
|
||||||
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
||||||
|
|
||||||
@@ -2055,9 +2078,9 @@ do -- COORDINATE
|
|||||||
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS
|
||||||
-- @return #string The temperature text in the configured measurement system.
|
-- @return #string The temperature text in the configured measurement system.
|
||||||
function COORDINATE:ToStringTemperature( Controllable, Settings ) -- R2.3
|
function COORDINATE:ToStringTemperature( Controllable, Settings )
|
||||||
|
|
||||||
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
||||||
|
|
||||||
|
|||||||
@@ -1908,7 +1908,7 @@ do -- SET_UNIT
|
|||||||
if _DATABASE then
|
if _DATABASE then
|
||||||
self:_FilterStart()
|
self:_FilterStart()
|
||||||
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
||||||
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrashOr )
|
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||||
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||||
self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash )
|
self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash )
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1702,7 +1702,7 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude, TerminalT
|
|||||||
-- When spawned in the air, we need to generate a Takeoff Event.
|
-- When spawned in the air, we need to generate a Takeoff Event.
|
||||||
if Takeoff == GROUP.Takeoff.Air then
|
if Takeoff == GROUP.Takeoff.Air then
|
||||||
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
|
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
|
||||||
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 )
|
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 5 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2005,10 +2005,10 @@ end
|
|||||||
function SPAWN:InitUnControlled( UnControlled )
|
function SPAWN:InitUnControlled( UnControlled )
|
||||||
self:F2( { self.SpawnTemplatePrefix, UnControlled } )
|
self:F2( { self.SpawnTemplatePrefix, UnControlled } )
|
||||||
|
|
||||||
self.SpawnUnControlled = UnControlled
|
self.SpawnUnControlled = UnControlled or true
|
||||||
|
|
||||||
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
||||||
self.SpawnGroups[SpawnGroupID].UnControlled = UnControlled
|
self.SpawnGroups[SpawnGroupID].UnControlled = self.SpawnUnControlled
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ do -- UserFlag
|
|||||||
--
|
--
|
||||||
function USERFLAG:Set( Number ) --R2.3
|
function USERFLAG:Set( Number ) --R2.3
|
||||||
|
|
||||||
self:F( { Number = Number } )
|
|
||||||
|
|
||||||
trigger.action.setUserFlag( self.UserFlagName, Number )
|
trigger.action.setUserFlag( self.UserFlagName, Number )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ PSEUDOATC.id="PseudoATC | "
|
|||||||
|
|
||||||
--- PSEUDOATC version.
|
--- PSEUDOATC version.
|
||||||
-- @field #number version
|
-- @field #number version
|
||||||
PSEUDOATC.version="0.9.0"
|
PSEUDOATC.version="0.9.1"
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -743,9 +743,9 @@ function PSEUDOATC:ReportBR(id, position, location)
|
|||||||
local coord=unit:GetCoordinate()
|
local coord=unit:GetCoordinate()
|
||||||
|
|
||||||
-- Direction vector from current position (coord) to target (position).
|
-- Direction vector from current position (coord) to target (position).
|
||||||
local pos=coord:Translate(30,90)
|
local angle=coord:HeadingTo(position)
|
||||||
local vec3=coord:GetDirectionVec3(pos)
|
|
||||||
local angle=coord:GetAngleDegrees(vec3)
|
-- Range from current to
|
||||||
local range=coord:Get2DDistance(position)
|
local range=coord:Get2DDistance(position)
|
||||||
|
|
||||||
-- Bearing string.
|
-- Bearing string.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
-- * Strategic components such as capturing, defending and destroying warehouses and their associated infrastructure.
|
-- * Strategic components such as capturing, defending and destroying warehouses and their associated infrastructure.
|
||||||
-- * Intelligent spawning of aircraft on airports (only if enough parking spots are available).
|
-- * Intelligent spawning of aircraft on airports (only if enough parking spots are available).
|
||||||
-- * Possibility to hook into events and customize actions.
|
-- * Possibility to hook into events and customize actions.
|
||||||
|
-- * Persistence of assets. Warehouse assets can be saved and loaded from file.
|
||||||
-- * Can be easily interfaced to other MOOSE classes.
|
-- * Can be easily interfaced to other MOOSE classes.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
-- @field Core.Point#COORDINATE rail Closest point to warehouse on rail.
|
-- @field Core.Point#COORDINATE rail Closest point to warehouse on rail.
|
||||||
-- @field Core.Zone#ZONE spawnzone Zone in which assets are spawned.
|
-- @field Core.Zone#ZONE spawnzone Zone in which assets are spawned.
|
||||||
-- @field #string wid Identifier of the warehouse printed before other output to DCS.log file.
|
-- @field #string wid Identifier of the warehouse printed before other output to DCS.log file.
|
||||||
-- @field #number uid Unit identifier of the warehouse. Derived from the associated airbase.
|
-- @field #number uid Unit identifier of the warehouse. Derived from id of warehouse static element.
|
||||||
-- @field #number markerid ID of the warehouse marker at the airbase.
|
-- @field #number markerid ID of the warehouse marker at the airbase.
|
||||||
-- @field #number dTstatus Time interval in seconds of updating the warehouse status and processing new events. Default 30 seconds.
|
-- @field #number dTstatus Time interval in seconds of updating the warehouse status and processing new events. Default 30 seconds.
|
||||||
-- @field #number queueid Unit id of each request in the queue. Essentially a running number starting at one and incremented when a new request is added.
|
-- @field #number queueid Unit id of each request in the queue. Essentially a running number starting at one and incremented when a new request is added.
|
||||||
@@ -65,6 +66,9 @@
|
|||||||
-- @field #table offroadpaths Table holding user defined paths from one warehouse to another.
|
-- @field #table offroadpaths Table holding user defined paths from one warehouse to another.
|
||||||
-- @field #boolean autodefence When the warehouse is under attack, automatically spawn assets to defend the warehouse.
|
-- @field #boolean autodefence When the warehouse is under attack, automatically spawn assets to defend the warehouse.
|
||||||
-- @field #number spawnzonemaxdist Max distance between warehouse and spawn zone. Default 5000 meters.
|
-- @field #number spawnzonemaxdist Max distance between warehouse and spawn zone. Default 5000 meters.
|
||||||
|
-- @field #boolean autosave Automatically save assets to file when mission ends.
|
||||||
|
-- @field #string autosavepath Path where the asset file is saved on auto save.
|
||||||
|
-- @field #string autosavefilename File name of the auto asset save file. Default is auto generated from warehouse id and name.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Have your assets at the right place at the right time - or not!
|
--- Have your assets at the right place at the right time - or not!
|
||||||
@@ -676,6 +680,69 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
-- # Persistence of Assets
|
||||||
|
--
|
||||||
|
-- Assets in stock of a warehouse can be saved to a file on your hard drive and then loaded from that file at a later point. This enables to restart the mission
|
||||||
|
-- and restore the warehouse stock.
|
||||||
|
--
|
||||||
|
-- ## Prerequisites
|
||||||
|
--
|
||||||
|
-- **Important** By default, DCS does not allow for writing data to files. Therefore, one first has to comment out the line "sanitizeModule('io')", i.e.
|
||||||
|
--
|
||||||
|
-- do
|
||||||
|
-- sanitizeModule('os')
|
||||||
|
-- --sanitizeModule('io')
|
||||||
|
-- sanitizeModule('lfs')
|
||||||
|
-- require = nil
|
||||||
|
-- loadlib = nil
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- in the file "MissionScripting.lua", which is located in the subdirectory "Scripts" of your DCS installation root directory.
|
||||||
|
--
|
||||||
|
-- ### Don't!
|
||||||
|
--
|
||||||
|
-- Do not use **semi-colons** or **equal signs** in the group names of your assets as these are used as separators in the saved and loaded files texts.
|
||||||
|
-- If you do, it will cause problems and give you a headache!
|
||||||
|
--
|
||||||
|
-- ## Save Assets
|
||||||
|
--
|
||||||
|
-- Saving asset data to file is achieved by the @{WAREHOUSE.Save}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||||
|
-- warehouse data is saved. If you do not specify a path, the file is saved your the DCS installation root directory.
|
||||||
|
-- The parameter *filename* is optional and defines the name of the saved file. By default this is automatically created from the warehouse id and name, for example
|
||||||
|
-- "Warehouse-1234_Batumi.txt".
|
||||||
|
--
|
||||||
|
-- warehouseBatumi:Save("D:\\My Warehouse Data\\")
|
||||||
|
--
|
||||||
|
-- This will save all asset data to in "D:\\My Warehouse Data\\Warehouse-1234_Batumi.txt".
|
||||||
|
--
|
||||||
|
-- ### Automatic Save at Mission End
|
||||||
|
--
|
||||||
|
-- The assets can be saved automatically when the mission is ended via the @{WAREHOUSE.SetSaveOnMissionEnd}(*path*, *filename*) function, i.e.
|
||||||
|
--
|
||||||
|
-- warehouseBatumi:SetSaveOnMissionEnd("D:\\My Warehouse Data\\")
|
||||||
|
--
|
||||||
|
-- ## Load Assets
|
||||||
|
--
|
||||||
|
-- Loading assets data from file is achieved by the @{WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
|
||||||
|
-- warehouse data is loaded from. If you do not specify a path, the file is loaded from your the DCS installation root directory.
|
||||||
|
-- The parameter *filename* is optional and defines the name of the file to load. By default this is automatically generated from the warehouse id and name, for example
|
||||||
|
-- "Warehouse-1234_Batumi.txt".
|
||||||
|
--
|
||||||
|
-- Note that the warehouse **must not be started** and in the *Running* state in order to load the assets. In other words, loading should happen after the
|
||||||
|
-- @{#WAREHOUSE.New} command is specified in the code but before the @{#WAREHOUSE.Start} command is given.
|
||||||
|
--
|
||||||
|
-- Loading the assets is done by
|
||||||
|
--
|
||||||
|
-- warehouseBatumi:New(STATIC:FindByName("Warehouse Batumi"))
|
||||||
|
-- warehouseBatumi:Load("D:\\My Warehouse Data\\")
|
||||||
|
-- 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.
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
-- # Examples
|
-- # Examples
|
||||||
--
|
--
|
||||||
-- This section shows some examples how the WAREHOUSE class is used in practice. This is one of the best ways to explain things, in my opinion.
|
-- This section shows some examples how the WAREHOUSE class is used in practice. This is one of the best ways to explain things, in my opinion.
|
||||||
@@ -1485,6 +1552,9 @@ WAREHOUSE = {
|
|||||||
offroadpaths = {},
|
offroadpaths = {},
|
||||||
autodefence = false,
|
autodefence = false,
|
||||||
spawnzonemaxdist = 5000,
|
spawnzonemaxdist = 5000,
|
||||||
|
autosave = false,
|
||||||
|
autosavepath = nil,
|
||||||
|
autosavefile = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Item of the warehouse stock table.
|
--- Item of the warehouse stock table.
|
||||||
@@ -1507,6 +1577,7 @@ WAREHOUSE = {
|
|||||||
-- @field #number loadradius Distance when cargo is loaded into the carrier.
|
-- @field #number loadradius Distance when cargo is loaded into the carrier.
|
||||||
-- @field DCS#AI.Skill skill Skill of AI unit.
|
-- @field DCS#AI.Skill skill Skill of AI unit.
|
||||||
-- @field #string livery Livery of the asset.
|
-- @field #string livery Livery of the asset.
|
||||||
|
-- @field #string assignment Assignment of the asset. This could, e.g., be used in the @{#WAREHOUSE.OnAfterNewAsset) funktion.
|
||||||
|
|
||||||
--- Item of the warehouse queue table.
|
--- Item of the warehouse queue table.
|
||||||
-- @type WAREHOUSE.Queueitem
|
-- @type WAREHOUSE.Queueitem
|
||||||
@@ -1655,7 +1726,7 @@ WAREHOUSE.db = {
|
|||||||
|
|
||||||
--- Warehouse class version.
|
--- Warehouse class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
WAREHOUSE.version="0.6.1"
|
WAREHOUSE.version="0.6.4"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO: Warehouse todo list.
|
-- TODO: Warehouse todo list.
|
||||||
@@ -1771,9 +1842,10 @@ function WAREHOUSE:New(warehouse, alias)
|
|||||||
|
|
||||||
-- Add FSM transitions.
|
-- Add FSM transitions.
|
||||||
-- From State --> Event --> To State
|
-- From State --> Event --> To State
|
||||||
self:AddTransition("NotReadyYet", "Load", "Loaded") -- TODO Load the warehouse state. No sure if it should be in stopped state.
|
self:AddTransition("NotReadyYet", "Load", "Loaded") -- Load the warehouse state from scatch.
|
||||||
|
self:AddTransition("Stopped", "Load", "Loaded") -- Load the warehouse state stopped state.
|
||||||
self:AddTransition("NotReadyYet", "Start", "Running") -- Start the warehouse from scratch.
|
self:AddTransition("NotReadyYet", "Start", "Running") -- Start the warehouse from scratch.
|
||||||
self:AddTransition("Loaded", "Start", "Running") -- TODO Start the warehouse when loaded from disk.
|
self:AddTransition("Loaded", "Start", "Running") -- Start the warehouse when loaded from disk.
|
||||||
self:AddTransition("*", "Status", "*") -- Status update.
|
self:AddTransition("*", "Status", "*") -- Status update.
|
||||||
self:AddTransition("*", "AddAsset", "*") -- Add asset to warehouse stock.
|
self:AddTransition("*", "AddAsset", "*") -- Add asset to warehouse stock.
|
||||||
self:AddTransition("*", "NewAsset", "*") -- New asset was added to warehouse stock.
|
self:AddTransition("*", "NewAsset", "*") -- New asset was added to warehouse stock.
|
||||||
@@ -1788,9 +1860,12 @@ function WAREHOUSE:New(warehouse, alias)
|
|||||||
self:AddTransition("Running", "Pause", "Paused") -- Pause the processing of new requests. Still possible to add assets and requests.
|
self:AddTransition("Running", "Pause", "Paused") -- Pause the processing of new requests. Still possible to add assets and requests.
|
||||||
self:AddTransition("Paused", "Unpause", "Running") -- Unpause the warehouse. Queued requests are processed again.
|
self:AddTransition("Paused", "Unpause", "Running") -- Unpause the warehouse. Queued requests are processed again.
|
||||||
self:AddTransition("*", "Stop", "Stopped") -- Stop the warehouse.
|
self:AddTransition("*", "Stop", "Stopped") -- Stop the warehouse.
|
||||||
|
self:AddTransition("Stopped", "Restart", "Running") -- Restart the warehouse when it was stopped before.
|
||||||
|
self:AddTransition("Loaded", "Restart", "Running") -- Restart the warehouse when assets were loaded from file before.
|
||||||
self:AddTransition("*", "Save", "*") -- TODO Save the warehouse state to disk.
|
self:AddTransition("*", "Save", "*") -- TODO Save the warehouse state to disk.
|
||||||
self:AddTransition("*", "Attacked", "Attacked") -- Warehouse is under attack by enemy coalition.
|
self:AddTransition("*", "Attacked", "Attacked") -- Warehouse is under attack by enemy coalition.
|
||||||
self:AddTransition("Attacked", "Defeated", "Running") -- Attack by other coalition was defeated!
|
self:AddTransition("Attacked", "Defeated", "Running") -- Attack by other coalition was defeated!
|
||||||
|
self:AddTransition("*", "ChangeCountry", "*") -- Change country (and coalition) of the warehouse. Warehouse is respawned!
|
||||||
self:AddTransition("Attacked", "Captured", "Running") -- Warehouse was captured by another coalition. It must have been attacked first.
|
self:AddTransition("Attacked", "Captured", "Running") -- Warehouse was captured by another coalition. It must have been attacked first.
|
||||||
self:AddTransition("*", "AirbaseCaptured", "*") -- Airbase was captured by other coalition.
|
self:AddTransition("*", "AirbaseCaptured", "*") -- Airbase was captured by other coalition.
|
||||||
self:AddTransition("*", "AirbaseRecaptured", "*") -- Airbase was re-captured from other coalition.
|
self:AddTransition("*", "AirbaseRecaptured", "*") -- Airbase was re-captured from other coalition.
|
||||||
@@ -1810,15 +1885,24 @@ function WAREHOUSE:New(warehouse, alias)
|
|||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #number delay Delay in seconds.
|
-- @param #number delay Delay in seconds.
|
||||||
|
|
||||||
--- Triggers the FSM event "Stop". Stops the warehouse and all its event handlers.
|
--- Triggers the FSM event "Stop". Stops the warehouse and all its event handlers. All waiting and pending queue items are deleted as well and all assets are removed from stock.
|
||||||
-- @function [parent=#WAREHOUSE] Stop
|
-- @function [parent=#WAREHOUSE] Stop
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
|
|
||||||
--- Triggers the FSM event "Stop" after a delay. Stops the warehouse and all its event handlers.
|
--- Triggers the FSM event "Stop" after a delay. Stops the warehouse and all its event handlers. All waiting and pending queue items are deleted as well and all assets are removed from stock.
|
||||||
-- @function [parent=#WAREHOUSE] __Stop
|
-- @function [parent=#WAREHOUSE] __Stop
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #number delay Delay in seconds.
|
-- @param #number delay Delay in seconds.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Restart". Restarts the warehouse from stopped state by reactivating the event handlers *only*.
|
||||||
|
-- @function [parent=#WAREHOUSE] Restart
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Restart" after a delay. Restarts the warehouse from stopped state by reactivating the event handlers *only*.
|
||||||
|
-- @function [parent=#WAREHOUSE] __Restart
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #number delay Delay in seconds.
|
||||||
|
|
||||||
--- Triggers the FSM event "Pause". Pauses the warehouse. Assets can still be added and requests be made. However, requests are not processed.
|
--- Triggers the FSM event "Pause". Pauses the warehouse. Assets can still be added and requests be made. However, requests are not processed.
|
||||||
-- @function [parent=#WAREHOUSE] Pause
|
-- @function [parent=#WAREHOUSE] Pause
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
@@ -2071,6 +2155,26 @@ function WAREHOUSE:New(warehouse, alias)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "ChangeCountry" so the warehouse is respawned with the new country.
|
||||||
|
-- @function [parent=#WAREHOUSE] ChangeCountry
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param DCS#country.id Country New country id of the warehouse.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "ChangeCountry" after a delay so the warehouse is respawned with the new country.
|
||||||
|
-- @function [parent=#WAREHOUSE] __ChangeCountry
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #number delay Delay in seconds.
|
||||||
|
-- @param DCS#country.id Country Country id which has captured the warehouse.
|
||||||
|
|
||||||
|
--- On after "ChangeCountry" event user function. Called when the warehouse has changed its country.
|
||||||
|
-- @function [parent=#WAREHOUSE] OnAfterChangeCountry
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param DCS#country.id Country New country id of the warehouse, i.e. a number @{DCS#country.id} enumerator.
|
||||||
|
|
||||||
|
|
||||||
--- Triggers the FSM event "Captured" when a warehouse has been captured by another coalition.
|
--- Triggers the FSM event "Captured" when a warehouse has been captured by another coalition.
|
||||||
-- @function [parent=#WAREHOUSE] Captured
|
-- @function [parent=#WAREHOUSE] Captured
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
@@ -2162,7 +2266,7 @@ function WAREHOUSE:New(warehouse, alias)
|
|||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
|
|
||||||
--- Triggers the FSM event "Destroyed" with a delay when the warehouse was destroyed. Services are stopped.
|
--- Triggers the FSM event "Destroyed" with a delay when the warehouse was destroyed. Services are stopped.
|
||||||
-- @function [parent=#WAREHOUSE] Destroyed
|
-- @function [parent=#WAREHOUSE] __Destroyed
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #number delay Delay in seconds.
|
-- @param #number delay Delay in seconds.
|
||||||
|
|
||||||
@@ -2173,6 +2277,53 @@ function WAREHOUSE:New(warehouse, alias)
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Save" when the warehouse assets are saved to file on disk.
|
||||||
|
-- @function [parent=#WAREHOUSE] Save
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string path Path where the file is saved. Default is the DCS installation root directory.
|
||||||
|
-- @param #string filename (Optional) File name. Default is WAREHOUSE-<UID>_<ALIAS>.txt.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Save" with a delay when the warehouse assets are saved to a file.
|
||||||
|
-- @function [parent=#WAREHOUSE] __Save
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #number delay Delay in seconds.
|
||||||
|
-- @param #string path Path where the file is saved. Default is the DCS installation root directory.
|
||||||
|
-- @param #string filename (Optional) File name. Default is WAREHOUSE-<UID>_<ALIAS>.txt.
|
||||||
|
|
||||||
|
--- On after "Save" event user function. Called when the warehouse assets are saved to disk.
|
||||||
|
-- @function [parent=#WAREHOUSE] OnAfterSave
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string path Path where the file is saved. Default is the DCS installation root directory.
|
||||||
|
-- @param #string filename (Optional) File name. Default is WAREHOUSE-<UID>_<ALIAS>.txt.
|
||||||
|
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Load" when the warehouse is loaded from a file on disk.
|
||||||
|
-- @function [parent=#WAREHOUSE] Load
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string path Path where the file is located. Default is the DCS installation root directory.
|
||||||
|
-- @param #string filename (Optional) File name. Default is WAREHOUSE-<UID>_<ALIAS>.txt.
|
||||||
|
|
||||||
|
--- Triggers the FSM event "Load" with a delay when the warehouse assets are loaded from disk.
|
||||||
|
-- @function [parent=#WAREHOUSE] __Load
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #number delay Delay in seconds.
|
||||||
|
-- @param #string path Path where the file is located. Default is the DCS installation root directory.
|
||||||
|
-- @param #string filename (Optional) File name. Default is WAREHOUSE-<UID>_<ALIAS>.txt.
|
||||||
|
|
||||||
|
--- On after "Load" event user function. Called when the warehouse assets are loaded from disk.
|
||||||
|
-- @function [parent=#WAREHOUSE] OnAfterLoad
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string path Path where the file is located. Default is the DCS installation root directory.
|
||||||
|
-- @param #string filename (Optional) File name. Default is WAREHOUSE-<UID>_<ALIAS>.txt.
|
||||||
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2258,6 +2409,18 @@ function WAREHOUSE:SetAutoDefenceOff()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set auto defence off. This is the default.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string path Path where to save the asset data file.
|
||||||
|
-- @param #string filename File name. Default is generated automatically from warehouse id.
|
||||||
|
-- @return #WAREHOUSE self
|
||||||
|
function WAREHOUSE:SetSaveOnMissionEnd(path, filename)
|
||||||
|
self.autosave=true
|
||||||
|
self.autosavepath=path
|
||||||
|
self.autosavefile=filename
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the airbase belonging to this warehouse.
|
--- Set the airbase belonging to this warehouse.
|
||||||
-- Note that it has to be of the same coalition as the warehouse.
|
-- Note that it has to be of the same coalition as the warehouse.
|
||||||
@@ -2903,6 +3066,7 @@ function WAREHOUSE:onafterStart(From, Event, To)
|
|||||||
self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead)
|
self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead)
|
||||||
self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead)
|
self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead)
|
||||||
self:HandleEvent(EVENTS.BaseCaptured, self._OnEventBaseCaptured)
|
self:HandleEvent(EVENTS.BaseCaptured, self._OnEventBaseCaptured)
|
||||||
|
self:HandleEvent(EVENTS.MissionEnd, self._OnEventMissionEnd)
|
||||||
|
|
||||||
-- This event triggers the arrived event for air assets.
|
-- This event triggers the arrived event for air assets.
|
||||||
-- TODO Might need to make this landing or optional!
|
-- TODO Might need to make this landing or optional!
|
||||||
@@ -2914,6 +3078,36 @@ function WAREHOUSE:onafterStart(From, Event, To)
|
|||||||
self:__Status(-1)
|
self:__Status(-1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- On after "Restart" event. Restarts the warehouse when it was in stopped state by reactivating the event handlers *only*.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
function WAREHOUSE:onafterRestart(From, Event, To)
|
||||||
|
|
||||||
|
self:I(self.wid..string.format("Restarting Warehouse %s.", self.alias))
|
||||||
|
|
||||||
|
-- Handle events:
|
||||||
|
self:HandleEvent(EVENTS.Birth, self._OnEventBirth)
|
||||||
|
self:HandleEvent(EVENTS.EngineStartup, self._OnEventEngineStartup)
|
||||||
|
self:HandleEvent(EVENTS.Takeoff, self._OnEventTakeOff)
|
||||||
|
self:HandleEvent(EVENTS.Land, self._OnEventLanding)
|
||||||
|
self:HandleEvent(EVENTS.EngineShutdown, self._OnEventEngineShutdown)
|
||||||
|
self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead)
|
||||||
|
self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead)
|
||||||
|
self:HandleEvent(EVENTS.BaseCaptured, self._OnEventBaseCaptured)
|
||||||
|
|
||||||
|
-- This event triggers the arrived event for air assets.
|
||||||
|
-- TODO Might need to make this landing or optional!
|
||||||
|
-- In fact, it would be better if the type could be defined for only for the warehouse which receives stuff,
|
||||||
|
-- since there will be warehouses with small airbases and little space or other problems!
|
||||||
|
self:HandleEvent(EVENTS.EngineShutdown, self._OnEventArrived)
|
||||||
|
|
||||||
|
-- Start the status monitoring.
|
||||||
|
self:__Status(-1)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- On after "Stop" event. Stops the warehouse, unhandles all events.
|
--- On after "Stop" event. Stops the warehouse, unhandles all events.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -2941,8 +3135,10 @@ function WAREHOUSE:onafterStop(From, Event, To)
|
|||||||
self.stock=nil
|
self.stock=nil
|
||||||
self.stock={}
|
self.stock={}
|
||||||
|
|
||||||
|
self:_UpdateWarehouseMarkText()
|
||||||
|
|
||||||
-- Clear all pending schedules.
|
-- Clear all pending schedules.
|
||||||
self.CallScheduler:Clear()
|
--self.CallScheduler:Clear()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- On after "Pause" event. Pauses the warehouse, i.e. no requests are processed. However, new requests and new assets can be added in this state.
|
--- On after "Pause" event. Pauses the warehouse, i.e. no requests are processed. However, new requests and new assets can be added in this state.
|
||||||
@@ -4476,6 +4672,73 @@ function WAREHOUSE:onafterDefeated(From, Event, To)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On before "ChangeCountry" event. Checks whether a change of country is necessary by comparing the actual country to the the requested one.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param DCS#country.id Country which has captured the warehouse.
|
||||||
|
function WAREHOUSE:onbeforeChangeCountry(From, Event, To, Country)
|
||||||
|
|
||||||
|
local currentCountry=self:GetCountry()
|
||||||
|
|
||||||
|
-- Message.
|
||||||
|
local text=string.format("Warehouse %s: request to change country %d-->%d", self.alias, currentCountry, Country)
|
||||||
|
self:_DebugMessage(text, 10)
|
||||||
|
|
||||||
|
-- Check if current or requested coalition or country match.
|
||||||
|
if currentCountry~=Country then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after "ChangeCountry" event. Warehouse is respawned with the specified country. All queued requests are deleted and the owned airbase is reset if the coalition is changed by changing the
|
||||||
|
-- country.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param DCS#country.id Country which has captured the warehouse.
|
||||||
|
function WAREHOUSE:onafterChangeCountry(From, Event, To, Country)
|
||||||
|
|
||||||
|
local CoalitionOld=self:GetCoalition()
|
||||||
|
|
||||||
|
-- Respawn warehouse with new coalition/country.
|
||||||
|
self.warehouse:ReSpawn(Country)
|
||||||
|
|
||||||
|
local CoalitionNew=self:GetCoalition()
|
||||||
|
|
||||||
|
-- Delete all waiting requests because they are not valid any more.
|
||||||
|
self.queue=nil
|
||||||
|
self.queue={}
|
||||||
|
|
||||||
|
-- Airbase could have been captured before and already belongs to the new coalition.
|
||||||
|
local airbase=AIRBASE:FindByName(self.airbasename)
|
||||||
|
local airbasecoaltion=airbase:GetCoalition()
|
||||||
|
|
||||||
|
if CoalitionNew==airbasecoaltion then
|
||||||
|
-- Airbase already owned by the coalition that captured the warehouse. Airbase can be used by this warehouse.
|
||||||
|
self.airbase=airbase
|
||||||
|
else
|
||||||
|
-- Airbase is owned by other coalition. So this warehouse does not have an airbase unil it is captured.
|
||||||
|
self.airbase=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug smoke.
|
||||||
|
if self.Debug then
|
||||||
|
if CoalitionNew==coalition.side.RED then
|
||||||
|
self:GetCoordinate():SmokeRed()
|
||||||
|
elseif CoalitionNew==coalition.side.BLUE then
|
||||||
|
self:GetCoordinate():SmokeBlue()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- On after "Captured" event. Warehouse has been captured by another coalition.
|
--- On after "Captured" event. Warehouse has been captured by another coalition.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -4486,39 +4749,15 @@ end
|
|||||||
function WAREHOUSE:onafterCaptured(From, Event, To, Coalition, Country)
|
function WAREHOUSE:onafterCaptured(From, Event, To, Coalition, Country)
|
||||||
|
|
||||||
-- Message.
|
-- Message.
|
||||||
local text=string.format("Warehouse %s: We were captured by enemy coalition (ID=%d)!", self.alias, Coalition)
|
local text=string.format("Warehouse %s: We were captured by enemy coalition (side=%d)!", self.alias, Coalition)
|
||||||
self:_InfoMessage(text)
|
self:_InfoMessage(text)
|
||||||
|
|
||||||
-- Respawn warehouse with new coalition/country.
|
-- Change coalition and country of warehouse static.
|
||||||
self.warehouse:ReSpawn(Country)
|
self:ChangeCoaliton(Coalition, Country)
|
||||||
|
|
||||||
-- Delete all waiting requests because they are not valid any more
|
|
||||||
self.queue=nil
|
|
||||||
self.queue={}
|
|
||||||
|
|
||||||
-- Airbase could have been captured before and already belongs to the new coalition.
|
|
||||||
local airbase=AIRBASE:FindByName(self.airbasename)
|
|
||||||
local airbasecoaltion=airbase:GetCoalition()
|
|
||||||
|
|
||||||
if Coalition==airbasecoaltion then
|
|
||||||
-- Airbase already owned by the coalition that captured the warehouse. Airbase can be used by this warehouse.
|
|
||||||
self.airbase=airbase
|
|
||||||
else
|
|
||||||
-- Airbase is owned by other coalition. So this warehouse does not have an airbase unil it is captured.
|
|
||||||
self.airbase=nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Debug smoke.
|
|
||||||
if self.Debug then
|
|
||||||
if Coalition==coalition.side.RED then
|
|
||||||
self:GetCoordinate():SmokeRed()
|
|
||||||
elseif Coalition==coalition.side.BLUE then
|
|
||||||
self:GetCoordinate():SmokeBlue()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- On after "AirbaseCaptured" event. Airbase of warehouse has been captured by another coalition.
|
--- On after "AirbaseCaptured" event. Airbase of warehouse has been captured by another coalition.
|
||||||
-- @param #WAREHOUSE self
|
-- @param #WAREHOUSE self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -4612,6 +4851,222 @@ function WAREHOUSE:onafterDestroyed(From, Event, To)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after "Save" event. Warehouse assets are saved to file on disk.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string path Path where the file is saved. If nil, file is saved in the DCS root installtion directory.
|
||||||
|
-- @param #string filename (Optional) Name of the file containing the asset data.
|
||||||
|
function WAREHOUSE:onafterSave(From, Event, To, path, filename)
|
||||||
|
|
||||||
|
local function _savefile(filename, data)
|
||||||
|
local f = assert(io.open(filename, "wb"))
|
||||||
|
f:write(data)
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set file name.
|
||||||
|
filename=filename or string.format("WAREHOUSE-%d_%s.txt", self.uid, self.alias)
|
||||||
|
|
||||||
|
-- Set path.
|
||||||
|
if path~=nil then
|
||||||
|
filename=path.."\\"..filename
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Info
|
||||||
|
local text=string.format("Saving warehouse assets to file %s", filename)
|
||||||
|
MESSAGE:New(text,30):ToAllIf(self.Debug or self.Report)
|
||||||
|
self:I(self.wid..text)
|
||||||
|
|
||||||
|
local warehouseassets=""
|
||||||
|
warehouseassets=warehouseassets..string.format("coalition=%d\n", self:GetCoalition())
|
||||||
|
warehouseassets=warehouseassets..string.format("country=%d\n", self:GetCountry())
|
||||||
|
|
||||||
|
-- Loop over all assets in stock.
|
||||||
|
for _,_asset in pairs(self.stock) do
|
||||||
|
local asset=_asset -- #WAREHOUSE.Assetitem
|
||||||
|
|
||||||
|
-- Loop over asset parameters.
|
||||||
|
local assetstring=""
|
||||||
|
for key,value in pairs(asset) do
|
||||||
|
|
||||||
|
-- Only save keys which are needed to restore the asset.
|
||||||
|
if key=="templatename" or key=="attribute" or key=="cargobay" or key=="weight" or key=="loadradius" or key=="livery" or key=="skill" or key=="assignment" then
|
||||||
|
local name
|
||||||
|
if type(value)=="table" then
|
||||||
|
name=string.format("%s=%s;", key, value[1])
|
||||||
|
else
|
||||||
|
name=string.format("%s=%s;", key, value)
|
||||||
|
end
|
||||||
|
assetstring=assetstring..name
|
||||||
|
end
|
||||||
|
self:I(string.format("Loaded asset: %s", assetstring))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add asset string.
|
||||||
|
warehouseassets=warehouseassets..assetstring.."\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save file.
|
||||||
|
_savefile(filename, warehouseassets)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On before "Load" event. Checks if the file the warehouse data should be loaded from exists.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string path Path where the file is loaded from.
|
||||||
|
-- @param #string filename (Optional) Name of the file containing the asset data.
|
||||||
|
function WAREHOUSE:onbeforeLoad(From, Event, To, path, filename)
|
||||||
|
|
||||||
|
|
||||||
|
local function _fileexists(name)
|
||||||
|
local f=io.open(name,"r")
|
||||||
|
if f~=nil then
|
||||||
|
io.close(f)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set file name.
|
||||||
|
filename=filename or string.format("WAREHOUSE-%d_%s.txt", self.uid, self.alias)
|
||||||
|
|
||||||
|
-- Set path.
|
||||||
|
if path~=nil then
|
||||||
|
filename=path.."\\"..filename
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if file exists.
|
||||||
|
local exists=_fileexists(filename)
|
||||||
|
|
||||||
|
if exists then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
self:_ErrorMessage(string.format("ERROR: file %s does not exist! Cannot load assets.", filename), 60)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- On after "Load" event. Warehouse assets are loaded from file on disk.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string path Path where the file is loaded from.
|
||||||
|
-- @param #string filename (Optional) Name of the file containing the asset data.
|
||||||
|
function WAREHOUSE:onafterLoad(From, Event, To, path, filename)
|
||||||
|
|
||||||
|
local function _loadfile(filename)
|
||||||
|
local f = assert(io.open(filename, "rb"))
|
||||||
|
local data = f:read("*all")
|
||||||
|
f:close()
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set file name.
|
||||||
|
filename=filename or string.format("WAREHOUSE-%d_%s.txt", self.uid, self.alias)
|
||||||
|
|
||||||
|
-- Set path.
|
||||||
|
if path~=nil then
|
||||||
|
filename=path.."\\"..filename
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Info
|
||||||
|
local text=string.format("Loading warehouse assets from file %s", filename)
|
||||||
|
MESSAGE:New(text,30):ToAllIf(self.Debug or self.Report)
|
||||||
|
self:I(self.wid..text)
|
||||||
|
|
||||||
|
-- Load asset data from file.
|
||||||
|
local data=_loadfile(filename)
|
||||||
|
|
||||||
|
-- Split by line break.
|
||||||
|
local assetdata=UTILS.Split(data,"\n")
|
||||||
|
|
||||||
|
-- Coalition and coutrny.
|
||||||
|
local Coalition
|
||||||
|
local Country
|
||||||
|
|
||||||
|
-- Loop over asset lines.
|
||||||
|
local assets={}
|
||||||
|
for _,asset in pairs(assetdata) do
|
||||||
|
|
||||||
|
-- Parameters are separated by semi-colons
|
||||||
|
local descriptors=UTILS.Split(asset,";")
|
||||||
|
|
||||||
|
local asset={}
|
||||||
|
local isasset=false
|
||||||
|
for _,descriptor in pairs(descriptors) do
|
||||||
|
|
||||||
|
local keyval=UTILS.Split(descriptor,"=")
|
||||||
|
|
||||||
|
if #keyval==2 then
|
||||||
|
|
||||||
|
if keyval[1]=="coalition" then
|
||||||
|
-- Get coalition side.
|
||||||
|
Coalition=tonumber(keyval[2])
|
||||||
|
elseif keyval[1]=="country" then
|
||||||
|
-- Get country id.
|
||||||
|
Country=tonumber(keyval[2])
|
||||||
|
else
|
||||||
|
|
||||||
|
-- This is an asset.
|
||||||
|
isasset=true
|
||||||
|
|
||||||
|
local key=keyval[1]
|
||||||
|
local val=keyval[2]
|
||||||
|
|
||||||
|
--env.info(string.format("FF asset key=%s val=%s", key, val))
|
||||||
|
|
||||||
|
-- Livery or skill could be "nil".
|
||||||
|
if val=="nil" then
|
||||||
|
val=nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert string to number where necessary.
|
||||||
|
if key=="cargobay" or key=="weight" or key=="loadradius" then
|
||||||
|
asset[key]=tonumber(val)
|
||||||
|
else
|
||||||
|
asset[key]=val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add to table.
|
||||||
|
if isasset then
|
||||||
|
table.insert(assets, asset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Respawn warehouse with prev coalition if necessary.
|
||||||
|
if Country~=self:GetCountry() then
|
||||||
|
self:T(self.wid..string.format("Changing warehouse country %d-->%d on loading assets.", self:GetCountry(), Country))
|
||||||
|
self:ChangeCountry(Country)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _,_asset in pairs(assets) do
|
||||||
|
local asset=_asset --#WAREHOUSE.Assetitem
|
||||||
|
|
||||||
|
local group=GROUP:FindByName(asset.templatename)
|
||||||
|
if group then
|
||||||
|
self:AddAsset(group, 1, asset.attribute, asset.cargobay, asset.weight, asset.loadradius, asset.skill, asset.livery, asset.assignment)
|
||||||
|
else
|
||||||
|
self:E(string.format("ERROR: Group %s doest not exit. Cannot be loaded as asset.", tostring(asset.templatename)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Spawn functions
|
-- Spawn functions
|
||||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -5538,6 +5993,18 @@ function WAREHOUSE:_OnEventBaseCaptured(EventData)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Warehouse event handling function.
|
||||||
|
-- Handles the case when the mission is ended.
|
||||||
|
-- @param #WAREHOUSE self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData Event data.
|
||||||
|
function WAREHOUSE:_OnEventMissionEnd(EventData)
|
||||||
|
self:T3(self.wid..string.format("Warehouse %s captured event mission end!",self.alias))
|
||||||
|
|
||||||
|
if self.autosave then
|
||||||
|
self:Save(self.autosavepath, self.autosavefile)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Helper functions
|
-- Helper functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -7290,7 +7757,7 @@ end
|
|||||||
function WAREHOUSE:_ErrorMessage(text, duration)
|
function WAREHOUSE:_ErrorMessage(text, duration)
|
||||||
duration=duration or 20
|
duration=duration or 20
|
||||||
if duration>0 then
|
if duration>0 then
|
||||||
MESSAGE:New(text, duration):ToAllIf()
|
MESSAGE:New(text, duration):ToAll()
|
||||||
end
|
end
|
||||||
self:E(self.wid..text)
|
self:E(self.wid..text)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -687,9 +687,9 @@ function COMMANDCENTER:ReportMissionsPlayers( ReportGroup )
|
|||||||
|
|
||||||
Report:Add( "Players active in all missions." )
|
Report:Add( "Players active in all missions." )
|
||||||
|
|
||||||
for MissionID, Mission in pairs( self.Missions ) do
|
for MissionID, MissionData in pairs( self.Missions ) do
|
||||||
local Mission = Mission -- Tasking.Mission#MISSION
|
local Mission = MissionData -- Tasking.Mission#MISSION
|
||||||
Report:Add( " - " .. Mission:ReportPlayers() )
|
Report:Add( " - " .. Mission:ReportPlayersPerTask(ReportGroup) )
|
||||||
end
|
end
|
||||||
|
|
||||||
self:MessageToGroup( Report:Text(), ReportGroup )
|
self:MessageToGroup( Report:Text(), ReportGroup )
|
||||||
|
|||||||
@@ -657,5 +657,26 @@ function UTILS.Randomize(value, fac, lower, upper)
|
|||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Calculate the [dot product](https://en.wikipedia.org/wiki/Dot_product) of two vectors. The result is a number.
|
||||||
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
|
-- @return #number Scalar product of the two vectors a*b.
|
||||||
|
function UTILS.VecDot(a, b)
|
||||||
|
return a.x*b.x + a.y*b.y + a.z*b.z
|
||||||
|
end
|
||||||
|
|
||||||
|
--- 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.
|
||||||
|
-- @return #number Norm of the vector.
|
||||||
|
function UTILS.VecNorm(a)
|
||||||
|
return math.sqrt(UTILS.VecDot(a, a))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculate the [cross product](https://en.wikipedia.org/wiki/Cross_product) of two 3D vectors. The result is a 3D vector.
|
||||||
|
-- @param DCS#Vec3 a Vector in 3D with x, y, z components.
|
||||||
|
-- @param DCS#Vec3 b Vector in 3D with x, y, z components.
|
||||||
|
-- @return DCS#Vec3 Vector
|
||||||
|
function UTILS.VecCross(a, b)
|
||||||
|
return {x=a.y*b.z - a.z*b.y, y=a.z*b.x - a.x*b.z, z=a.x*b.y - a.y*b.x}
|
||||||
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ end
|
|||||||
--- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase.
|
--- Find a AIRBASE in the _DATABASE using the name of an existing DCS Airbase.
|
||||||
-- @param #AIRBASE self
|
-- @param #AIRBASE self
|
||||||
-- @param #string AirbaseName The Airbase Name.
|
-- @param #string AirbaseName The Airbase Name.
|
||||||
-- @return Wrapper.Airbase#AIRBASE self
|
-- @return #AIRBASE self
|
||||||
function AIRBASE:FindByName( AirbaseName )
|
function AIRBASE:FindByName( AirbaseName )
|
||||||
|
|
||||||
local AirbaseFound = _DATABASE:FindAirbase( AirbaseName )
|
local AirbaseFound = _DATABASE:FindAirbase( AirbaseName )
|
||||||
|
|||||||
@@ -1975,6 +1975,24 @@ do -- Route methods
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Make the controllable to push follow a given route.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #table Route A table of Route Points.
|
||||||
|
-- @param #number DelaySeconds (Optional) Wait for the specified seconds before executing the Route. Default is one second.
|
||||||
|
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||||
|
function CONTROLLABLE:RoutePush( Route, DelaySeconds )
|
||||||
|
self:F2( Route )
|
||||||
|
|
||||||
|
local DCSControllable = self:GetDCSObject()
|
||||||
|
if DCSControllable then
|
||||||
|
local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route.
|
||||||
|
self:PushTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1).
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
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
|
||||||
@@ -2118,7 +2136,7 @@ do -- Route methods
|
|||||||
local canroad=false
|
local canroad=false
|
||||||
|
|
||||||
-- Check if a valid path on road could be found.
|
-- Check if a valid path on road could be found.
|
||||||
if PathOnRoad then
|
if PathOnRoad and LengthDirect > 2000 then -- if the length of the movement is less than 1 km, drive directly.
|
||||||
-- Check whether the road is very long compared to direct path.
|
-- Check whether the road is very long compared to direct path.
|
||||||
if LongRoad and Shortcut then
|
if LongRoad and Shortcut then
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,80 @@ function POSITIONABLE:Destroy( GenerateEvent )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns a pos3 table of the objects current position and orientation in 3D space. X, Y, Z values are unit vectors defining the objects orientation.
|
||||||
|
-- Coordinates are dependent on the position of the maps origin.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return DCS#Position Table consisting of the point and orientation tables.
|
||||||
|
function POSITIONABLE:GetPosition()
|
||||||
|
self:F2( self.PositionableName )
|
||||||
|
|
||||||
|
local DCSPositionable = self:GetDCSObject()
|
||||||
|
|
||||||
|
if DCSPositionable then
|
||||||
|
local PositionablePosition = DCSPositionable:getPosition()
|
||||||
|
self:T3( PositionablePosition )
|
||||||
|
return PositionablePosition
|
||||||
|
end
|
||||||
|
|
||||||
|
BASE:E( { "Cannot GetPositionVec3", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a {@DCS#Vec3} table of the objects current orientation in 3D space. X, Y, Z values are unit vectors defining the objects orientation.
|
||||||
|
-- X is the orientation parallel to the movement of the object, Z perpendicular and Y vertical orientation.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return DCS#Vec3 X orientation, i.e. parallel to the direction of movement.
|
||||||
|
-- @return DCS#Vec3 Y orientation, i.e. vertical.
|
||||||
|
-- @return DCS#Vec3 Z orientation, i.e. perpendicular to the direction of movement.
|
||||||
|
function POSITIONABLE:GetOrientation()
|
||||||
|
local position=self:GetPosition()
|
||||||
|
if position then
|
||||||
|
return position.x, position.y, position.z
|
||||||
|
else
|
||||||
|
BASE:E( { "Cannot GetOrientation", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
return nil, nil, nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a {@DCS#Vec3} table of the objects current X orientation in 3D space, i.e. along the direction of movement.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return DCS#Vec3 X orientation, i.e. parallel to the direction of movement.
|
||||||
|
function POSITIONABLE:GetOrientationX()
|
||||||
|
local position=self:GetPosition()
|
||||||
|
if position then
|
||||||
|
return position.x
|
||||||
|
else
|
||||||
|
BASE:E( { "Cannot GetOrientationX", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a {@DCS#Vec3} table of the objects current Y orientation in 3D space, i.e. vertical orientation.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return DCS#Vec3 Y orientation, i.e. vertical.
|
||||||
|
function POSITIONABLE:GetOrientationY()
|
||||||
|
local position=self:GetPosition()
|
||||||
|
if position then
|
||||||
|
return position.y
|
||||||
|
else
|
||||||
|
BASE:E( { "Cannot GetOrientationY", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a {@DCS#Vec3} table of the objects current Z orientation in 3D space, i.e. perpendicular to direction of movement.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return DCS#Vec3 Z orientation, i.e. perpendicular to movement.
|
||||||
|
function POSITIONABLE:GetOrientationZ()
|
||||||
|
local position=self:GetPosition()
|
||||||
|
if position then
|
||||||
|
return position.z
|
||||||
|
else
|
||||||
|
BASE:E( { "Cannot GetOrientationZ", Positionable = self, Alive = self:IsAlive() } )
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission.
|
--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return DCS#Position The 3D position vectors of the POSITIONABLE.
|
-- @return DCS#Position The 3D position vectors of the POSITIONABLE.
|
||||||
@@ -582,6 +656,153 @@ function POSITIONABLE:GetVelocityMPS()
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the Angle of Attack of a positionable.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Angle of attack in degrees.
|
||||||
|
function POSITIONABLE:GetAoA()
|
||||||
|
|
||||||
|
-- Get position of the unit.
|
||||||
|
local unitpos = self:GetPosition()
|
||||||
|
|
||||||
|
if unitpos then
|
||||||
|
|
||||||
|
-- Get velocity vector of the unit.
|
||||||
|
local unitvel = self:GetVelocityVec3()
|
||||||
|
|
||||||
|
if unitvel and UTILS.VecNorm(unitvel)~=0 then
|
||||||
|
|
||||||
|
-- Get wind vector including turbulences.
|
||||||
|
local wind=self:GetCoordinate():GetWindWithTurbulenceVec3()
|
||||||
|
|
||||||
|
-- Include wind vector.
|
||||||
|
unitvel.x=unitvel.x-wind.x
|
||||||
|
unitvel.y=unitvel.y-wind.y
|
||||||
|
unitvel.z=unitvel.z-wind.z
|
||||||
|
|
||||||
|
-- Unit velocity transformed into aircraft axes directions.
|
||||||
|
local AxialVel = {}
|
||||||
|
|
||||||
|
-- Transform velocity components in direction of aircraft axes.
|
||||||
|
AxialVel.x = UTILS.VecDot(unitpos.x, unitvel)
|
||||||
|
AxialVel.y = UTILS.VecDot(unitpos.y, unitvel)
|
||||||
|
AxialVel.z = UTILS.VecDot(unitpos.z, unitvel)
|
||||||
|
|
||||||
|
-- AoA is angle between unitpos.x and the x and y velocities.
|
||||||
|
local AoA = math.acos(UTILS.VecDot({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/UTILS.VecNorm({x = AxialVel.x, y = AxialVel.y, z = 0}))
|
||||||
|
|
||||||
|
--Set correct direction:
|
||||||
|
if AxialVel.y > 0 then
|
||||||
|
AoA = -AoA
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return AoA value in degrees.
|
||||||
|
return math.deg(AoA)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the unit's climb or descent angle.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Climb or descent angle in degrees.
|
||||||
|
function POSITIONABLE:GetClimbAnge()
|
||||||
|
|
||||||
|
-- Get position of the unit.
|
||||||
|
local unitpos = self:GetPosition()
|
||||||
|
|
||||||
|
if unitpos then
|
||||||
|
|
||||||
|
-- Get velocity vector of the unit.
|
||||||
|
local unitvel = self:GetVelocityVec3()
|
||||||
|
|
||||||
|
if unitvel and UTILS.VecNorm(unitvel)~=0 then
|
||||||
|
|
||||||
|
return math.asin(unitvel.y/UTILS.VecNorm(unitvel))
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the pitch angle of a unit.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Pitch ange in degrees.
|
||||||
|
function POSITIONABLE:GetPitch()
|
||||||
|
|
||||||
|
-- Get position of the unit.
|
||||||
|
local unitpos = self:GetPosition()
|
||||||
|
|
||||||
|
if unitpos then
|
||||||
|
return math.deg(math.asin(unitpos.x.y))
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the roll angle of a unit.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Pitch ange in degrees.
|
||||||
|
function POSITIONABLE:GetRoll()
|
||||||
|
|
||||||
|
-- Get position of the unit.
|
||||||
|
local unitpos = self:GetPosition()
|
||||||
|
|
||||||
|
if unitpos then
|
||||||
|
|
||||||
|
--first, make a vector that is perpendicular to y and unitpos.x with cross product
|
||||||
|
local cp = UTILS.VecCross(unitpos.x, {x = 0, y = 1, z = 0})
|
||||||
|
|
||||||
|
--now, get dot product of of this cross product with unitpos.z
|
||||||
|
local dp = UTILS.VecDot(cp, unitpos.z)
|
||||||
|
|
||||||
|
--now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|)
|
||||||
|
local Roll = math.acos(dp/(UTILS.VecNorm(cp)*UTILS.VecNorm(unitpos.z)))
|
||||||
|
|
||||||
|
--now, have to get sign of roll.
|
||||||
|
-- by convention, making right roll positive
|
||||||
|
-- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative.
|
||||||
|
|
||||||
|
if unitpos.z.y > 0 then -- left roll, flip the sign of the roll
|
||||||
|
Roll = -Roll
|
||||||
|
end
|
||||||
|
|
||||||
|
return math.deg(Roll)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the yaw angle of a unit.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Yaw ange in degrees.
|
||||||
|
function POSITIONABLE:GetYaw()
|
||||||
|
|
||||||
|
local unitpos = self:GetPosition()
|
||||||
|
if unitpos then
|
||||||
|
-- get unit velocity
|
||||||
|
local unitvel = self:GetVelocityVec3()
|
||||||
|
|
||||||
|
if unitvel and UTILS.VecNorm(unitvel) ~= 0 then --must have non-zero velocity!
|
||||||
|
local AxialVel = {} --unit velocity transformed into aircraft axes directions
|
||||||
|
|
||||||
|
--transform velocity components in direction of aircraft axes.
|
||||||
|
AxialVel.x = UTILS.VecDot(unitpos.x, unitvel)
|
||||||
|
AxialVel.y = UTILS.VecDot(unitpos.y, unitvel)
|
||||||
|
AxialVel.z = UTILS.VecDot(unitpos.z, unitvel)
|
||||||
|
|
||||||
|
--Yaw is the angle between unitpos.x and the x and z velocities
|
||||||
|
--define right yaw as positive
|
||||||
|
local Yaw = math.acos(UTILS.VecDot({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/UTILS.VecNorm({x = AxialVel.x, y = 0, z = AxialVel.z}))
|
||||||
|
|
||||||
|
--now set correct direction:
|
||||||
|
if AxialVel.z > 0 then
|
||||||
|
Yaw = -Yaw
|
||||||
|
end
|
||||||
|
return Yaw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the message text with the callsign embedded (if there is one).
|
--- Returns the message text with the callsign embedded (if there is one).
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
|
|||||||
@@ -896,16 +896,35 @@ function UNIT:IsShip()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Returns true if the UNIT is in the air.
|
--- Returns true if the UNIT is in the air.
|
||||||
-- @param Wrapper.Positionable#UNIT self
|
-- @param #UNIT self
|
||||||
-- @return #boolean true if in the air.
|
-- @return #boolean true if in the air.
|
||||||
-- @return #nil The UNIT is not existing or alive.
|
-- @return #nil The UNIT is not existing or alive.
|
||||||
function UNIT:InAir()
|
function UNIT:InAir()
|
||||||
self:F2( self.UnitName )
|
self:F2( self.UnitName )
|
||||||
|
|
||||||
local DCSUnit = self:GetDCSObject()
|
local DCSUnit = self:GetDCSObject() --DCS#Unit
|
||||||
|
|
||||||
if DCSUnit then
|
if DCSUnit then
|
||||||
local UnitInAir = DCSUnit:inAir()
|
-- Implementation of workaround. The original code is below.
|
||||||
|
-- This to simulate the landing on buildings.
|
||||||
|
|
||||||
|
local UnitInAir = true
|
||||||
|
|
||||||
|
local UnitCategory = DCSUnit:getDesc().category
|
||||||
|
if UnitCategory == Unit.Category.HELICOPTER then
|
||||||
|
local VelocityVec3 = DCSUnit:getVelocity()
|
||||||
|
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
|
||||||
|
local Coordinate = DCSUnit:getPoint()
|
||||||
|
local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } )
|
||||||
|
local Height = Coordinate.y - LandHeight
|
||||||
|
if Velocity < 1 and Height <= 60 then
|
||||||
|
UnitInAir = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
UnitInAir = DCSUnit:inAir()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
self:T3( UnitInAir )
|
self:T3( UnitInAir )
|
||||||
return UnitInAir
|
return UnitInAir
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user