Compare commits

..

70 Commits

Author SHA1 Message Date
FlightControl
dd242bc1fe Finish 2.4.10 2018-11-09 07:44:37 +01:00
FlightControl
34d73af8bf Changed the default lase duration for designations to 120 seconds. A new method has been added to change the lase duration yourself. Use SetLaseDuratioin API! 2018-11-09 07:44:11 +01:00
FlightControl
604255bfba Finish 2.4.9 2018-11-09 06:46:23 +01:00
FlightControl
cfc0367c55 Fixing problems with A2A_GCI. 2018-11-09 06:45:34 +01:00
FlightControl
f4a89d62e3 Finish 2.4.8 2018-11-06 19:11:25 +01:00
FlightControl
a36e39205b Further fixes and optimizations for the A2A dispatcher plane optimization. 2018-11-06 18:50:42 +01:00
FlightControl
3789674666 First version of AI_A2G_DISPATCHER ...
- Created a new AI_AIR class. AI_A2A and AI_A2G inherit from AI_AIR.
- Created a new AI_A2G_DISPATCHER class.
- Created a new AI_A2G_ENGAGE class, that implements the SEAD, CAS and BAI actions.
- The AI_A2G_DISPATCHER implements now:
  * SEAD, CAS and BAI attacks from airbases.
  * AddDefenseCoordinate() to set a defense coordinate.
  * RemoveDefenseCoordinate() to remove a defense coordinate.
  * SetDefenseReactivenessHigh() for high reactiveness.
  * SetDefenseReactivenessMedium() for medium reactiveness.
  * SetDefenseReactivenessLow() for low reactiveness.
  * Overhead for ground attacks.
  * Grouping for ground attacks.
  * Evaluates task type based on enemy group composition.

- Tested AI_A2A_DISPATCHER for backward compatibility.
- Implemented spawning of airplanes in AI_A2A_DISPATCHER:
  * SetSquadronVisible() method to make the squadron visible at the airport.
2018-11-05 21:52:31 +01:00
FlightControl
a22774b278 Fixing takeoff bug in air for dispatchers. 2018-11-05 21:44:47 +01:00
FlightControl
81bb8dd65f Reworking a confusion with the takeoff in air spawning. 2018-11-05 21:41:52 +01:00
FlightControl
9d3796b605 Changes 2018-11-05 21:26:47 +01:00
FlightControl
3e3dfc83aa First Version of AI_A2G_DISPATCHER. There are lots of challenges here to overcome. One of the first one is the defense points. 2018-11-02 16:43:06 +01:00
Frank
e062db9411 Merge pull request #1050 from FlightControl-Master/FF/Develop
Several improvements and fixes.
2018-10-28 14:16:07 +01:00
Frank
023eae825d RCT 2018-10-28 13:16:32 +01:00
Frank
1a4baeafb6 Warehose v0.6.6
WAREHOUSE:
- Improved parking spot check for airbase ship.
AI_FORMATION:
- Added Stop option
CT:
- fixes
COORDINATE:
- Improved landing waypoint.
2018-10-28 13:15:38 +01:00
Frank
b754972490 Merge branch 'FF/Develop' of https://github.com/FlightControl-Master/MOOSE into FF/Develop 2018-10-26 18:55:41 +02:00
Frank
0c36e4e40d CT 2018-10-26 18:55:36 +02:00
funkyfranky
1f97495fdd CT,RAT,WH work 2018-10-26 16:04:02 +02:00
FlightControl
c164c0f9e3 Merge branch 'hotfix/2.4.8' into feature/Feature-AI-A2A-Dispatcher 2018-10-26 14:09:25 +02:00
FlightControl
f0b5ec1025 Fixed the out of fuel bug. 2018-10-26 12:08:48 +02:00
Frank
b72ea2d02c minor 2018-10-26 00:12:21 +02:00
Frank
238fcf1176 WAREHOUSE v0.6.5
* fixed bug for assignments
2018-10-24 23:13:56 +02:00
Frank
c354fecc6d Merge branch 'develop' into FF/Develop 2018-10-24 21:47:52 +02:00
Frank
4434d1da21 Fixes
AI_FORMATION:
* added stop possibility ad interval input
WAREHOUSE
* added autodefence assignment
UNIT:
* improved  InAir() check function
2018-10-24 21:32:07 +02:00
FlightControl
17ffc7cef9 Updates for visibility of squadrons before start. 2018-10-24 20:55:04 +02:00
Frank
006fd25e56 Merge pull request #1044 from cjbehm/bugfix/CONTROLLABLE-honor-GotPath
Honor the GotPath return value from COORDINATE
2018-10-24 15:20:18 +02:00
Chris
f2eafe0302 Honor the GotPath return value from COORDINATE
PathOnRoad is always defined, at least as an empty table.
Use the 3rd return value instead, which indicates whether
a road route was found
2018-10-24 00:17:26 -04:00
FlightControl
52069cc1d0 Respawning of existing visible resources at the airbases is working. 2018-10-24 00:18:02 +02:00
Frank
d9374f0389 Controllable
Added more general orbit task.
2018-10-23 23:35:25 +02:00
Frank
19520f9688 CT v0.1.0 2018-10-22 23:41:48 +02:00
FlightControl
1eda5af7df Visible before start, uncontrolled planes. 2018-10-22 07:06:24 +02:00
Frank
2ea8487e04 ARTY v1.0.7
Fixed bug when targets get removed because ARTY group is immobile and not declared as cargo.
CT fixes
2018-10-22 00:08:38 +02:00
FlightControl
b0885ada00 Fixing resuming task after refuelling. 2018-10-21 14:36:31 +02:00
FlightControl
1c6c0c4d81 Fixing resuming task after refuelling. 2018-10-21 14:36:05 +02:00
FlightControl
3011b0ac8e Merge branch 'develop' 2018-10-21 13:18:29 +02:00
FlightControl
e4334cccb3 Fixing back to the inclusion of inactive units. 2018-10-21 13:12:20 +02:00
Frank
645ca570a8 CT 0.0.9
many fixes
2018-10-20 12:20:35 +02:00
FlightControl
fd30da2f95 Merge branch 'develop' 2018-10-20 04:31:59 +02:00
FlightControl
b378ad2885 Fixing path calculation. Direct route when the length between the two coordinates is less than 2 km. 2018-10-20 04:26:45 +02:00
FlightControl
9c45031a33 Merge branch 'develop' 2018-10-19 17:01:11 +02:00
FlightControl
e4606b4d05 Fixing path calculation. Direct route when the length between the two coordinates is less than 1 km. 2018-10-19 17:00:43 +02:00
funkyfranky
07e690caf0 CT008 2018-10-19 15:09:26 +02:00
Frank
223de9d1aa Range 2018-10-18 22:51:51 +02:00
FlightControl
a22b9e925a Merge branch 'develop' 2018-10-18 20:25:35 +02:00
FlightControl
90e7688cea Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 20:25:21 +02:00
FlightControl
9ecd48f523 Merge branch 'develop' 2018-10-18 20:11:49 +02:00
FlightControl
ce9d1837a7 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 20:11:31 +02:00
FlightControl
bbf83eca3e Merge branch 'develop' 2018-10-18 18:24:56 +02:00
FlightControl
65c28d6628 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 18:24:25 +02:00
funkyfranky
7d7c521bce CT007 2018-10-18 16:50:08 +02:00
FlightControl
f0ac7818b3 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 07:27:50 +02:00
FlightControl
07d666b030 Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now. 2018-10-18 07:27:09 +02:00
Frank
baaee9f92e Merge branch 'develop' into FF/Develop 2018-10-17 22:10:04 +02:00
Frank
3a9be7a890 CTA 0.0.6 2018-10-17 22:07:11 +02:00
Frank
3c1547bd6c Merge pull request #1033 from FlightControl-Master/FF/Develop
Warehouse v0.6.4
2018-10-17 21:59:57 +02:00
Frank
92bf8b59e6 CTR 2018-10-17 21:54:44 +02:00
Frank
4b39312c2c CT 2018-10-17 21:20:30 +02:00
Frank
ea767650ae Merge branch 'develop' into FF/Develop 2018-10-17 21:20:19 +02:00
Frank
e0afd19a94 Warehouse v0.6.4
- Added possibility to auto save assets on mission end.
- Minor bug fixes.
2018-10-17 21:17:45 +02:00
FlightControl
767bb58ac9 Merge branch 'develop' 2018-10-17 19:23:47 +02:00
FlightControl
8a78308dbc Improvements on the pickup. Avoid a template as part of a CarrierSet to be considered as a valid carrier for pickup. And improved the timing of the loading. 2018-10-17 19:21:35 +02:00
funkyfranky
d2db1e56cc WH 2018-10-17 16:00:22 +02:00
Frank
5f8ebbaf6a CCT 2018-10-17 00:28:08 +02:00
Frank
52758b6900 Merge pull request #1031 from FlightControl-Master/FF/Develop
Warehouse v0.6.3
2018-10-17 00:22:19 +02:00
Frank
3bb2405563 Merge branch 'develop' into FF/Develop 2018-10-17 00:17:44 +02:00
Frank
c6403325f5 Warehouse v0.6.3
Persistance of assets.
2018-10-17 00:17:25 +02:00
funkyfranky
e17b5356dd WH 2018-10-16 16:32:35 +02:00
Frank
d87cb41b75 Warehouse v0.6.2
added first version of save/load assets

PseudoATC
fixed bearing info
other bugs reported!
2018-10-15 23:50:40 +02:00
funkyfranky
40154788d6 WH, CT WIP 2018-10-15 16:19:43 +02:00
FlightControl
a8f42d61fa APC defense ... optimized the unloading of infantry when enemies are nearby. Now the infantry is reloading into the APCs when the enemies are eliminated. 2018-10-15 07:20:46 +02:00
Frank
b923f66c56 CT v0.0.6 2018-10-14 22:27:30 +02:00
16 changed files with 1328 additions and 583 deletions

View File

@@ -438,13 +438,14 @@ function AI_A2A:onafterStatus()
RTB = false RTB = false
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
@@ -503,8 +507,11 @@ function AI_A2A:onafterStatus()
if RTB == true then if RTB == true then
self:__RTB( 0.5 ) self:__RTB( 0.5 )
end end
if not self:Is("Home") then
self:__Status( 10 )
end
self:__Status( 10 )
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

View File

@@ -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

View File

@@ -1013,12 +1013,48 @@ do -- AI_A2A_DISPATCHER
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, AI_A2A_DISPATCHER ).onafterStart( self, From, Event, To )
-- Spawn the resources.
for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons ) do
DefenderSquadron.Resource = {}
if DefenderSquadron.ResourceCount then
for Resource = 1, DefenderSquadron.ResourceCount do
self:ParkDefender( DefenderSquadron )
end
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 #AI_A2A_DISPATCHER self
-- @param Core.Event#EVENTDATA EventData -- @param Core.Event#EVENTDATA EventData
function AI_A2A_DISPATCHER:OnEventBaseCaptured( EventData ) function AI_A2A_DISPATCHER:OnEventBaseCaptured( EventData )
@@ -1030,7 +1066,7 @@ do -- AI_A2A_DISPATCHER
-- Now search for all squadrons located at the airbase, and sanatize them. -- Now search for all squadrons located at the airbase, and sanatize them.
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
if Squadron.AirbaseName == AirbaseName then if Squadron.AirbaseName == AirbaseName then
Squadron.Resources = -999 -- The base has been captured, and the resources are eliminated. No more spawning. Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
Squadron.Captured = true Squadron.Captured = true
self:I( "Squadron " .. SquadronName .. " captured." ) self:I( "Squadron " .. SquadronName .. " captured." )
end end
@@ -1059,6 +1095,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
@@ -1085,6 +1122,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
@@ -1474,7 +1512,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.
@@ -1497,13 +1535,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 {}
@@ -1528,11 +1566,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. 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
@@ -1551,6 +1589,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.
@@ -1699,7 +1785,7 @@ do -- AI_A2A_DISPATCHER
if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured. if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured.
if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 0 ) then -- And, if there are sufficient resources. 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
@@ -1732,7 +1818,7 @@ do -- AI_A2A_DISPATCHER
if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured. if DefenderSquadron.Captured == false then -- We can only spawn new CAP if the base has not been captured.
if ( not DefenderSquadron.Resources ) or ( DefenderSquadron.Resources and DefenderSquadron.Resources > 0 ) then -- And, if there are sufficient resources. 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
@@ -2490,21 +2576,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 )
@@ -2646,7 +2732,80 @@ do -- AI_A2A_DISPATCHER
return Friendlies return Friendlies
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
@@ -2663,15 +2822,9 @@ do -- AI_A2A_DISPATCHER
local Cap = DefenderSquadron.Cap local Cap = DefenderSquadron.Cap
if Cap then if Cap then
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Core.Spawn#SPAWN
local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping
Spawn:InitGrouping( DefenderGrouping )
local TakeoffMethod = self:GetSquadronTakeoff( SquadronName ) local DefenderCAP, DefenderGrouping = self:ResourceActivate( DefenderSquadron )
local DefenderCAP = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude )
self:AddDefenderToSquadron( DefenderSquadron, DefenderCAP, DefenderGrouping )
if DefenderCAP then if DefenderCAP then
local Fsm = AI_A2A_CAP:New( DefenderCAP, Cap.Zone, Cap.FloorAltitude, Cap.CeilingAltitude, Cap.PatrolMinSpeed, Cap.PatrolMaxSpeed, Cap.EngageMinSpeed, Cap.EngageMaxSpeed, Cap.AltType ) local Fsm = AI_A2A_CAP:New( DefenderCAP, Cap.Zone, Cap.FloorAltitude, Cap.CeilingAltitude, Cap.PatrolMinSpeed, Cap.PatrolMaxSpeed, Cap.EngageMinSpeed, Cap.EngageMaxSpeed, Cap.AltType )
@@ -2686,7 +2839,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
@@ -2720,9 +2873,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
@@ -2828,31 +2981,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
@@ -2919,6 +3060,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
@@ -3500,7 +3642,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
-- --
@@ -3575,7 +3717,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 )
@@ -3629,7 +3771,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
@@ -3706,7 +3848,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
-- --
@@ -3790,9 +3932,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 ) ) )

View File

@@ -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

View File

@@ -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
@@ -279,8 +280,81 @@ function AI_CARGO:onbeforeLoad( Carrier, From, Event, To, PickupZone )
end end
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
if not Loaded == true then if not Loaded == true then
@@ -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
@@ -359,7 +433,7 @@ function AI_CARGO:onafterPickedUp( Carrier, From, Event, To, PickupZone )
Carrier:RouteResume() Carrier:RouteResume()
local HasCargo = false local HasCargo = false
if Carrier and Carrier :IsAlive() then if Carrier and Carrier:IsAlive() then
for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do for Cargo, CarrierUnit in pairs( self.Carrier_Cargo ) do
HasCargo = true HasCargo = true
break break
@@ -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
Cargo:SetDeployed( true ) self:__Unboard( UnboardDelay, Cargo, CarrierUnit, DeployZone, Defend )
self:__Unboard( UnboardDelay, Cargo, CarrierUnit, DeployZone ) if not Defend == true then
Cargo:SetDeployed( true )
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

View File

@@ -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"})
@@ -132,18 +132,20 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
end end
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,34 +278,36 @@ 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()
self.Zone:Scan( { Object.Category.UNIT } ) if self:Is( "Unloaded" ) or self:Is( "Loaded" ) then
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then self.Zone:Scan( { Object.Category.UNIT } )
if self:Is( "Unloaded" ) or self:Is( "Following" ) then if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
-- There are no enemies within combat radius. Load the CargoCarrier.
self:Load()
end
else
if self:Is( "Loaded" ) then
-- There are enemies within combat radius. Unload the CargoCarrier.
self:__Unload( 1 )
else
if self:Is( "Unloaded" ) then if self:Is( "Unloaded" ) then
self:Follow() -- There are no enemies within combat radius. Reload the CargoCarrier.
self:Reload()
end end
self:F( "I am here" .. self:GetCurrentState() ) else
if self:Is( "Following" ) then if self:Is( "Loaded" ) then
for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do -- There are enemies within combat radius. Unload the CargoCarrier.
local Cargo = Cargo -- Cargo.Cargo#CARGO self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy!
local APCUnit = APCUnit -- Wrapper.Unit#UNIT else
if Cargo:IsAlive() then if self:Is( "Unloaded" ) then
if not Cargo:IsNear( APCUnit, 40 ) then --self:Follow()
APCUnit:RouteStop() end
self.CarrierStopped = true self:F( "I am here" .. self:GetCurrentState() )
else if self:Is( "Following" ) then
if self.CarrierStopped then for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do
if Cargo:IsNear( APCUnit, 25 ) then local Cargo = Cargo -- Cargo.Cargo#CARGO
APCUnit:RouteResume() local APCUnit = APCUnit -- Wrapper.Unit#UNIT
self.CarrierStopped = nil if Cargo:IsAlive() then
if not Cargo:IsNear( APCUnit, 40 ) then
APCUnit:RouteStop()
self.CarrierStopped = true
else
if self.CarrierStopped then
if Cargo:IsNear( APCUnit, 25 ) then
APCUnit:RouteResume()
self.CarrierStopped = nil
end
end end
end end
end end
@@ -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

View File

@@ -894,275 +894,280 @@ 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
local AI_Cargo = self.AI_Cargo[Carrier] if Carrier:IsAlive() ~= nil then
if not AI_Cargo then local AI_Cargo = self.AI_Cargo[Carrier]
if not AI_Cargo then
-- ok, so this Carrier does not have yet an AI_CARGO handling object...
-- let's create one and also declare the Loaded and UnLoaded handlers.
self.AI_Cargo[Carrier] = self:AICargo( Carrier, self.SetCargo, self.CombatRadius )
AI_Cargo = self.AI_Cargo[Carrier]
--- Pickup event handler OnAfter for AI_CARGO_DISPATCHER. -- ok, so this Carrier does not have yet an AI_CARGO handling object...
-- Use this event handler to tailor the event when a CarrierGroup is routed towards a new pickup Coordinate and a specified Speed. -- let's create one and also declare the Loaded and UnLoaded handlers.
-- You can use this event handler to post messages to players, or provide status updates etc. self.AI_Cargo[Carrier] = self:AICargo( Carrier, self.SetCargo, self.CombatRadius )
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterPickup AI_Cargo = self.AI_Cargo[Carrier]
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered. --- Pickup event handler OnAfter for AI_CARGO_DISPATCHER.
-- @param #string Event A string that contains the "*event name*" when the event was triggered. -- Use this event handler to tailor the event when a CarrierGroup is routed towards a new pickup Coordinate and a specified Speed.
-- @param #string To A string that contains the "*to state name*" when the event was triggered. -- You can use this event handler to post messages to players, or provide status updates etc.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits. -- @function [parent=#AI_CARGO_DISPATCHER] OnAfterPickup
-- @param Core.Point#COORDINATE Coordinate The coordinate of the pickup location. -- @param #AI_CARGO_DISPATCHER self
-- @param #number Speed The velocity in meters per second on which the CarrierGroup is routed towards the pickup Coordinate. -- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #number Height Height in meters to move to the pickup coordinate. -- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone. -- @param #string To A string that contains the "*to state name*" when the event was triggered.
function AI_Cargo.OnAfterPickup( AI_Cargo, CarrierGroup, From, Event, To, Coordinate, Speed, Height, PickupZone ) -- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
self:Pickup( CarrierGroup, Coordinate, Speed, Height, PickupZone ) -- @param Core.Point#COORDINATE Coordinate The coordinate of the pickup location.
-- @param #number Speed The velocity in meters per second on which the CarrierGroup is routed towards the pickup Coordinate.
-- @param #number Height Height in meters to move to the pickup coordinate.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone.
function AI_Cargo.OnAfterPickup( AI_Cargo, CarrierGroup, From, Event, To, Coordinate, Speed, Height, PickupZone )
self:Pickup( CarrierGroup, Coordinate, Speed, Height, PickupZone )
end
--- Load event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierGroup has initiated the loading or boarding of cargo within reporting or near range.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterLoad
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone.
function AI_Cargo.OnAfterLoad( AI_Cargo, CarrierGroup, From, Event, To, PickupZone )
self:Load( CarrierGroup, PickupZone )
end
--- Loading event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup is in the process of loading or boarding of a cargo object.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- Note that this event is triggered repeatedly until all cargo (units) have been boarded into the carrier.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterLoading
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Cargo.Cargo#CARGO Cargo The cargo object.
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo loading operation.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone.
function AI_Cargo.OnAfterBoard( AI_Cargo, CarrierGroup, From, Event, To, Cargo, CarrierUnit, PickupZone )
self:Loading( CarrierGroup, Cargo, CarrierUnit, PickupZone )
end
--- Loaded event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup has loaded a cargo object.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- Note that if more cargo objects were loading or boarding into the CarrierUnit, then this event can be triggered multiple times for each different Cargo/CarrierUnit.
-- A CarrierUnit can be part of the larger CarrierGroup.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterLoaded
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Cargo.Cargo#CARGO Cargo The cargo object.
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo loading operation.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone.
function AI_Cargo.OnAfterLoaded( AI_Cargo, CarrierGroup, From, Event, To, Cargo, CarrierUnit, PickupZone )
self:Loaded( CarrierGroup, Cargo, CarrierUnit, PickupZone )
end
--- PickedUp event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a carrier has picked up all cargo objects into the CarrierGroup.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterPickedUp
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone.
function AI_Cargo.OnAfterPickedUp( AI_Cargo, CarrierGroup, From, Event, To, PickupZone )
self:PickedUp( CarrierGroup, PickupZone )
self:Transport( CarrierGroup )
end
--- Deploy event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierGroup is routed to a deploy coordinate, to Unload all cargo objects in each CarrierUnit.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterDeploy
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Core.Point#COORDINATE Coordinate The deploy coordinate.
-- @param #number Speed The velocity in meters per second on which the CarrierGroup is routed towards the deploy Coordinate.
-- @param #number Height Height in meters to move to the deploy coordinate.
-- @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.OnAfterDeploy( AI_Cargo, CarrierGroup, From, Event, To, Coordinate, Speed, Height, DeployZone )
self:Deploy( CarrierGroup, Coordinate, Speed, Height, DeployZone )
end
--- Unload event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierGroup has initiated the unloading or unboarding of cargo.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterUnload
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @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( AI_Cargo, Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
self:Unloading( Carrier, Cargo, CarrierUnit, DeployZone )
end
--- UnLoading event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup is in the process of unloading or unboarding of a cargo object.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- Note that this event is triggered repeatedly until all cargo (units) have been unboarded from the CarrierUnit.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterUnloading
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Cargo.Cargo#CARGO Cargo The cargo object.
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo unloading operation.
-- @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( AI_Cargo, CarrierGroup, From, Event, To, Cargo, CarrierUnit, DeployZone )
self:Unloading( CarrierGroup, Cargo, CarrierUnit, DeployZone )
end
--- Unloaded event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup has unloaded a cargo object.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- Note that if more cargo objects were unloading or unboarding from the CarrierUnit, then this event can be triggered multiple times for each different Cargo/CarrierUnit.
-- A CarrierUnit can be part of the larger CarrierGroup.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterUnloaded
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Cargo.Cargo#CARGO Cargo The cargo object.
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo unloading operation.
-- @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( AI_Cargo, Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
self:Unloaded( Carrier, Cargo, CarrierUnit, DeployZone )
end
--- Deployed event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a carrier has deployed all cargo objects from the CarrierGroup.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterDeployed
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @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( AI_Cargo, Carrier, From, Event, To, DeployZone )
self:Deployed( Carrier, DeployZone )
end
--- Home event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierGroup is returning to the HomeZone, after it has deployed all cargo objects from the CarrierGroup.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- If there is no HomeZone is specified, the CarrierGroup will stay at the current location after having deployed all cargo.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterHome
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Core.Point#COORDINATE Coordinate The home coordinate the Carrier will arrive and stop it's activities.
-- @param #number Speed The velocity in meters per second on which the CarrierGroup is routed towards the home Coordinate.
-- @param #number Height Height in meters to move to the home coordinate.
-- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_Cargo.OnAfterHome( AI_Cargo, Carrier, From, Event, To, Coordinate, Speed, Height, HomeZone )
self:Home( Carrier, Coordinate, Speed, Height, HomeZone )
end
end end
--- Load event handler OnAfter for AI_CARGO_DISPATCHER. -- The Pickup sequence ...
-- Use this event handler to tailor the event when a CarrierGroup has initiated the loading or boarding of cargo within reporting or near range. -- Check if this Carrier need to go and Pickup something...
-- You can use this event handler to post messages to players, or provide status updates etc. -- So, if the cargo bay is not full yet with cargo to be loaded ...
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterLoad self:I( { Carrier = CarrierGroupName, IsRelocating = AI_Cargo:IsRelocating(), IsTransporting = AI_Cargo:IsTransporting() } )
-- @param #AI_CARGO_DISPATCHER self if AI_Cargo:IsRelocating() == false and AI_Cargo:IsTransporting() == false then
-- @param #string From A string that contains the "*from state name*" when the event was triggered. -- ok, so there is a free Carrier
-- @param #string Event A string that contains the "*event name*" when the event was triggered. -- now find the first cargo that is Unloaded
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits. local PickupCargo = nil
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone. local PickupZone = nil
function AI_Cargo.OnAfterLoad( AI_Cargo, CarrierGroup, From, Event, To, PickupZone ) self.SetCargo:Flush()
self:Load( CarrierGroup, PickupZone ) for CargoName, Cargo in UTILS.spairs( self.SetCargo:GetSet(), function( t, a, b ) return t[a]:GetWeight() < t[b]:GetWeight() end ) do
end local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Carrier] ~= nil } )
--- Loading event handler OnAfter for AI_CARGO_DISPATCHER. if Cargo:IsUnLoaded() == true and Cargo:IsDeployed() == false then
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup is in the process of loading or boarding of a cargo object. local CargoCoordinate = Cargo:GetCoordinate()
-- You can use this event handler to post messages to players, or provide status updates etc. local CoordinateFree = true
-- Note that this event is triggered repeatedly until all cargo (units) have been boarded into the carrier. --self.PickupZoneSet:Flush()
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterLoading --PickupZone = self.PickupZoneSet:GetRandomZone()
-- @param #AI_CARGO_DISPATCHER self PickupZone = self.PickupZoneSet and self.PickupZoneSet:IsCoordinateInZone( CargoCoordinate )
-- @param #string From A string that contains the "*from state name*" when the event was triggered. if not self.PickupZoneSet or PickupZone then
-- @param #string Event A string that contains the "*event name*" when the event was triggered. for CarrierPickup, Coordinate in pairs( self.PickupCargo ) do
-- @param #string To A string that contains the "*to state name*" when the event was triggered. if CarrierPickup:IsAlive() == true then
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits. if CargoCoordinate:Get2DDistance( Coordinate ) <= 25 then
-- @param Cargo.Cargo#CARGO Cargo The cargo object. self:F( { "Coordinate not free for ", Cargo = Cargo:GetName(), Carrier:GetName(), PickupCargo = self.PickupCargo[Carrier] ~= nil } )
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo loading operation. CoordinateFree = false
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone. break
end
function AI_Cargo.OnAfterBoard( AI_Cargo, CarrierGroup, From, Event, To, Cargo, CarrierUnit, PickupZone ) else
self:Loading( CarrierGroup, Cargo, CarrierUnit, PickupZone ) self.PickupCargo[CarrierPickup] = nil
end end
end
--- Loaded event handler OnAfter for AI_CARGO_DISPATCHER. if CoordinateFree == true then
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup has loaded a cargo object. -- Check if this cargo can be picked-up by at least one carrier unit of AI_Cargo.
-- You can use this event handler to post messages to players, or provide status updates etc. local LargestLoadCapacity = 0
-- Note that if more cargo objects were loading or boarding into the CarrierUnit, then this event can be triggered multiple times for each different Cargo/CarrierUnit. for _, Carrier in pairs( Carrier:GetUnits() ) do
-- A CarrierUnit can be part of the larger CarrierGroup. local LoadCapacity = Carrier:GetCargoBayFreeWeight()
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterLoaded if LargestLoadCapacity < LoadCapacity then
-- @param #AI_CARGO_DISPATCHER self LargestLoadCapacity = LoadCapacity
-- @param #string From A string that contains the "*from state name*" when the event was triggered. end
-- @param #string Event A string that contains the "*event name*" when the event was triggered. end
-- @param #string To A string that contains the "*to state name*" when the event was triggered. -- So if there is a carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits. -- Otherwise break and go to the next carrier.
-- @param Cargo.Cargo#CARGO Cargo The cargo object. -- This will skip cargo which is too large to be able to be loaded by carriers
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo loading operation. -- and will secure an efficient dispatching scheme.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone. if LargestLoadCapacity >= Cargo:GetWeight() then
self.PickupCargo[Carrier] = CargoCoordinate
function AI_Cargo.OnAfterLoaded( AI_Cargo, CarrierGroup, From, Event, To, Cargo, CarrierUnit, PickupZone ) PickupCargo = Cargo
self:Loaded( CarrierGroup, Cargo, CarrierUnit, PickupZone )
end
--- PickedUp event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a carrier has picked up all cargo objects into the CarrierGroup.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterPickedUp
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Core.Zone#ZONE_AIRBASE PickupZone (optional) The zone from where the cargo is picked up. Note that the zone is optional and may not be provided, but for AI_CARGO_DISPATCHER_AIRBASE there will always be a PickupZone, as the pickup location is an airbase zone.
function AI_Cargo.OnAfterPickedUp( AI_Cargo, CarrierGroup, From, Event, To, PickupZone )
self:PickedUp( CarrierGroup, PickupZone )
self:Transport( CarrierGroup )
end
--- Deploy event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierGroup is routed to a deploy coordinate, to Unload all cargo objects in each CarrierUnit.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterDeploy
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Core.Point#COORDINATE Coordinate The deploy coordinate.
-- @param #number Speed The velocity in meters per second on which the CarrierGroup is routed towards the deploy Coordinate.
-- @param #number Height Height in meters to move to the deploy coordinate.
-- @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.OnAfterDeploy( AI_Cargo, CarrierGroup, From, Event, To, Coordinate, Speed, Height, DeployZone )
self:Deploy( CarrierGroup, Coordinate, Speed, Height, DeployZone )
end
--- Unload event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierGroup has initiated the unloading or unboarding of cargo.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterUnload
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @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( AI_Cargo, Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
self:Unloading( Carrier, Cargo, CarrierUnit, DeployZone )
end
--- UnLoading event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup is in the process of unloading or unboarding of a cargo object.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- Note that this event is triggered repeatedly until all cargo (units) have been unboarded from the CarrierUnit.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterUnloading
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Cargo.Cargo#CARGO Cargo The cargo object.
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo unloading operation.
-- @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( AI_Cargo, CarrierGroup, From, Event, To, Cargo, CarrierUnit, DeployZone )
self:Unloading( CarrierGroup, Cargo, CarrierUnit, DeployZone )
end
--- Unloaded event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierUnit of a CarrierGroup has unloaded a cargo object.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- Note that if more cargo objects were unloading or unboarding from the CarrierUnit, then this event can be triggered multiple times for each different Cargo/CarrierUnit.
-- A CarrierUnit can be part of the larger CarrierGroup.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterUnloaded
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Cargo.Cargo#CARGO Cargo The cargo object.
-- @param Wrapper.Unit#UNIT CarrierUnit The carrier unit that is executing the cargo unloading operation.
-- @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( AI_Cargo, Carrier, From, Event, To, Cargo, CarrierUnit, DeployZone )
self:Unloaded( Carrier, Cargo, CarrierUnit, DeployZone )
end
--- Deployed event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a carrier has deployed all cargo objects from the CarrierGroup.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterDeployed
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @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( AI_Cargo, Carrier, From, Event, To, DeployZone )
self:Deployed( Carrier, DeployZone )
end
--- Home event handler OnAfter for AI_CARGO_DISPATCHER.
-- Use this event handler to tailor the event when a CarrierGroup is returning to the HomeZone, after it has deployed all cargo objects from the CarrierGroup.
-- You can use this event handler to post messages to players, or provide status updates etc.
-- If there is no HomeZone is specified, the CarrierGroup will stay at the current location after having deployed all cargo.
-- @function [parent=#AI_CARGO_DISPATCHER] OnAfterHome
-- @param #AI_CARGO_DISPATCHER self
-- @param #string From A string that contains the "*from state name*" when the event was triggered.
-- @param #string Event A string that contains the "*event name*" when the event was triggered.
-- @param #string To A string that contains the "*to state name*" when the event was triggered.
-- @param Wrapper.Group#GROUP CarrierGroup The group object that contains the CarrierUnits.
-- @param Core.Point#COORDINATE Coordinate The home coordinate the Carrier will arrive and stop it's activities.
-- @param #number Speed The velocity in meters per second on which the CarrierGroup is routed towards the home Coordinate.
-- @param #number Height Height in meters to move to the home coordinate.
-- @param Core.Zone#ZONE HomeZone The zone wherein the carrier will return when all cargo has been transported. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
function AI_Cargo.OnAfterHome( AI_Cargo, Carrier, From, Event, To, Coordinate, Speed, Height, HomeZone )
self:Home( Carrier, Coordinate, Speed, Height, HomeZone )
end
end
-- The Pickup sequence ...
-- Check if this Carrier need to go and Pickup something...
-- So, if the cargo bay is not full yet with cargo to be loaded ...
self:I( { Carrier = CarrierGroupName, IsRelocating = AI_Cargo:IsRelocating(), IsTransporting = AI_Cargo:IsTransporting() } )
if AI_Cargo:IsRelocating() == false and AI_Cargo:IsTransporting() == false then
-- ok, so there is a free Carrier
-- now find the first cargo that is Unloaded
local PickupCargo = nil
local PickupZone = nil
--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
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Carrier] ~= nil } )
if Cargo:IsUnLoaded() == true and Cargo:IsDeployed() == false then
local CargoCoordinate = Cargo:GetCoordinate()
local CoordinateFree = true
--self.PickupZoneSet:Flush()
--PickupZone = self.PickupZoneSet:GetRandomZone()
PickupZone = self.PickupZoneSet and self.PickupZoneSet:IsCoordinateInZone( CargoCoordinate )
if not self.PickupZoneSet or PickupZone then
for CarrierPickup, Coordinate in pairs( self.PickupCargo ) do
if CarrierPickup:IsAlive() == true then
if CargoCoordinate:Get2DDistance( Coordinate ) <= 25 then
self:F( { "Coordinate not free for ", Cargo = Cargo:GetName(), Carrier:GetName(), PickupCargo = self.PickupCargo[Carrier] ~= nil } )
CoordinateFree = false
break break
end end
else
self.PickupCargo[CarrierPickup] = nil
end
end
if CoordinateFree == true then
-- Check if this cargo can be picked-up by at least one carrier unit of AI_Cargo.
local LargestLoadCapacity = 0
for _, Carrier in pairs( Carrier:GetUnits() ) do
local LoadCapacity = Carrier:GetCargoBayFreeWeight()
if LargestLoadCapacity < LoadCapacity then
LargestLoadCapacity = LoadCapacity
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.
-- Otherwise break and go to the next carrier.
-- This will skip cargo which is too large to be able to be loaded by carriers
-- and will secure an efficient dispatching scheme.
if LargestLoadCapacity >= Cargo:GetWeight() then
self.PickupCargo[Carrier] = CargoCoordinate
PickupCargo = Cargo
break
end end
end end
end end
end end
end
if PickupCargo then
if PickupCargo then self.CarrierHome[Carrier] = nil
self.CarrierHome[Carrier] = nil local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius )
local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius ) AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ), math.random( self.PickupMinHeight, self.PickupMaxHeight ), PickupZone )
AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ), math.random( self.PickupMinHeight, self.PickupMaxHeight ), PickupZone ) break
break else
else if self.HomeZone then
if self.HomeZone then if not self.CarrierHome[Carrier] then
if not self.CarrierHome[Carrier] then self.CarrierHome[Carrier] = true
self.CarrierHome[Carrier] = true AI_Cargo:Home( self.HomeZone:GetRandomPointVec2(), math.random( self.PickupMinSpeed, self.PickupMaxSpeed ), math.random( self.PickupMinHeight, self.PickupMaxHeight ), self.HomeZone )
AI_Cargo:Home( self.HomeZone:GetRandomPointVec2(), math.random( self.PickupMinSpeed, self.PickupMaxSpeed ), math.random( self.PickupMinHeight, self.PickupMaxHeight ), self.HomeZone ) end
end end
end end
end end

View File

@@ -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
self.CargoSet:ForEach(
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 function( Cargo, ... )
self.CargoSet:ForEach( self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
function( Cargo, ... ) local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP
Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) CargoGroup:OptionAlarmStateGreen()
end, ... Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
) end, ...
)
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
end self:__Boarding( -1, CargoCarrier, NearRadius, ... )
end end
@@ -323,13 +323,15 @@ 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
Cargo:Load( CargoCarrier ) if not Cargo:IsDestroyed() then
Cargo:Load( CargoCarrier )
end
end end
end end
@@ -360,7 +362,7 @@ do -- CARGO_GROUP
--self:T( { Cargo:GetName(), Cargo.current } ) --self:T( { Cargo:GetName(), Cargo.current } )
if not Cargo:is( "Loaded" ) if not Cargo:is( "Loaded" )
and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function.
Boarded = false Boarded = false
end end
@@ -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
) )

View File

@@ -231,48 +231,49 @@ 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()})
-- Only move the group to the carrier when the cargo is not in the air -- A cargo unit can only be boarded if it is not dead
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then -- Only move the group to the carrier when the cargo is not in the air
-- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
-- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis. if not self.CargoInAir then
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5 -- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then -- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis.
self:Load( CargoCarrier, NearRadius, ... ) local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5
else if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then
self:Load( CargoCarrier, NearRadius, ... ) self:Load( CargoCarrier, NearRadius, ... )
else else
if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then
self:Load( CargoCarrier, NearRadius, ... )
else
local Speed = 90
local Angle = 180
local Distance = 0
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
-- Set the CargoObject to state Green to ensure it is boarding!
self.CargoObject:OptionAlarmStateGreen()
local Points = {}
local Speed = 90 local PointStartVec2 = self.CargoObject:GetPointVec2()
local Angle = 180
local Distance = 0
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
-- Set the CargoObject to state Green to ensure it is boarding! self:__Boarding( -5, CargoCarrier, NearRadius, ... )
self.CargoObject:OptionAlarmStateGreen() self.RunCount = 0
end
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
self:__Boarding( -5, CargoCarrier, NearRadius, ... )
self.RunCount = 0
end end
end end
end
end end
@@ -286,50 +287,53 @@ 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
if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 1
else else
self:__Boarding( -2, CargoCarrier, NearRadius, ... ) if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
self.RunCount = self.RunCount + 2 self:__Boarding( -1, CargoCarrier, NearRadius, ... )
end self.RunCount = self.RunCount + 1
if self.RunCount >= 40 then else
self.RunCount = 0 self:__Boarding( -2, CargoCarrier, NearRadius, ... )
local Speed = 90 self.RunCount = self.RunCount + 2
local Angle = 180 end
local Distance = 0 if self.RunCount >= 40 then
self.RunCount = 0
local Speed = 90
local Angle = 180
local Distance = 0
--self:F({Unit=self.CargoObject:GetName()})
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() -- Set the CargoObject to state Green to ensure it is boarding!
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. self.CargoObject:OptionAlarmStateGreen()
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) local Points = {}
-- Set the CargoObject to state Green to ensure it is boarding! local PointStartVec2 = self.CargoObject:GetPointVec2()
self.CargoObject:OptionAlarmStateGreen()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" )
local Points = {} Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" )
local PointStartVec2 = self.CargoObject:GetPointVec2() local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 0.2 )
Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" ) end
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 0.2 )
end end
else
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
self:CancelBoarding( CargoCarrier, NearRadius, ... )
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end end
else
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
self:CancelBoarding( CargoCarrier, NearRadius, ... )
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end
else else
self:E("Something is wrong") self:E("Something is wrong")
end end
@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -474,7 +474,7 @@ do -- DESIGNATE
self.Designating = {} self.Designating = {}
self:SetDesignateName() self:SetDesignateName()
self.LaseDuration = 60 self:SetLaseDuration() -- Default is 120 seconds.
self:SetFlashStatusMenu( false ) self:SetFlashStatusMenu( false )
self:SetFlashDetectionMessages( true ) self:SetFlashDetectionMessages( true )
@@ -677,6 +677,14 @@ do -- DESIGNATE
return self return self
end end
--- Set the lase duration for designations.
-- @param #DESIGNATE self
-- @param #number LaseDuration The time in seconds a lase will continue to hold on target. The default is 120 seconds.
-- @return #DESIGNATE
function DESIGNATE:SetLaseDuration( LaseDuration )
self.LaseDuration = LaseDuration or 120
return self
end
--- Generate an array of possible laser codes. --- Generate an array of possible laser codes.
-- Each new lase will select a code from this table. -- Each new lase will select a code from this table.

View File

@@ -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.

View File

@@ -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!
@@ -675,6 +679,69 @@
-- Mission designers can capture the events with OnAfterEvent functions, e.g. @{#WAREHOUSE.OnAfterDelivered} or @{#WAREHOUSE.OnAfterAirbaseCaptured}. -- Mission designers can capture the events with OnAfterEvent functions, e.g. @{#WAREHOUSE.OnAfterDelivered} or @{#WAREHOUSE.OnAfterAirbaseCaptured}.
-- --
-- === -- ===
--
-- # 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
-- --
@@ -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

View File

@@ -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

View File

@@ -908,16 +908,23 @@ function UNIT:InAir()
-- Implementation of workaround. The original code is below. -- Implementation of workaround. The original code is below.
-- This to simulate the landing on buildings. -- This to simulate the landing on buildings.
-- local UnitInAir = DCSUnit:inAir()
local UnitInAir = true local UnitInAir = true
local VelocityVec3 = DCSUnit:getVelocity()
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec local UnitCategory = DCSUnit:getDesc().category
local Coordinate = DCSUnit:getPoint() if UnitCategory == Unit.Category.HELICOPTER then
local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } ) local VelocityVec3 = DCSUnit:getVelocity()
local Height = Coordinate.y - LandHeight local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
if Velocity < 1 and Height <= 60 then local Coordinate = DCSUnit:getPoint()
UnitInAir = false 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 end
self:T3( UnitInAir ) self:T3( UnitInAir )
return UnitInAir return UnitInAir
end end