From 1dc6b91d37631d3e6c2b6a6c960d530dda20deb7 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 30 Jul 2018 00:11:08 +0200 Subject: [PATCH 01/29] G2G Dispatcher Draft --- .../Moose/AI/AI_G2G_Dispatcher.lua | 131 ++++++++++++++++++ Moose Development/Moose/Core/Message.lua | 2 +- .../Moose/Functional/Detection.lua | 3 +- Moose Setup/Moose.files | 1 + 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 Moose Development/Moose/AI/AI_G2G_Dispatcher.lua diff --git a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua new file mode 100644 index 000000000..2bf2ac3a3 --- /dev/null +++ b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua @@ -0,0 +1,131 @@ +--- **AI** - (R2.4) - Manages automatic ground troups dispatching to the battle field. +-- +-- +-- Features: +-- +-- * Some nice stuff. +-- +-- # QUICK START GUIDE +-- +-- === +-- +-- ### Authors: **funkyfranky** +-- +-- @module AI.AI_G2G_Dispatcher +-- @image AI_Air_To_Air_Dispatching.JPG + +do -- AI_G2G_DISPATCHER + + --- AI_G2G_DISPATCHER class. + -- @type AI_G2G_DISPATCHER + -- @field #string ClassName Name of the class. + -- @field Functional.Detection#DETECTION_AREAS Detection Detection object responsible for identifying enemies. + -- @extends Tasking.DetectionManager#DETECTION_MANAGER + + --- Create an automatic ground . + -- + -- === + -- + -- # Demo Missions + -- + -- ### [AI\_A2A\_DISPATCHER Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching) + -- + -- === + -- + -- # YouTube Channel + -- + -- ### [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx) + -- + -- === + -- + -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia3.JPG) + -- + -- It includes automatic spawning of Combat Air Patrol aircraft (CAP) and Ground Controlled Intercept aircraft (GCI) in response to enemy air movements that are detected by a ground based radar network. + -- CAP flights will take off and proceed to designated CAP zones where they will remain on station until the ground radars direct them to intercept detected enemy aircraft or they run short of fuel and must return to base (RTB). When a CAP flight leaves their zone to perform an interception or return to base a new CAP flight will spawn to take their place. + -- If all CAP flights are engaged or RTB then additional GCI interceptors will scramble to intercept unengaged enemy aircraft under ground radar control. + -- With a little time and with a little work it provides the mission designer with a convincing and completely automatic air defence system. + -- In short it is a plug in very flexible and configurable air defence module for DCS World. + -- + -- Note that in order to create a two way A2A defense system, two AI\_A2A\_DISPATCHER defense system may need to be created, for each coalition one. + -- This is a good implementation, because maybe in the future, more coalitions may become available in DCS world. + -- + -- === + -- + -- # USAGE GUIDE + -- + -- + -- + -- @field #AI_G2G_DISPATCHER + AI_G2G_DISPATCHER = { + ClassName = "AI_G2G_DISPATCHER", + Detection = nil, + } + + + + --- AI_G2G_DISPATCHER constructor. Creates a new AI_G2G_DISPATCHER object. + -- @param #AI_G2G_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network. + -- @return #AI_G2G_DISPATCHER self + function AI_G2G_DISPATCHER:New(Detection) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit(self, DETECTION_MANAGER:New(nil, Detection)) -- #AI_G2G_DISPATCHER + + self.Detection = Detection -- Functional.Detection#DETECTION_AREAS + + self:AddTransition( "Started", "Assign", "Started" ) + + self:__Start(5) + + return self + end + + --- Adds an APC group to transport troops to the front line. + -- @param #AI_G2G_DISPATCHER self + -- @param Wrapper.Group#GROUP group APC group. + -- @return #AI_G2G_DISPATCHER self + function AI_G2G_DISPATCHER:SetTransportAPC(group) + + + end + + --- Adds an APC group to transport troops to the front line. + -- @param #AI_G2G_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem The detected item. + function AI_G2G_DISPATCHER:EvaluateDetectedItem(DetectedItem) + local _coord=DetectedItem.Coordinate + _coord:MarkToAll("detected") + end + + --- Adds an APC group to transport troops to the front line. + -- @param #AI_G2G_DISPATCHER self + -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. + -- @return #boolean True if you want the task assigning to continue while false will cancel the loop. + function AI_G2G_DISPATCHER:ProcessDetected(Detection) + + + -- Now that all obsolete tasks are removed, loop through the detected targets. + for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do + + local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem + local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT + local DetectedCount = DetectedSet:Count() + local DetectedZone = DetectedItem.Zone + + self:F( { "Target ID", DetectedItem.ItemID } ) + DetectedSet:Flush( self ) + + local DetectedID = DetectedItem.ID + local DetectionIndex = DetectedItem.Index + local DetectedItemChanged = DetectedItem.Changed + + env.info(string.format("FF detected item id %d, index = %d, changed = %s", DetectedID, DetectedItem.Index, tostring(DetectedItem.Changed))) + + + + end + end + +end + diff --git a/Moose Development/Moose/Core/Message.lua b/Moose Development/Moose/Core/Message.lua index 1333a43da..5ccfc3b65 100644 --- a/Moose Development/Moose/Core/Message.lua +++ b/Moose Development/Moose/Core/Message.lua @@ -308,7 +308,7 @@ end --- Sends a MESSAGE to all players. -- @param #MESSAGE self --- @param Core.Settings#Settings (Optional) Settings for message display +-- @param Core.Settings#Settings Settings (Optional) Settings for message display. -- @return #MESSAGE -- @usage -- -- Send a message created to all players. diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index a547eb1d2..66ca390e2 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -515,6 +515,7 @@ do -- DETECTION_BASE for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do --self:F( { DetectionGroupData } ) + self:F( {"FF", DetectionGroupData } ) self:__DetectionGroup( DetectDelay, DetectionGroupData, DetectionTimeStamp ) -- Process each detection asynchronously. self.DetectionCount = self.DetectionCount + 1 DetectDelay = DetectDelay + 1 @@ -1877,7 +1878,7 @@ do -- DETECTION_UNITS -- @param #DETECTION_UNITS self -- @return #DETECTION_UNITS self function DETECTION_UNITS:CreateDetectionItems() - + env.info("FF createdetectionitmes") -- Loop the current detected items, and check if each object still exists and is detected. for DetectedItemKey, DetectedItem in pairs( self.DetectedItems ) do diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index ea44b6326..2f53e45a8 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -76,6 +76,7 @@ AI/AI_Cargo_Dispatcher.lua AI/AI_Cargo_Dispatcher_APC.lua AI/AI_Cargo_Dispatcher_Helicopter.lua AI/AI_Cargo_Dispatcher_Airplane.lua +AI/AI_G2G_Dispatcher.lua Actions/Act_Assign.lua Actions/Act_Route.lua From 849120a8856a7a847b25e8b74e68a34b3ace5529 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 30 Jul 2018 16:04:07 +0200 Subject: [PATCH 02/29] G2G --- .../Moose/AI/AI_G2G_Dispatcher.lua | 126 ++++++++++++++++-- 1 file changed, 116 insertions(+), 10 deletions(-) diff --git a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua index 2bf2ac3a3..0f0a352a2 100644 --- a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua @@ -40,14 +40,7 @@ do -- AI_G2G_DISPATCHER -- -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia3.JPG) -- - -- It includes automatic spawning of Combat Air Patrol aircraft (CAP) and Ground Controlled Intercept aircraft (GCI) in response to enemy air movements that are detected by a ground based radar network. - -- CAP flights will take off and proceed to designated CAP zones where they will remain on station until the ground radars direct them to intercept detected enemy aircraft or they run short of fuel and must return to base (RTB). When a CAP flight leaves their zone to perform an interception or return to base a new CAP flight will spawn to take their place. - -- If all CAP flights are engaged or RTB then additional GCI interceptors will scramble to intercept unengaged enemy aircraft under ground radar control. - -- With a little time and with a little work it provides the mission designer with a convincing and completely automatic air defence system. - -- In short it is a plug in very flexible and configurable air defence module for DCS World. - -- - -- Note that in order to create a two way A2A defense system, two AI\_A2A\_DISPATCHER defense system may need to be created, for each coalition one. - -- This is a good implementation, because maybe in the future, more coalitions may become available in DCS world. + -- Blabla. -- -- === -- @@ -59,6 +52,7 @@ do -- AI_G2G_DISPATCHER AI_G2G_DISPATCHER = { ClassName = "AI_G2G_DISPATCHER", Detection = nil, + Homebase = {}, } @@ -85,9 +79,16 @@ do -- AI_G2G_DISPATCHER -- @param #AI_G2G_DISPATCHER self -- @param Wrapper.Group#GROUP group APC group. -- @return #AI_G2G_DISPATCHER self - function AI_G2G_DISPATCHER:SetTransportAPC(group) - + function AI_G2G_DISPATCHER:AddTransportAPC(group, homebase, resources) + self.TransportAPC[group]={} + self.TransportAPC[group].group=group + self.TransportAPC[group].homebase=homebase + self.TransportAPC[group].resources=resources + -- Add homebase + if not self:GetHomebase(homebase) then + self:AddHomebase(homebase) + end end --- Adds an APC group to transport troops to the front line. @@ -96,6 +97,12 @@ do -- AI_G2G_DISPATCHER function AI_G2G_DISPATCHER:EvaluateDetectedItem(DetectedItem) local _coord=DetectedItem.Coordinate _coord:MarkToAll("detected") + + + local _id=DetectedItem.ID + + + end --- Adds an APC group to transport troops to the front line. @@ -125,7 +132,106 @@ do -- AI_G2G_DISPATCHER end + end end + + +do + + --- WAREHOUSE class. + -- @type WAREHOUSE + -- @field #string ClassName Name of the class. + -- @extends Core.Fsm#FSM + + --- Create an automatic ground . + -- + -- === + -- + -- # Demo Missions + -- + -- ### None. + -- + -- === + -- + -- # YouTube Channel + -- + -- ### None. + -- + -- === + -- + -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia3.JPG) + -- + -- Warehouse + -- + -- === + -- + -- # USAGE GUIDE + -- + -- + -- + -- @field #WAREHOUSE + WAREHOUSE = { + ClassName = "WAREHOUSE", + Homebase = nil, + plane = {}, + helicopter = {}, + artillery={}, + tank = {}, + apcs = {}, + infantry={}, + } + + WAREHOUSE.category= { + Transport=1, + Figherplane=1, + AWACS=1, + Tanker=1, + + } + + --- WAREHOUSE constructor. Creates a new WAREHOUSE object. + -- @param #WAREHOUSE self + -- @param Wrapper.Airbase#AIRBASE airbase Airbase. + -- @return #WAREHOUSE self + function WAREHOUSE:NewAirbase(airbase) + + -- Inherits from DETECTION_MANAGER + local self = BASE:Inherit( self, FSM:New() ) -- #WAREHOUSE + + self.Homebase=airbase + + return self + end + + --- Add an airplane group to the warehouse stock. + -- @param #WAREHOUSE self + -- @param #string templateprefix Name of the late activated template group as defined in the mission editor. + -- @param #number n Number of groups to add to the warehouse stock. + -- @return #WAREHOUSE self + function WAREHOUSE:AddAirplane(templateprefix, n, warehousetype) + + local group=GROUP:FindByName(templateprefix) + local typename=group:GetDesc().typeName + local displayname=group:GetDesc().displayName + + -- Create a table with properties. + self.airplane[templateprefix]=self.airplane[templateprefix] or {} + + -- Increase number in stock. + if self.airplane[templateprefix].nstock then + self.airplane[templateprefix].nstock=self.airplane[templateprefix].nstock+n + else + self.airplane[templateprefix].nstock=n + end + + self.airplane[templateprefix].nstock=n + + end + +end + + + From 1146684144016881622e19e5472f8ff4ac84dbfc Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 30 Jul 2018 23:41:02 +0200 Subject: [PATCH 03/29] G2G improvments --- .../Moose/AI/AI_G2G_Dispatcher.lua | 157 ++++++++++++++++-- 1 file changed, 145 insertions(+), 12 deletions(-) diff --git a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua index 0f0a352a2..f4468f9f9 100644 --- a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua @@ -175,13 +175,14 @@ do -- @field #WAREHOUSE WAREHOUSE = { ClassName = "WAREHOUSE", - Homebase = nil, - plane = {}, - helicopter = {}, - artillery={}, - tank = {}, - apcs = {}, - infantry={}, + coalition = nil, + homebase = nil, + plane = {}, + helo = {}, + arty = {}, + tank = {}, + apc = {}, + infantry = {}, } WAREHOUSE.category= { @@ -198,25 +199,152 @@ do -- @return #WAREHOUSE self function WAREHOUSE:NewAirbase(airbase) - -- Inherits from DETECTION_MANAGER + -- Inherits from FSM local self = BASE:Inherit( self, FSM:New() ) -- #WAREHOUSE - self.Homebase=airbase + self.homebase=airbase + self.coordinate=airbase:GetCoordinate() + self.coalition=airbase:GetCoalition() + + + self:AddTransition("*", "Start", "Idle") + self:AddTransition("*", "Status", "*") + self:AddTransition("*", "Request", "*") + + --- Triggers the FSM event "Start". + -- @function [parent=#WAREHOUSE] Start + -- @param #WAREHOUSE self + + --- Triggers the FSM event "Start" after a delay. + -- @function [parent=#WAREHOUSE] __Start + -- @param #WAREHOUSE self + -- @param #number delay Delay in seconds. + + + --- Triggers the FSM event "Status". + -- @function [parent=#WAREHOUSE] Status + -- @param #WAREHOUSE self + + --- Triggers the FSM event "Status" after a delay. + -- @function [parent=#WAREHOUSE] __Status + -- @param #WAREHOUSE self + -- @param #number delay Delay in seconds. + + + --- Triggers the FSM event "Request". + -- @function [parent=#WAREHOUSE] Request + -- @param #WAREHOUSE self + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. + -- @param #string Asset Asset that is requested. + -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + + --- Triggers the FSM event "Request" after a delay. + -- @function [parent=#WAREHOUSE] __Request + -- @param #WAREHOUSE self + -- @param #number delay Delay in seconds. + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. + -- @param #string Asset Asset that is requested. + -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" return self end + + --- Warehouse + -- @param #WAREHOUSE self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + function WAREHOUSE:onafterStart(From, Event, To) + env.info("FF starting warehouse of airbase of "..self.homebase:GetName()) + + -- handle events + -- event takeoff + -- event landing + -- event crash/dead + -- event base captured + self:__Status(-5) + end + + + --- Warehouse + -- @param #WAREHOUSE self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + function WAREHOUSE:onafterStatus(From, Event, To) + env.info("FF checking warehouse status of "..self.homebase:GetName()) + + env.info(string.format("FF warehouse at %s: number of transport planes = %d", self.homebase:GetName(), #self.plane)) + + self:__Status(-30) + end + + --- Warehouse + -- @param #WAREHOUSE self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. + -- @param #string Asset Asset that is requested. + -- @param #number nAssed Number of groups of that asset requested. + -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + function WAREHOUSE:onafterRequest(From, Event, To, Airbase, Asset, nAsset, TransportType) + env.info(string.format("FF airbase %s is requesting asset %s from warehouse %s", Airbase:GetName(), Asset, self.homebase:GetName())) + + local nAsset=nAsset or 1 + + if TransportType=="Air" then + + local template=self.plane[math.random(#self.plane)] + + if template then + + local Plane=SPAWN:New(template):SpawnAtAirbase(Airbase, nil, nil, nil, false) + + local CargoGroups = SET_CARGO:New() + + local spawn=SPAWN:New("Infantry Platoon Alpha") + + for i=1,nAsset do + local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) + local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) + CargoGroups:AddCargo(cargogroup) + end + + local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) + + CargoPlane:__Pickup(5, self.homebase) + + function CargoPlane:onafterLoaded( Airplane, From, Event, To, Cargo) + CargoPlane:__Deploy(10, Airbase, 500) + end + + + end + end + + end --- Add an airplane group to the warehouse stock. -- @param #WAREHOUSE self -- @param #string templateprefix Name of the late activated template group as defined in the mission editor. -- @param #number n Number of groups to add to the warehouse stock. -- @return #WAREHOUSE self - function WAREHOUSE:AddAirplane(templateprefix, n, warehousetype) + function WAREHOUSE:AddTransportPlane(templateprefix, n) + + local n=n or 1 local group=GROUP:FindByName(templateprefix) - local typename=group:GetDesc().typeName - local displayname=group:GetDesc().displayName + local DCSgroup=group:GetDCSObject() + local DCSunit=DCSgroup:getUnit(1) + local DCSdesc=DCSunit:getDesc() + local DCSdisplay=DCSunit:getDesc().displayName + local DCScategory=DCSgroup:getCategory() + local DCStype=DCSunit:getTypeName() + --env.info(string.format("FF adding %d transport plane template %s type %s, display %s", n, tostring(templateprefix), tostring(typename), tostring(displayname))) + + --[[ -- Create a table with properties. self.airplane[templateprefix]=self.airplane[templateprefix] or {} @@ -228,6 +356,11 @@ do end self.airplane[templateprefix].nstock=n + ]] + + for i=1,n do + table.insert(self.plane, templateprefix) + end end From 5a034ecf4f5680290953ee70530255c910a12d78 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Tue, 31 Jul 2018 15:43:31 +0200 Subject: [PATCH 04/29] G2G Warehouse --- .../Moose/AI/AI_Cargo_Airplane.lua | 113 +++++++++----- .../Moose/AI/AI_G2G_Dispatcher.lua | 139 ++++++++++++++---- Moose Development/Moose/Core/Base.lua | 9 +- 3 files changed, 189 insertions(+), 72 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index bbbe19ed0..b1422cb11 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -23,8 +23,8 @@ AI_CARGO_AIRPLANE = { --- Creates a new AI_CARGO_AIRPLANE object. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane --- @param Core.Set#SET_CARGO CargoSet +-- @param Wrapper.Group#GROUP Airplane Plane used for transportation of cargo. +-- @param Core.Set#SET_CARGO CargoSet Cargo set to be transported. -- @return #AI_CARGO_AIRPLANE function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) @@ -54,7 +54,7 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- @param #string From -- @param #string Event -- @param #string To - -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. -- @return #boolean --- Pickup Handler OnAfter for AI_CARGO_AIRPLANE @@ -63,18 +63,18 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- @param #string From -- @param #string Event -- @param #string To - -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. --- Pickup Trigger for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] Pickup -- @param #AI_CARGO_AIRPLANE self - -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. --- Pickup Asynchronous Trigger for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] __Pickup -- @param #AI_CARGO_AIRPLANE self - -- @param #number Delay - -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param #number Delay Delay in seconds. + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. --- Deploy Handler OnBefore for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] OnBeforeDeploy @@ -82,7 +82,8 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- @param #string From -- @param #string Event -- @param #string To - -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed. + -- @param #number Speed Speed in km/h for travelling to deploy base. -- @return #boolean --- Deploy Handler OnAfter for AI_CARGO_AIRPLANE @@ -91,20 +92,22 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- @param #string From -- @param #string Event -- @param #string To - -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed. + -- @param #number Speed Speed in km/h for travelling to deploy base. --- Deploy Trigger for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] Deploy -- @param #AI_CARGO_AIRPLANE self - -- @param Wrapper.Airbase#AIRBASE Airbase + -- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed. + -- @param #number Speed Speed in km/h for travelling to deploy base. --- Deploy Asynchronous Trigger for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] __Deploy -- @param #AI_CARGO_AIRPLANE self - -- @param Wrapper.Airbase#AIRBASE Airbase - -- @param #number Delay - - + -- @param #number Delay Delay in seconds. + -- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed. + -- @param #number Speed Speed in km/h for travelling to deploy base. + self:SetCarrier( Airplane ) return self @@ -190,13 +193,12 @@ function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius ) end ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane +--- On after "Landed" event. Called on engine shutdown. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Transport plane. -- @param From -- @param Event -- @param To - -- @param Wrapper.Airbase#AIRBASE Airbase --- @param #number Speed function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -216,8 +218,8 @@ function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To ) end - ---- @param #AI_CARGO_AIRPLANE self +--- On after "Pickup" event. Routes transport to pickup airbase. +-- @param #AI_CARGO_AIRPLANE self -- @param Wrapper.Group#GROUP Airplane -- @param From -- @param Event @@ -227,24 +229,34 @@ end function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Speed ) if Airplane and Airplane:IsAlive() then - self:Route( Airplane, Airbase, Speed ) + + -- Aircraft might be on the ground of the pickup airbase already. + if Airplane:InAir() then + self:Route( Airplane, Airbase, Speed ) + end + -- TODO: Improve :Route() so that the aircraft can be routed from another airbase to the pickup airbase. + self.RoutePickup = true + + -- Set airbase as starting point in the next Route() call. self.Airbase = Airbase end end - ---- @param #AI_CARGO_AIRPLANE self +--- On after Depoly event. Routes plane to deploy airbase. +-- @param #AI_CARGO_AIRPLANE self -- @param Wrapper.Group#GROUP Airplane -- @param From -- @param Event -- @param To --- @param Wrapper.Airbase#AIRBASE Airbase --- @param #number Speed +-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troups should be deployed. +-- @param #number Speed Speed in km/h for travelling to deploy base. function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Speed ) if Airplane and Airplane:IsAlive() then + + -- Route to self:Route( Airplane, Airbase, Speed ) self.RouteDeploy = true self.Airbase = Airbase @@ -253,26 +265,37 @@ function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Sp end ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane +--- On after Load event. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Transport plane. +-- @param From +-- @param Event +-- @param To +-- @param Wrapper.Point#COORDINATE Coordinate function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) if Airplane and Airplane:IsAlive() then for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo=Cargo --Cargo.Cargo#CARGO if Cargo:IsInLoadRadius( Coordinate ) then self:__Board( 5 ) Cargo:Board( Airplane, 25 ) self.Cargo = Cargo break end + end end end ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane +--- On after Board event. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Cargo plane. +-- @param From +-- @param Event +-- @param To function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -286,8 +309,12 @@ function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) end ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane +--- On after Loaded event. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Cargo plane. +-- @param From +-- @param Event +-- @param To function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -296,8 +323,12 @@ function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To ) end ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane +--- On after Unload event. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Cargo plane. +-- @param From +-- @param Event +-- @param To function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -307,8 +338,12 @@ function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) end ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane +--- On after Unboard event. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Cargo plane. +-- @param From +-- @param Event +-- @param To function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -321,8 +356,12 @@ function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) end ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane +--- On after Unloaded event. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Cargo plane. +-- @param From +-- @param Event +-- @param To function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then diff --git a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua index f4468f9f9..36f833a80 100644 --- a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua @@ -185,12 +185,12 @@ do infantry = {}, } + -- @field category WAREHOUSE.category= { Transport=1, - Figherplane=1, + Fighter=1, AWACS=1, - Tanker=1, - + Tanker=1, } --- WAREHOUSE constructor. Creates a new WAREHOUSE object. @@ -205,11 +205,11 @@ do self.homebase=airbase self.coordinate=airbase:GetCoordinate() self.coalition=airbase:GetCoalition() - - - self:AddTransition("*", "Start", "Idle") - self:AddTransition("*", "Status", "*") - self:AddTransition("*", "Request", "*") + + self:AddTransition("*", "Start", "Running") + self:AddTransition("*", "Status", "*") + self:AddTransition("*", "Request", "*") + self:AddTransition("*", "Delivered", "*") --- Triggers the FSM event "Start". -- @function [parent=#WAREHOUSE] Start @@ -236,6 +236,7 @@ do -- @param #WAREHOUSE self -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. -- @param #string Asset Asset that is requested. + -- @param #number nAsset Number of assets requested. Default 1. -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" --- Triggers the FSM event "Request" after a delay. @@ -244,7 +245,19 @@ do -- @param #number delay Delay in seconds. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. -- @param #string Asset Asset that is requested. + -- @param #number nAsset Number of assets requested. Default 1. -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + + --- Triggers the FSM event "Delivered". + -- @function [parent=#WAREHOUSE] Delivered + -- @param #WAREHOUSE self + -- @param Wrapper.Group#GROUP group Group that was delivered. + + --- Triggers the FSM event "Delivered" after a delay. + -- @function [parent=#WAREHOUSE] __Delivered + -- @param #number delay Delay in seconds. + -- @param #WAREHOUSE self + -- @param Wrapper.Group#GROUP group Group that was delivered. return self end @@ -255,7 +268,7 @@ do -- @param #string Event Event. -- @param #string To To state. function WAREHOUSE:onafterStart(From, Event, To) - env.info("FF starting warehouse of airbase of "..self.homebase:GetName()) + env.info("FF starting warehouse at airbase "..self.homebase:GetName()) -- handle events -- event takeoff @@ -272,7 +285,7 @@ do -- @param #string Event Event. -- @param #string To To state. function WAREHOUSE:onafterStatus(From, Event, To) - env.info("FF checking warehouse status of "..self.homebase:GetName()) + env.info("FF checking warehouse status of airbase "..self.homebase:GetName()) env.info(string.format("FF warehouse at %s: number of transport planes = %d", self.homebase:GetName(), #self.plane)) @@ -295,35 +308,80 @@ do if TransportType=="Air" then - local template=self.plane[math.random(#self.plane)] + -- Get a random template from the stock list. + local _chosenone=math.random(#self.plane) + -- Select template group name. + local template=self.plane[_chosenone] + if template then + -- Spawn plane at warehouse homebase. local Plane=SPAWN:New(template):SpawnAtAirbase(Airbase, nil, nil, nil, false) + if Plane==nil then + -- Plane was not spawned correctly. Try again in 60 seconds. + self:__Request( 60, Airbase, Asset, nAsset, TransportType) + return + else + -- Remove chosen plane from list. + table.remove(self.plane,_chosenone) + end + + -- New empty cargo set. local CargoGroups = SET_CARGO:New() + -- Spawn requested assets. local spawn=SPAWN:New("Infantry Platoon Alpha") for i=1,nAsset do local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) - CargoGroups:AddCargo(cargogroup) + CargoGroups:AddCargo(cargogroup) end - local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) + -- Define cargo airplane. + local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) + -- Pickup cargo at homebase. CargoPlane:__Pickup(5, self.homebase) - function CargoPlane:onafterLoaded( Airplane, From, Event, To, Cargo) + -- Set warehouse state so that we can retreive it later. + Plane:SetState(Plane, "WAREHOUSE", self) + + -- Once the cargo was loaded start off to deploy airbase. + function CargoPlane:OnAfterLoaded(Airplane, From, Event, To) CargoPlane:__Deploy(10, Airbase, 500) end - + --- Function + -- @param Wrapper.Group#GROUP Airplane + function CargoPlane:OnAfterUnloaded(Airplane, From, Event, To) + local group=CargoPlane.Cargo:GetObject() + local Airplane=Airplane --Wrapper.Group#GROUP + local warehouse Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE + warehouse:__Delivered(1, group) + end + end end end + + --- Warehouse + -- @param #WAREHOUSE self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. + -- @param Wrapper.Group#GROUP Group The group that was delivered. + -- @param #string Asset Asset that is requested. + -- @param #number nAssed Number of groups of that asset requested. + -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + function WAREHOUSE:onafterDelivered(From, Event, To, Group) + local road=Group:GetCoordinate():GetClosestPointToRoad() + local speed=Group:GetSpeedMax()*0.5 + Group:RouteGroundTo(road, speed, "Off Road") + end --- Add an airplane group to the warehouse stock. -- @param #WAREHOUSE self @@ -341,27 +399,44 @@ do local DCSdisplay=DCSunit:getDesc().displayName local DCScategory=DCSgroup:getCategory() local DCStype=DCSunit:getTypeName() - - --env.info(string.format("FF adding %d transport plane template %s type %s, display %s", n, tostring(templateprefix), tostring(typename), tostring(displayname))) - - --[[ - -- Create a table with properties. - self.airplane[templateprefix]=self.airplane[templateprefix] or {} - - -- Increase number in stock. - if self.airplane[templateprefix].nstock then - self.airplane[templateprefix].nstock=self.airplane[templateprefix].nstock+n - else - self.airplane[templateprefix].nstock=n - end - - self.airplane[templateprefix].nstock=n - ]] - + + -- Add this n times to the table. for i=1,n do table.insert(self.plane, templateprefix) end + return self + end + + + --- Add an airplane group to the warehouse stock. + -- @param #WAREHOUSE self + -- @param #string templateprefix Name of the late activated template group as defined in the mission editor. + -- @param #number n Number of groups to add to the warehouse stock. + -- @return #WAREHOUSE self + function WAREHOUSE:AddInfantry(templateprefix, n) + + local n=n or 1 + + local group=GROUP:FindByName(templateprefix) + + if group then + + local DCSgroup=group:GetDCSObject() + local DCSunit=DCSgroup:getUnit(1) + local DCSdesc=DCSunit:getDesc() + local DCSdisplay=DCSunit:getDesc().displayName + local DCScategory=DCSgroup:getCategory() + local DCStype=DCSunit:getTypeName() + + -- Add this n times to the table. + for i=1,n do + table.insert(self.infantry, {templatename=templateprefix, category=DCScategory, typename=DCStype}) + end + + end + + return self end end diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 83d9cd5a7..1b4d96efb 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -798,8 +798,7 @@ end -- @param Object The object that will hold the Value set by the Key. -- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type! -- @param Value The value to is stored in the object. --- @return The Value set. --- @return #nil The Key was not found and thus the Value could not be retrieved. +-- @return The Value set. function BASE:SetState( Object, Key, Value ) local ClassNameAndID = Object:GetClassNameAndID() @@ -816,7 +815,7 @@ end -- @param #BASE self -- @param Object The object that holds the Value set by the Key. -- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type! --- @return The Value retrieved. +-- @return The Value retrieved or nil if the Key was not found and thus the Value could not be retrieved. function BASE:GetState( Object, Key ) local ClassNameAndID = Object:GetClassNameAndID() @@ -829,6 +828,10 @@ function BASE:GetState( Object, Key ) return nil end +--- Clear the state of an object. +-- @param #BASE self +-- @param Object The object that holds the Value set by the Key. +-- @param StateName The key that is should be cleared. function BASE:ClearState( Object, StateName ) local ClassNameAndID = Object:GetClassNameAndID() From e0564876f4d85cd3e0cfbe21010e73b5723673e3 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 1 Aug 2018 01:11:24 +0200 Subject: [PATCH 05/29] RANGE 1.2.1, WAREHOUSE 0.1.0 --- .../Moose/AI/AI_G2G_Dispatcher.lua | 306 -------------- Moose Development/Moose/DCS.lua | 1 + Moose Development/Moose/Functional/Range.lua | 30 +- .../Moose/Functional/Warehouse.lua | 383 ++++++++++++++++++ Moose Development/Moose/Wrapper/Group.lua | 37 +- Moose Setup/Moose.files | 1 + 6 files changed, 447 insertions(+), 311 deletions(-) create mode 100644 Moose Development/Moose/Functional/Warehouse.lua diff --git a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua index 36f833a80..734c4ef4d 100644 --- a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua @@ -137,309 +137,3 @@ do -- AI_G2G_DISPATCHER end - - -do - - --- WAREHOUSE class. - -- @type WAREHOUSE - -- @field #string ClassName Name of the class. - -- @extends Core.Fsm#FSM - - --- Create an automatic ground . - -- - -- === - -- - -- # Demo Missions - -- - -- ### None. - -- - -- === - -- - -- # YouTube Channel - -- - -- ### None. - -- - -- === - -- - -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia3.JPG) - -- - -- Warehouse - -- - -- === - -- - -- # USAGE GUIDE - -- - -- - -- - -- @field #WAREHOUSE - WAREHOUSE = { - ClassName = "WAREHOUSE", - coalition = nil, - homebase = nil, - plane = {}, - helo = {}, - arty = {}, - tank = {}, - apc = {}, - infantry = {}, - } - - -- @field category - WAREHOUSE.category= { - Transport=1, - Fighter=1, - AWACS=1, - Tanker=1, - } - - --- WAREHOUSE constructor. Creates a new WAREHOUSE object. - -- @param #WAREHOUSE self - -- @param Wrapper.Airbase#AIRBASE airbase Airbase. - -- @return #WAREHOUSE self - function WAREHOUSE:NewAirbase(airbase) - - -- Inherits from FSM - local self = BASE:Inherit( self, FSM:New() ) -- #WAREHOUSE - - self.homebase=airbase - self.coordinate=airbase:GetCoordinate() - self.coalition=airbase:GetCoalition() - - self:AddTransition("*", "Start", "Running") - self:AddTransition("*", "Status", "*") - self:AddTransition("*", "Request", "*") - self:AddTransition("*", "Delivered", "*") - - --- Triggers the FSM event "Start". - -- @function [parent=#WAREHOUSE] Start - -- @param #WAREHOUSE self - - --- Triggers the FSM event "Start" after a delay. - -- @function [parent=#WAREHOUSE] __Start - -- @param #WAREHOUSE self - -- @param #number delay Delay in seconds. - - - --- Triggers the FSM event "Status". - -- @function [parent=#WAREHOUSE] Status - -- @param #WAREHOUSE self - - --- Triggers the FSM event "Status" after a delay. - -- @function [parent=#WAREHOUSE] __Status - -- @param #WAREHOUSE self - -- @param #number delay Delay in seconds. - - - --- Triggers the FSM event "Request". - -- @function [parent=#WAREHOUSE] Request - -- @param #WAREHOUSE self - -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. - -- @param #string Asset Asset that is requested. - -- @param #number nAsset Number of assets requested. Default 1. - -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" - - --- Triggers the FSM event "Request" after a delay. - -- @function [parent=#WAREHOUSE] __Request - -- @param #WAREHOUSE self - -- @param #number delay Delay in seconds. - -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. - -- @param #string Asset Asset that is requested. - -- @param #number nAsset Number of assets requested. Default 1. - -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" - - --- Triggers the FSM event "Delivered". - -- @function [parent=#WAREHOUSE] Delivered - -- @param #WAREHOUSE self - -- @param Wrapper.Group#GROUP group Group that was delivered. - - --- Triggers the FSM event "Delivered" after a delay. - -- @function [parent=#WAREHOUSE] __Delivered - -- @param #number delay Delay in seconds. - -- @param #WAREHOUSE self - -- @param Wrapper.Group#GROUP group Group that was delivered. - - return self - end - - --- Warehouse - -- @param #WAREHOUSE self - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - function WAREHOUSE:onafterStart(From, Event, To) - env.info("FF starting warehouse at airbase "..self.homebase:GetName()) - - -- handle events - -- event takeoff - -- event landing - -- event crash/dead - -- event base captured - self:__Status(-5) - end - - - --- Warehouse - -- @param #WAREHOUSE self - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - function WAREHOUSE:onafterStatus(From, Event, To) - env.info("FF checking warehouse status of airbase "..self.homebase:GetName()) - - env.info(string.format("FF warehouse at %s: number of transport planes = %d", self.homebase:GetName(), #self.plane)) - - self:__Status(-30) - end - - --- Warehouse - -- @param #WAREHOUSE self - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. - -- @param #string Asset Asset that is requested. - -- @param #number nAssed Number of groups of that asset requested. - -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" - function WAREHOUSE:onafterRequest(From, Event, To, Airbase, Asset, nAsset, TransportType) - env.info(string.format("FF airbase %s is requesting asset %s from warehouse %s", Airbase:GetName(), Asset, self.homebase:GetName())) - - local nAsset=nAsset or 1 - - if TransportType=="Air" then - - -- Get a random template from the stock list. - local _chosenone=math.random(#self.plane) - - -- Select template group name. - local template=self.plane[_chosenone] - - if template then - - -- Spawn plane at warehouse homebase. - local Plane=SPAWN:New(template):SpawnAtAirbase(Airbase, nil, nil, nil, false) - - if Plane==nil then - -- Plane was not spawned correctly. Try again in 60 seconds. - self:__Request( 60, Airbase, Asset, nAsset, TransportType) - return - else - -- Remove chosen plane from list. - table.remove(self.plane,_chosenone) - end - - -- New empty cargo set. - local CargoGroups = SET_CARGO:New() - - -- Spawn requested assets. - local spawn=SPAWN:New("Infantry Platoon Alpha") - - for i=1,nAsset do - local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) - local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) - CargoGroups:AddCargo(cargogroup) - end - - -- Define cargo airplane. - local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) - - -- Pickup cargo at homebase. - CargoPlane:__Pickup(5, self.homebase) - - -- Set warehouse state so that we can retreive it later. - Plane:SetState(Plane, "WAREHOUSE", self) - - -- Once the cargo was loaded start off to deploy airbase. - function CargoPlane:OnAfterLoaded(Airplane, From, Event, To) - CargoPlane:__Deploy(10, Airbase, 500) - end - - --- Function - -- @param Wrapper.Group#GROUP Airplane - function CargoPlane:OnAfterUnloaded(Airplane, From, Event, To) - local group=CargoPlane.Cargo:GetObject() - local Airplane=Airplane --Wrapper.Group#GROUP - local warehouse Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE - warehouse:__Delivered(1, group) - end - - end - end - - end - - --- Warehouse - -- @param #WAREHOUSE self - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. - -- @param Wrapper.Group#GROUP Group The group that was delivered. - -- @param #string Asset Asset that is requested. - -- @param #number nAssed Number of groups of that asset requested. - -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" - function WAREHOUSE:onafterDelivered(From, Event, To, Group) - local road=Group:GetCoordinate():GetClosestPointToRoad() - local speed=Group:GetSpeedMax()*0.5 - Group:RouteGroundTo(road, speed, "Off Road") - end - - --- Add an airplane group to the warehouse stock. - -- @param #WAREHOUSE self - -- @param #string templateprefix Name of the late activated template group as defined in the mission editor. - -- @param #number n Number of groups to add to the warehouse stock. - -- @return #WAREHOUSE self - function WAREHOUSE:AddTransportPlane(templateprefix, n) - - local n=n or 1 - - local group=GROUP:FindByName(templateprefix) - local DCSgroup=group:GetDCSObject() - local DCSunit=DCSgroup:getUnit(1) - local DCSdesc=DCSunit:getDesc() - local DCSdisplay=DCSunit:getDesc().displayName - local DCScategory=DCSgroup:getCategory() - local DCStype=DCSunit:getTypeName() - - -- Add this n times to the table. - for i=1,n do - table.insert(self.plane, templateprefix) - end - - return self - end - - - --- Add an airplane group to the warehouse stock. - -- @param #WAREHOUSE self - -- @param #string templateprefix Name of the late activated template group as defined in the mission editor. - -- @param #number n Number of groups to add to the warehouse stock. - -- @return #WAREHOUSE self - function WAREHOUSE:AddInfantry(templateprefix, n) - - local n=n or 1 - - local group=GROUP:FindByName(templateprefix) - - if group then - - local DCSgroup=group:GetDCSObject() - local DCSunit=DCSgroup:getUnit(1) - local DCSdesc=DCSunit:getDesc() - local DCSdisplay=DCSunit:getDesc().displayName - local DCScategory=DCSgroup:getCategory() - local DCStype=DCSunit:getTypeName() - - -- Add this n times to the table. - for i=1,n do - table.insert(self.infantry, {templatename=templateprefix, category=DCScategory, typename=DCStype}) - end - - end - - return self - end - -end - - - diff --git a/Moose Development/Moose/DCS.lua b/Moose Development/Moose/DCS.lua index 492d1d049..ba6bc1c42 100644 --- a/Moose Development/Moose/DCS.lua +++ b/Moose Development/Moose/DCS.lua @@ -959,6 +959,7 @@ do -- Group -- @field HELICOPTER -- @field GROUND -- @field SHIP + -- @field TRAIN -- Static Functions diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 1e39d0735..e7c015056 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -68,6 +68,8 @@ -- @field #number dtBombtrack Time step [sec] used for tracking released bomb/rocket positions. Default 0.005 seconds. -- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threashold [m]. Default 25000 m. -- @field #number Tmsg Time [sec] messages to players are displayed. Default 30 sec. +-- @field #string examinergroupname Name of the examiner group which should get all messages. +-- @field #boolean examinerexclusive If true, only the examiner gets messages. If false, clients and examiner get messages. -- @field #number strafemaxalt Maximum altitude above ground for registering for a strafe run. Default is 914 m = 3000 ft. -- @field #number ndisplayresult Number of (player) results that a displayed. Default is 10. -- @field Utilities.Utils#SMOKECOLOR BombSmokeColor Color id used for smoking bomb targets. @@ -234,6 +236,8 @@ RANGE={ dtBombtrack=0.005, BombtrackThreshold=25000, Tmsg=30, + examinergroupname=nil, + examinerexclusive=nil, strafemaxalt=914, ndisplayresult=10, BombSmokeColor=SMOKECOLOR.Red, @@ -279,8 +283,8 @@ RANGE.MenuF10={} RANGE.id="RANGE | " --- Range script version. --- @field #number version -RANGE.version="1.2.0" +-- @field #string version +RANGE.version="1.2.1" --TODO list: --TODO: Add custom weapons, which can be specified by the user. @@ -434,6 +438,15 @@ function RANGE:SetMessageTimeDuration(time) self.Tmsg=time or RANGE.Defaults.Tmsg end +--- Set messages to examiner. The examiner will receive messages from all clients. +-- @param #RANGE self +-- @param #string examinergroupname Name of the group of the examiner. +-- @param #boolean exclusively If true, messages are send exclusively to the examiner, i.e. not to the clients. +function RANGE:SetMessageToExaminer(examinergroupname, exclusively) + self.examinergroupname=examinergroupname + self.examinerexclusive=exclusively +end + --- Set max number of player results that are displayed. -- @param #RANGE self -- @param #number nmax Number of results. Default is 10. @@ -2119,13 +2132,24 @@ function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear) -- Group ID. local _gid=_unit:GetGroup():GetID() - if _gid then + if _gid and not self.examinerexclusive then if _clear == true then trigger.action.outTextForGroup(_gid, _text, _time, _clear) else trigger.action.outTextForGroup(_gid, _text, _time) end end + + if self.examinergroupname~=nil then + local _examinerid=GROUP:FindByName(self.examinergroupname):GetID() + if _examinerid then + if _clear == true then + trigger.action.outTextForGroup(_examinerid, _text, _time, _clear) + else + trigger.action.outTextForGroup(_examinerid, _text, _time) + end + end + end end diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua new file mode 100644 index 000000000..c5ee2d6a7 --- /dev/null +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -0,0 +1,383 @@ +--- **Functional** - (R2.4) - Manages assets of an airbase and transportation to other airbases. +-- +-- +-- Features: +-- +-- * Some nice stuff. +-- +-- # QUICK START GUIDE +-- +-- === +-- +-- ### Authors: **funkyfranky** +-- +-- @module Functional.Warehouse +-- @image Warehouse.JPG + +--- WAREHOUSE class. +-- @type WAREHOUSE +-- @field #string ClassName Name of the class. +-- @extends Core.Fsm#FSM + +--- Manages ground assets of an airbase and offers the possibility to transport them to another airbase or warehouse. +-- +-- === +-- +-- # Demo Missions +-- +-- ### None. +-- +-- === +-- +-- # YouTube Channel +-- +-- ### None. +-- +-- === +-- +-- ![Banner Image](..\Presentations\WAREHOUSE\Warehouse_pic.JPG) +-- +-- Warehouse +-- +-- === +-- +-- # USAGE GUIDE +-- +-- +-- +-- @field #WAREHOUSE +WAREHOUSE = { + ClassName = "WAREHOUSE", + coalition = nil, + homebase = nil, + stock = {}, +} + +--- Type Warehouse stock table. table.insert(self.stock, {templatename=templategroupname, category=DCScategory, type=DCStype, transport=transport, fighther=fighter, tanker=tanker, awacs=awacs, artillery=artillery}) +-- @type WAREHOUSE.Stock +-- @field #string templatename Name of the template group. +-- @field DCS#Category category Category of the group. Airplane, helicopter, ... +-- @field #string type Type of the group +-- @field #boolean fighter If true, group is a fighter airplane. +-- @field #boolean transport If truie, group can transport other units either by air or ground. +-- @field #boolean tanker If true, group is a tanker and can refuel other air units. +-- @field #boolean awacs If true, group has AWACS capabilities. +-- @field #boolean artillery If true, group is an artillery unit. + +--- Warehouse classes. +-- @field Warehouse.Class Class +WAREHOUSE.Class = { + TRANSPORT=1, + FIGHTER=2, + TANKER=3, + AWACS=4, + ARTY=5, +} + +--- Warehouse categories +-- @field Category +WAREHOUSE.Category = { + AIRPLANE = 0, + HELICOPTER = 1, + GROUND = 2, + SHIP = 3, + TRAIN = 4, +} + +--- Warehouse class version. +-- @field #number version +WAREHOUSE.version="0.1.0" + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- TODO: Warehuse todo list. +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +-- TODO: A lot! + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Constructor(s) +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- WAREHOUSE constructor. Creates a new WAREHOUSE object. +-- @param #WAREHOUSE self +-- @param Wrapper.Airbase#AIRBASE airbase Airbase. +-- @return #WAREHOUSE self +function WAREHOUSE:NewAirbase(airbase) + BASE:E({airbase=airbase}) + + -- Print version. + env.info(string.format("Adding warehouse v%s for airbase %s", WAREHOUSE.version, airbase:GetName())) + + -- Inherit everthing from FSM class. + local self = BASE:Inherit( self, FSM:New() ) -- #WAREHOUSE + + -- Set some string id for output to DCS.log file. + self.wid=string.format("WAREHOUSE %s | ", airbase:GetName()) + + -- Set some variables. + self.homebase=airbase + self.coordinate=airbase:GetCoordinate() + self.coalition=airbase:GetCoalition() + + self:AddTransition("*", "Start", "Running") + self:AddTransition("*", "Status", "*") + self:AddTransition("*", "Request", "*") + self:AddTransition("*", "Delivered", "*") + + --- Triggers the FSM event "Start". + -- @function [parent=#WAREHOUSE] Start + -- @param #WAREHOUSE self + + --- Triggers the FSM event "Start" after a delay. + -- @function [parent=#WAREHOUSE] __Start + -- @param #WAREHOUSE self + -- @param #number delay Delay in seconds. + + + --- Triggers the FSM event "Status". + -- @function [parent=#WAREHOUSE] Status + -- @param #WAREHOUSE self + + --- Triggers the FSM event "Status" after a delay. + -- @function [parent=#WAREHOUSE] __Status + -- @param #WAREHOUSE self + -- @param #number delay Delay in seconds. + + + --- Triggers the FSM event "Request". + -- @function [parent=#WAREHOUSE] Request + -- @param #WAREHOUSE self + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. + -- @param #string Asset Asset that is requested. + -- @param #number nAsset Number of assets requested. Default 1. + -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + + --- Triggers the FSM event "Request" after a delay. + -- @function [parent=#WAREHOUSE] __Request + -- @param #WAREHOUSE self + -- @param #number delay Delay in seconds. + -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. + -- @param #string Asset Asset that is requested. + -- @param #number nAsset Number of assets requested. Default 1. + -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + + --- Triggers the FSM event "Delivered". + -- @function [parent=#WAREHOUSE] Delivered + -- @param #WAREHOUSE self + -- @param Wrapper.Group#GROUP group Group that was delivered. + + --- Triggers the FSM event "Delivered" after a delay. + -- @function [parent=#WAREHOUSE] __Delivered + -- @param #number delay Delay in seconds. + -- @param #WAREHOUSE self + -- @param Wrapper.Group#GROUP group Group that was delivered. + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- FSM states +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Warehouse +-- @param #WAREHOUSE self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function WAREHOUSE:onafterStart(From, Event, To) + env.info("FF starting warehouse at airbase "..self.homebase:GetName()) + + -- handle events + -- event takeoff + -- event landing + -- event crash/dead + -- event base captured + self:__Status(-5) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Warehouse +-- @param #WAREHOUSE self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +function WAREHOUSE:onafterStatus(From, Event, To) + env.info("FF checking warehouse status of airbase "..self.homebase:GetName()) + + env.info(string.format("FF warehouse at %s: number of stock = %d", self.homebase:GetName(), #self.stock)) + + self:__Status(-30) +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Warehouse +-- @param #WAREHOUSE self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. +-- @param #string Asset Asset that is requested. +-- @param #number nAssed Number of groups of that asset requested. +-- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" +function WAREHOUSE:onafterRequest(From, Event, To, Airbase, Asset, nAsset, TransportType) + env.info(string.format("FF airbase %s is requesting asset %s from warehouse %s", Airbase:GetName(), Asset, self.homebase:GetName())) + + local nAsset=nAsset or 1 + + if TransportType=="Air" then + + -- Get a random template from the stock list. + local _chosenone=math.random(#self.stock) + + -- Select template group name. + --TODO: FILTER HERE'! + local template=self.stock[_chosenone].templatename + + if template then + + -- Spawn plane at warehouse homebase. + local Plane=SPAWN:New(template):SpawnAtAirbase(Airbase, nil, nil, nil, false) + + if Plane==nil then + -- Plane was not spawned correctly. Try again in 60 seconds. + self:__Request( 60, Airbase, Asset, nAsset, TransportType) + return + else + -- Remove chosen plane from list. + table.remove(self.stock,_chosenone) + end + + -- New empty cargo set. + local CargoGroups = SET_CARGO:New() + + -- Spawn requested assets. + local spawn=SPAWN:New("Infantry Platoon Alpha") + + for i=1,nAsset do + local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) + local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) + CargoGroups:AddCargo(cargogroup) + end + + -- Define cargo airplane. + local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) + + -- Pickup cargo at homebase. + CargoPlane:__Pickup(5, self.homebase) + + -- Set warehouse state so that we can retreive it later. + Plane:SetState(Plane, "WAREHOUSE", self) + + -- Once the cargo was loaded start off to deploy airbase. + function CargoPlane:OnAfterLoaded(Airplane, From, Event, To) + CargoPlane:__Deploy(10, Airbase, 500) + end + + --- Function + -- @param Wrapper.Group#GROUP Airplane + function CargoPlane:OnAfterUnloaded(Airplane, From, Event, To) + local group=CargoPlane.Cargo:GetObject() + local Airplane=Airplane --Wrapper.Group#GROUP + local warehouse Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE + warehouse:__Delivered(1, group) + end + + end + end + +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Warehouse +-- @param #WAREHOUSE self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Group#GROUP Group The group that was delivered. +-- @param #string Asset Asset that is requested. +-- @param #number nAssed Number of groups of that asset requested. +-- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" +function WAREHOUSE:onafterDelivered(From, Event, To, Group) + local road=Group:GetCoordinate():GetClosestPointToRoad() + local speed=Group:GetSpeedMax()*0.5 + Group:RouteGroundTo(road, speed, "Off Road") +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- User functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Add an airplane group to the warehouse stock. +-- @param #WAREHOUSE self +-- @param #string templategroupname Name of the late activated template group as defined in the mission editor. +-- @param #number ngroups Number of groups to add to the warehouse stock. Default is 1. +-- @param #boolean istransport If true, this group will act as transport unit to transport other assets to another airbase. If false, this unit will not be used as transport unit. By default the behavior is determined for the group's attributes. +-- @return #WAREHOUSE self +function WAREHOUSE:AddAsset(templategroupname, ngroups, istransport) + + local n=ngroups or 1 + + local group=GROUP:FindByName(templategroupname) + + if group then + + local DCSgroup=group:GetDCSObject() + local DCSunit=DCSgroup:getUnit(1) + local DCSdesc=DCSunit:getDesc() + local DCSdisplay=DCSunit:getDesc().displayName + local DCScategory=DCSgroup:getCategory() + local DCStype=DCSunit:getTypeName() + + env.info(string.format("group name = %s", group:GetName())) + env.info(string.format("display name = %s", DCSdisplay)) + env.info(string.format("category = %s", DCScategory)) + env.info(string.format("type = %s", DCStype)) + env.info(string.format("attribute infantry = %s", tostring(group:HasAttribute("Infantry")))) + self:E({desc=DCSdesc}) + + local transport=group:HasAttribute("Transport helicopters") or group:HasAttribute("Transports") or group:HasAttribute("Infantry carriers") + local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") + local tanker=group:HasAttribute("Tankers") + local awacs=group:HasAttribute("AWACS") + local apc=group:HasAttribute("Infantry carriers") + local artillery=group:HasAttribute("Artillery") + env.info(string.format("attribute transport = %s", tostring(transport))) + env.info(string.format("attribute apc = %s", tostring(apc))) + env.info(string.format("attribute figther = %s", tostring(fighter))) + env.info(string.format("attribute tanker = %s", tostring(tanker))) + env.info(string.format("attribute awacs = %s", tostring(awacs))) + env.info(string.format("attribute artillery = %s", tostring(artillery))) + + -- Add this n times to the table. + for i=1,n do + table.insert(self.stock, {templatename=templategroupname, category=DCScategory, type=DCStype, transport=transport, fighther=fighter, tanker=tanker, awacs=awacs, artillery=artillery}) + end + + else + -- Group name does not exist! + self:E(string.format("ERROR: Template group name not defined in the mission editor. Check the spelling! templategroupname=%s",tostring(templategroupname))) + end + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Filter stock assets by table entry. +-- @param #WAREHOUSE self +-- @param #WAREHOUSE.Stock entry +function WAREHOUSE:_FilterStock(entry) + --entry.artillery + + return +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 4a2596c49..f5e40c30c 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -335,8 +335,7 @@ end --- Returns the country of the DCS Group. -- @param #GROUP self --- @return DCS#country.id The country identifier. --- @return #nil The DCS Group is not existing or alive. +-- @return DCS#country.id The country identifier or nil if the DCS Group is not existing or alive. function GROUP:GetCountry() self:F2( self.GroupName ) @@ -350,6 +349,40 @@ function GROUP:GetCountry() return nil end + +--- Check if at least one (or all) unit(s) has (have) a certain attribute. +-- See [hoggit documentation](https://wiki.hoggitworld.com/view/DCS_func_hasAttribute). +-- @param #GROUP self +-- @param #string attribute The name of the attribute the group is supposed to have. Valid attributes can be found in the "db_attributes.lua" file which is located at in "C:\Program Files\Eagle Dynamics\DCS World\Scripts\Database". +-- @param #boolean all If true, all units of the group must have the attribute in order to return true. Default is only one unit of a heterogenious group needs to have the attribute. +-- @return #boolean Group has this attribute. +function GROUP:HasAttribute(attribute, all) + + -- Get all units of the group. + local _units=self:GetUnits() + + local _allhave=true + local _onehas=false + + for _,_unit in pairs(_units) do + local _unit=_unit --Wrapper.Unit#UNIT + if _unit then + local _hastit=_unit:HasAttribute(attribute) + if _hastit==true then + _onehas=true + else + _allhave=false + end + end + end + + if all==true then + return _allhave + else + return _onehas + end +end + --- Returns the maximum speed of the group. -- If the group is heterogenious and consists of different units, the max speed of the slowest unit is returned. -- @param #GROUP self diff --git a/Moose Setup/Moose.files b/Moose Setup/Moose.files index 2f53e45a8..cee63ea07 100644 --- a/Moose Setup/Moose.files +++ b/Moose Setup/Moose.files @@ -57,6 +57,7 @@ Functional/ZoneCaptureCoalition.lua Functional/Artillery.lua Functional/Suppression.lua Functional/PseudoATC.lua +Functional/Warehouse.lua AI/AI_Balancer.lua AI/AI_A2A.lua From d4449f791364ae6f7c138c29a8f0e981e6d204d9 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Wed, 1 Aug 2018 15:56:07 +0200 Subject: [PATCH 06/29] WAREHOUSE --- .../Moose/Functional/Warehouse.lua | 122 +++++++++++++++--- 1 file changed, 101 insertions(+), 21 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index c5ee2d6a7..524c8b779 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -17,6 +17,10 @@ --- WAREHOUSE class. -- @type WAREHOUSE -- @field #string ClassName Name of the class. +-- @field DCS#Coalition coalition Coalition the warehouse belongs to. +-- @field Core.Point#COORDINATE coordinate Coordinate of the warehouse. +-- @field Wrapper.Airbase#AIRBASE airbase Airbase the warehouse belongs to. +-- @field #table stock Table holding all assets in stock. Table entries are of type @{#WAREHOUSE.Stock}. -- @extends Core.Fsm#FSM --- Manages ground assets of an airbase and offers the possibility to transport them to another airbase or warehouse. @@ -47,10 +51,11 @@ -- -- @field #WAREHOUSE WAREHOUSE = { - ClassName = "WAREHOUSE", - coalition = nil, - homebase = nil, - stock = {}, + ClassName = "WAREHOUSE", + coalition = nil, + homebase = nil, + coordinate = nil, + stock = {}, } --- Type Warehouse stock table. table.insert(self.stock, {templatename=templategroupname, category=DCScategory, type=DCStype, transport=transport, fighther=fighter, tanker=tanker, awacs=awacs, artillery=artillery}) @@ -59,11 +64,20 @@ WAREHOUSE = { -- @field DCS#Category category Category of the group. Airplane, helicopter, ... -- @field #string type Type of the group -- @field #boolean fighter If true, group is a fighter airplane. +-- @field #boolean attackhelo If true, group is an attack helicopter. -- @field #boolean transport If truie, group can transport other units either by air or ground. -- @field #boolean tanker If true, group is a tanker and can refuel other air units. -- @field #boolean awacs If true, group has AWACS capabilities. -- @field #boolean artillery If true, group is an artillery unit. +--- Asset descriptor. +-- @field Warehouse.AssetDescriptor Assetdescriptor +WAREHOUSE.Descriptor = { + TEMPLATENAME="templatename", + CATEGORY="category", + +} + --- Warehouse classes. -- @field Warehouse.Class Class WAREHOUSE.Class = { @@ -72,16 +86,18 @@ WAREHOUSE.Class = { TANKER=3, AWACS=4, ARTY=5, + ATTACKHELO=6, } --- Warehouse categories -- @field Category WAREHOUSE.Category = { - AIRPLANE = 0, - HELICOPTER = 1, - GROUND = 2, - SHIP = 3, - TRAIN = 4, + AIRPLANE = "plane", + HELICOPTER = "helo", + GROUND = "apc", + SHIP = "ship", + TRAIN = "train", + SELF = "self", } --- Warehouse class version. @@ -207,12 +223,63 @@ function WAREHOUSE:onafterStatus(From, Event, To) env.info(string.format("FF warehouse at %s: number of stock = %d", self.homebase:GetName(), #self.stock)) - self:__Status(-30) + self:__Status(30) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- On before "Request" event. Checks if the request can be fullfilled. +-- @param #WAREHOUSE self +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. +-- @param #string AssetDescriptor Asset that is requested. Can be "templatename", ... +-- @param depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, +-- @param #number nAssed Number of groups of that asset requested. +-- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" +-- @return boolean If true, request is granted. +-- +-- @usage mywarehouse:Request(AIRBASE:)... +function WAREHOUSE:onbeforeRequest(From, Event, To, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) ---- Warehouse + -- Distance from warehouse to + local distance=self.coordinate:Get2DDistance(Airbase:GetCoordinate()) + + -- + local _stockrequest=self._FilterStock(self.stock, AssetDescriptor, AssetDescriptorValue) + + -- Asset is not in stock ==> request denied. + if #_stockrequest==0 then + self:E(self.wid..string.format("Request denied! Asset is currently not in stock.")) + return false + end + + local _TT=TransportType:lower() + if _TT==nil then + if AssetDescriptor=="" then + end + end + + if TransportType:lower() == "plane" then + + elseif TransportType:lower() == "helicopter" then + + elseif TransportType:lower() == "apc" then + + elseif TransportType:lower() == "train" then + + elseif TransportType:lower() == "ship" then + + elseif TransportType:lower() == "self" then + + else + self:E(self.wid..string.format("ERROR: unknown transport type requested! type = %s", tostring(TransportType))) + end + +end + + +--- On after "Request" event. -- @param #WAREHOUSE self -- @param #string From From state. -- @param #string Event Event. @@ -229,10 +296,12 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, Asset, nAsset, Trans if TransportType=="Air" then -- Get a random template from the stock list. - local _chosenone=math.random(#self.stock) + local _chosenone=math.random(#self.stock) --#WAREHOUSE.Stock + + -- Select template group name. - --TODO: FILTER HERE'! + --TODO: FILTER HERE! local template=self.stock[_chosenone].templatename if template then @@ -270,17 +339,19 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, Asset, nAsset, Trans -- Set warehouse state so that we can retreive it later. Plane:SetState(Plane, "WAREHOUSE", self) - -- Once the cargo was loaded start off to deploy airbase. + --- Once the cargo was loaded start off to deploy airbase. function CargoPlane:OnAfterLoaded(Airplane, From, Event, To) CargoPlane:__Deploy(10, Airbase, 500) end - --- Function - -- @param Wrapper.Group#GROUP Airplane + --- Function called when cargo has arrived and was unloaded. function CargoPlane:OnAfterUnloaded(Airplane, From, Event, To) + local group=CargoPlane.Cargo:GetObject() local Airplane=Airplane --Wrapper.Group#GROUP - local warehouse Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE + local warehouse=Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE + + -- Trigger Delivered event. warehouse:__Delivered(1, group) end @@ -370,11 +441,20 @@ end --- Filter stock assets by table entry. -- @param #WAREHOUSE self --- @param #WAREHOUSE.Stock entry -function WAREHOUSE:_FilterStock(entry) - --entry.artillery +-- @param #WAREHOUSE.Stock stock +-- @param #string item Descriptor +-- @param depends value +function WAREHOUSE:_FilterStock(stock, item, value) - return + local filtered={} + + for _,_stock in pairs(stock) do + if _stock[item]==value then + table.insert(filtered, _stock) + end + end + + return filtered end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 52e69cb697f605ca3877d280801d54c88413050c Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 2 Aug 2018 00:29:14 +0200 Subject: [PATCH 07/29] WAREHOUSE --- Moose Development/Moose/DCS.lua | 8 +- .../Moose/Functional/Warehouse.lua | 240 +++++++++++------- 2 files changed, 159 insertions(+), 89 deletions(-) diff --git a/Moose Development/Moose/DCS.lua b/Moose Development/Moose/DCS.lua index ba6bc1c42..c8e997f5c 100644 --- a/Moose Development/Moose/DCS.lua +++ b/Moose Development/Moose/DCS.lua @@ -81,11 +81,11 @@ do -- world --- Searches a defined volume of 3d space for the specified objects within it and then can run function on each returned object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_searchObjects). -- @function [parent=#world] searchObjects - -- @param #DCS.Object.Category objectcategory Category (can be a table) of objects to search. - -- @param #DCS word.VolumeType volume Shape of the search area/volume. - -- @param #ObjectSeachHandler handler A function that handles the search. + -- @param DCS#Object.Category objectcategory Category (can be a table) of objects to search. + -- @param DCS#word.VolumeType volume Shape of the search area/volume. + -- @param ObjectSeachHandler handler A function that handles the search. -- @param #table any Additional data. - -- @return #DCS.unit + -- @return DCS#Unit --- Returns a table of mark panels indexed numerically that are present within the mission. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_getMarkPanels) -- @function [parent=#world] getMarkPanels diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 524c8b779..bb13c9d07 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -1,4 +1,4 @@ ---- **Functional** - (R2.4) - Manages assets of an airbase and transportation to other airbases. +--- **Functional** - (R2.4) - Manages assets of an airbase and transportation to other airbases upon request. -- -- -- Features: @@ -19,7 +19,7 @@ -- @field #string ClassName Name of the class. -- @field DCS#Coalition coalition Coalition the warehouse belongs to. -- @field Core.Point#COORDINATE coordinate Coordinate of the warehouse. --- @field Wrapper.Airbase#AIRBASE airbase Airbase the warehouse belongs to. +-- @field Wrapper.Airbase#AIRBASE homebase Airbase the warehouse belongs to. -- @field #table stock Table holding all assets in stock. Table entries are of type @{#WAREHOUSE.Stock}. -- @extends Core.Fsm#FSM @@ -58,50 +58,50 @@ WAREHOUSE = { stock = {}, } ---- Type Warehouse stock table. table.insert(self.stock, {templatename=templategroupname, category=DCScategory, type=DCStype, transport=transport, fighther=fighter, tanker=tanker, awacs=awacs, artillery=artillery}) --- @type WAREHOUSE.Stock +--- Item of the warehouse stock table. +-- @type WAREHOUSE.Stockitem -- @field #string templatename Name of the template group. --- @field DCS#Category category Category of the group. Airplane, helicopter, ... --- @field #string type Type of the group --- @field #boolean fighter If true, group is a fighter airplane. --- @field #boolean attackhelo If true, group is an attack helicopter. --- @field #boolean transport If truie, group can transport other units either by air or ground. --- @field #boolean tanker If true, group is a tanker and can refuel other air units. --- @field #boolean awacs If true, group has AWACS capabilities. --- @field #boolean artillery If true, group is an artillery unit. +-- @field DCS#Group.Category category Category of the group. +-- @field #string unittype Type of the first unit of the group as obtained by the Object.getTypeName() DCS API function. +-- @field #WAREHOUSE.Attribute attribute Generalized attribute of the group. ---- Asset descriptor. --- @field Warehouse.AssetDescriptor Assetdescriptor +--- Descriptors enumerator describing the type of the asset in stock. +-- @type WAREHOUSE.Descriptor WAREHOUSE.Descriptor = { TEMPLATENAME="templatename", CATEGORY="category", - + UNITTYPE="unittype", + ATTRIBUTE="attribute", } ---- Warehouse classes. --- @field Warehouse.Class Class -WAREHOUSE.Class = { - TRANSPORT=1, - FIGHTER=2, - TANKER=3, - AWACS=4, - ARTY=5, - ATTACKHELO=6, +--- Warehouse unit categories. These are used for +-- @type WAREHOUSE.Attribute +WAREHOUSE.Attribute = { + TRANSPORT="transport", + FIGHTER="fighter", + TANKER="tanker", + AWACS="awacs", + ARTILLERY="artillery", + ATTACKHELICOPTER="attackhelicopter", + INFANTRY="infantry", + BOMBER="bomber", + TANK="tank", } ---- Warehouse categories --- @field Category -WAREHOUSE.Category = { +--- Cargo transport type. +-- @type WAREHOUSE.TransportType +-- @field #string AIRPLANE plane blabla +WAREHOUSE.TransportType = { AIRPLANE = "plane", HELICOPTER = "helo", - GROUND = "apc", + GROUND = "ground", SHIP = "ship", TRAIN = "train", - SELF = "self", + SELFPROPELLED = "selfporpelled", } --- Warehouse class version. --- @field #number version +-- @field #string version WAREHOUSE.version="0.1.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -164,9 +164,13 @@ function WAREHOUSE:NewAirbase(airbase) -- @function [parent=#WAREHOUSE] Request -- @param #WAREHOUSE self -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. - -- @param #string Asset Asset that is requested. - -- @param #number nAsset Number of assets requested. Default 1. - -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + -- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. + -- @param #depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. + -- @param #number nAsset Number of groups requested that match the asset specification. + -- @param #WAREHOUSE.TransportType TransportType Type of transport. + -- @return boolean If true, request is granted. + -- + -- @usage mywarehouse:Request(AIRBASE:)... --- Triggers the FSM event "Request" after a delay. -- @function [parent=#WAREHOUSE] __Request @@ -221,22 +225,24 @@ end function WAREHOUSE:onafterStatus(From, Event, To) env.info("FF checking warehouse status of airbase "..self.homebase:GetName()) - env.info(string.format("FF warehouse at %s: number of stock = %d", self.homebase:GetName(), #self.stock)) - + --env.info(string.format("FF warehouse at %s: number of stock = %d", self.homebase:GetName(), #self.stock)) + self:_DisplayStockItems(self.stock) self:__Status(30) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + --- On before "Request" event. Checks if the request can be fullfilled. -- @param #WAREHOUSE self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. --- @param #string AssetDescriptor Asset that is requested. Can be "templatename", ... --- @param depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, --- @param #number nAssed Number of groups of that asset requested. --- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" +-- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. +-- @param depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. +-- @param #number nAsset Number of groups requested that match the asset specification. +-- @param #WAREHOUSE.TransportType TransportType Type of transport. -- @return boolean If true, request is granted. -- -- @usage mywarehouse:Request(AIRBASE:)... @@ -244,78 +250,83 @@ function WAREHOUSE:onbeforeRequest(From, Event, To, Airbase, AssetDescriptor, As -- Distance from warehouse to local distance=self.coordinate:Get2DDistance(Airbase:GetCoordinate()) - - -- - local _stockrequest=self._FilterStock(self.stock, AssetDescriptor, AssetDescriptorValue) + + -- Filter the requested assets. + local _stockrequest=self:_FilterStock(self.stock, AssetDescriptor, AssetDescriptorValue) -- Asset is not in stock ==> request denied. - if #_stockrequest==0 then - self:E(self.wid..string.format("Request denied! Asset is currently not in stock.")) + if #_stockrequest < nAsset then + self:E(self.wid..string.format("Request denied! Not enought assets currently in stock. Requested %d < %d in stock.", nAsset, #_stockrequest)) return false end + -- Shortcut local _TT=TransportType:lower() - if _TT==nil then - if AssetDescriptor=="" then - end - end - if TransportType:lower() == "plane" then + if _TT == WAREHOUSE.TransportType.AIRPLANE then + -- here check the availability of transport units! + elseif _TT == WAREHOUSE.TransportType.HELICOPTER then - elseif TransportType:lower() == "helicopter" then + elseif _TT == WAREHOUSE.TransportType.GROUND then - elseif TransportType:lower() == "apc" then + elseif _TT == WAREHOUSE.TransportType.SHIP then - elseif TransportType:lower() == "train" then + elseif _TT == WAREHOUSE.TransportType.TRAIN then - elseif TransportType:lower() == "ship" then - - elseif TransportType:lower() == "self" then + elseif _TT == WAREHOUSE.TransportType.SELFPROPELLED then else self:E(self.wid..string.format("ERROR: unknown transport type requested! type = %s", tostring(TransportType))) end + return true end ---- On after "Request" event. +--- On before "Request" event. Checks if the request can be fullfilled. -- @param #WAREHOUSE self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. --- @param #string Asset Asset that is requested. --- @param #number nAssed Number of groups of that asset requested. --- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" -function WAREHOUSE:onafterRequest(From, Event, To, Airbase, Asset, nAsset, TransportType) - env.info(string.format("FF airbase %s is requesting asset %s from warehouse %s", Airbase:GetName(), Asset, self.homebase:GetName())) +-- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. +-- @param depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. +-- @param #number nAsset Number of groups requested that match the asset specification. +-- @param #WAREHOUSE.TransportType TransportType Type of transport. +-- @return boolean If true, request is granted. +-- +-- @usage mywarehouse:Request(AIRBASE:)... +function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) + env.info(self.wid..string.format("Airbase %s requesting asset %s = %s.", Airbase:GetName(), tostring(AssetDescriptor), tostring(AssetDescriptorValue))) local nAsset=nAsset or 1 - if TransportType=="Air" then + -- Filter the requested assets. + local _stock=self:_FilterStock(self.stock, AssetDescriptor, AssetDescriptorValue) - -- Get a random template from the stock list. - local _chosenone=math.random(#self.stock) --#WAREHOUSE.Stock + -- Get a random template from the stock list. + local _chosenone=math.random(#_stock) - - - -- Select template group name. - --TODO: FILTER HERE! - local template=self.stock[_chosenone].templatename + -- Select template group name. + local template=_stock[_chosenone].templatename + + + if TransportType==WAREHOUSE.TransportType.AIRPLANE then + if template then -- Spawn plane at warehouse homebase. + --TODO: this is wrong. we need to filter the transports and get the right template! local Plane=SPAWN:New(template):SpawnAtAirbase(Airbase, nil, nil, nil, false) if Plane==nil then -- Plane was not spawned correctly. Try again in 60 seconds. - self:__Request( 60, Airbase, Asset, nAsset, TransportType) + self:__Request(60, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) return else - -- Remove chosen plane from list. - table.remove(self.stock,_chosenone) + -- Remove chosen asset from list. + table.remove(self.stock,_stock.pos) end -- New empty cargo set. @@ -354,8 +365,13 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, Asset, nAsset, Trans -- Trigger Delivered event. warehouse:__Delivered(1, group) end - + + else + self:E(self.wid.."ERROR: template does not exist!") end + + else + self:E(self.wid.."ERROR: unknown transport type!") end end @@ -406,25 +422,60 @@ function WAREHOUSE:AddAsset(templategroupname, ngroups, istransport) env.info(string.format("display name = %s", DCSdisplay)) env.info(string.format("category = %s", DCScategory)) env.info(string.format("type = %s", DCStype)) - env.info(string.format("attribute infantry = %s", tostring(group:HasAttribute("Infantry")))) self:E({desc=DCSdesc}) + -- Get generalized attributes. local transport=group:HasAttribute("Transport helicopters") or group:HasAttribute("Transports") or group:HasAttribute("Infantry carriers") local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") local tanker=group:HasAttribute("Tankers") local awacs=group:HasAttribute("AWACS") - local apc=group:HasAttribute("Infantry carriers") local artillery=group:HasAttribute("Artillery") - env.info(string.format("attribute transport = %s", tostring(transport))) - env.info(string.format("attribute apc = %s", tostring(apc))) - env.info(string.format("attribute figther = %s", tostring(fighter))) - env.info(string.format("attribute tanker = %s", tostring(tanker))) - env.info(string.format("attribute awacs = %s", tostring(awacs))) - env.info(string.format("attribute artillery = %s", tostring(artillery))) + local infantry=group:HasAttribute("Infantry") + local attackhelicopter=group:HasAttribute("Attack helicopters") + local bomber=group:HasAttribute("Bombers") + local tank=group:HasAttribute("Old Tanks") or group:HasAttribute("Modern Tanks") + + -- Debug output. + env.info(string.format("attribute transport = %s", tostring(transport))) + env.info(string.format("attribute figther = %s", tostring(fighter))) + env.info(string.format("attribute tanker = %s", tostring(tanker))) + env.info(string.format("attribute awacs = %s", tostring(awacs))) + env.info(string.format("attribute artillery = %s", tostring(artillery))) + env.info(string.format("attribute infantry = %s", tostring(infantry))) + env.info(string.format("attribute attackhelo = %s", tostring(attackhelicopter))) + env.info(string.format("attribute bomber = %s", tostring(bomber))) + env.info(string.format("attribute tank = %s", tostring(tank))) + + + local attribute="unknown" --#WAREHOUSE.Attribute + if transport then + attribute=WAREHOUSE.Attribute.TRANSPORT + elseif fighter then + attribute=WAREHOUSE.Attribute.FIGHTER + elseif tanker then + attribute=WAREHOUSE.Attribute.TANKER + elseif awacs then + attribute=WAREHOUSE.Attribute.AWACS + elseif artillery then + attribute=WAREHOUSE.Attribute.ARTILLERY + elseif infantry then + attribute=WAREHOUSE.Attribute.INFANTRY + elseif attackhelicopter then + attribute=WAREHOUSE.Attribute.ATTACKHELICOPTER + elseif bomber then + attribute=WAREHOUSE.Attribute.BOMBER + elseif tank then + attribute=WAREHOUSE.Attribute.TANK + end -- Add this n times to the table. for i=1,n do - table.insert(self.stock, {templatename=templategroupname, category=DCScategory, type=DCStype, transport=transport, fighther=fighter, tanker=tanker, awacs=awacs, artillery=artillery}) + local stockitem={} --#WAREHOUSE.Stockitem + stockitem.templatename=templategroupname + stockitem.category=DCScategory + stockitem.attribute=attribute + stockitem.unittype=DCStype + table.insert(self.stock, stockitem) end else @@ -441,15 +492,19 @@ end --- Filter stock assets by table entry. -- @param #WAREHOUSE self --- @param #WAREHOUSE.Stock stock +-- @param #table stock Table holding all assets in stock of the warehouse. Each entry is of type @{#WAREHOUSE.Stockitem}. -- @param #string item Descriptor --- @param depends value +-- @param depends value Value of the descriptor. +-- @return #table Filtered stock items table. function WAREHOUSE:_FilterStock(stock, item, value) + -- Filtered array. local filtered={} - for _,_stock in pairs(stock) do + -- Loop over stock items. + for _i,_stock in ipairs(stock) do if _stock[item]==value then + _stock.pos=_i table.insert(filtered, _stock) end end @@ -457,6 +512,21 @@ function WAREHOUSE:_FilterStock(stock, item, value) return filtered end +--- Filter stock assets by table entry. +-- @param #WAREHOUSE self +-- @param #table stock Table holding all assets in stock of the warehouse. Each entry is of type @{#WAREHOUSE.Stockitem}. +function WAREHOUSE:_DisplayStockItems(stock) + + local text=self.wid..string.format("Warehouse %s stock assets:\n", self.homebase:GetName()) + for _,_stock in pairs(stock) do + local mystock=_stock --#WAREHOUSE.Stockitem + text=text..string.format("template = %s, category = %d, unittype = %s, attribute = %s\n", mystock.templatename, mystock.category, mystock.unittype, mystock.attribute) + end + + env.info(text) + MESSAGE:New(text,30):ToAll() +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From f8b1056c9873cda51b9dd0e3acfe5175b51a6fbd Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Thu, 2 Aug 2018 16:35:25 +0200 Subject: [PATCH 08/29] WAREHOUSE --- .../Moose/Functional/Warehouse.lua | 415 ++++++++++++------ Moose Development/Moose/Wrapper/Airbase.lua | 2 +- 2 files changed, 283 insertions(+), 134 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index bb13c9d07..3d90f7c65 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -17,9 +17,13 @@ --- WAREHOUSE class. -- @type WAREHOUSE -- @field #string ClassName Name of the class. +-- @field #boolean Debug If true, send debug messages to all. +-- @field #boolean Report If true, send status messages to coalition. -- @field DCS#Coalition coalition Coalition the warehouse belongs to. --- @field Core.Point#COORDINATE coordinate Coordinate of the warehouse. -- @field Wrapper.Airbase#AIRBASE homebase Airbase the warehouse belongs to. +-- @field Core.Point#COORDINATE coordinate Coordinate of the warehouse. +-- @field Core.Zone#ZONE spawnzone Zone in which assets are spawned. +-- @field #number assetid Unique id of asset items in stock. Essentially a running number starting at one and incremented when a new asset is added. -- @field #table stock Table holding all assets in stock. Table entries are of type @{#WAREHOUSE.Stock}. -- @extends Core.Fsm#FSM @@ -52,14 +56,19 @@ -- @field #WAREHOUSE WAREHOUSE = { ClassName = "WAREHOUSE", + Debug = false, + Report = true, coalition = nil, homebase = nil, coordinate = nil, + spawnzone = nil, + assetid = 0, stock = {}, } --- Item of the warehouse stock table. -- @type WAREHOUSE.Stockitem +-- @field #number id Unique id of the asset. -- @field #string templatename Name of the template group. -- @field DCS#Group.Category category Category of the group. -- @field #string unittype Type of the first unit of the group as obtained by the Object.getTypeName() DCS API function. @@ -68,6 +77,7 @@ WAREHOUSE = { --- Descriptors enumerator describing the type of the asset in stock. -- @type WAREHOUSE.Descriptor WAREHOUSE.Descriptor = { + ID="id", TEMPLATENAME="templatename", CATEGORY="category", UNITTYPE="unittype", @@ -77,7 +87,9 @@ WAREHOUSE.Descriptor = { --- Warehouse unit categories. These are used for -- @type WAREHOUSE.Attribute WAREHOUSE.Attribute = { - TRANSPORT="transport", + TRANSPORT_PLANE="transportplane", + TRANSPORT_HELO="transporthelo", + TRANSPORT_APC="transportapc", FIGHTER="fighter", TANKER="tanker", AWACS="awacs", @@ -86,15 +98,17 @@ WAREHOUSE.Attribute = { INFANTRY="infantry", BOMBER="bomber", TANK="tank", + TRUCK="truck", + OTHER="other", } --- Cargo transport type. -- @type WAREHOUSE.TransportType -- @field #string AIRPLANE plane blabla WAREHOUSE.TransportType = { - AIRPLANE = "plane", - HELICOPTER = "helo", - GROUND = "ground", + AIRPLANE = "transportplane", + HELICOPTER = "transporthelo", + APC = "transportapc", SHIP = "ship", TRAIN = "train", SELFPROPELLED = "selfporpelled", @@ -134,7 +148,14 @@ function WAREHOUSE:NewAirbase(airbase) self.homebase=airbase self.coordinate=airbase:GetCoordinate() self.coalition=airbase:GetCoalition() - + + -- Get the closest point on road. + local _road=self.coordinate:GetClosestPointToRoad():GetVec2() + + -- Define the default spawn zone. + self.spawnzone=ZONE:New("Spawnzone",_road, 200) + + -- Add FSM transitions. self:AddTransition("*", "Start", "Running") self:AddTransition("*", "Status", "*") self:AddTransition("*", "Request", "*") @@ -163,9 +184,12 @@ function WAREHOUSE:NewAirbase(airbase) --- Triggers the FSM event "Request". -- @function [parent=#WAREHOUSE] Request -- @param #WAREHOUSE self + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. -- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. - -- @param #depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. + -- @param AssetDescriptorValue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. -- @param #number nAsset Number of groups requested that match the asset specification. -- @param #WAREHOUSE.TransportType TransportType Type of transport. -- @return boolean If true, request is granted. @@ -175,11 +199,14 @@ function WAREHOUSE:NewAirbase(airbase) --- Triggers the FSM event "Request" after a delay. -- @function [parent=#WAREHOUSE] __Request -- @param #WAREHOUSE self - -- @param #number delay Delay in seconds. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. - -- @param #string Asset Asset that is requested. - -- @param #number nAsset Number of assets requested. Default 1. - -- @param #string TransportType Type of transport: "Plane", "Helicopter", "APC" + -- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. + -- @param AssetDescriptorValue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. + -- @param #number nAsset Number of groups requested that match the asset specification. + -- @param #WAREHOUSE.TransportType TransportType Type of transport. --- Triggers the FSM event "Delivered". -- @function [parent=#WAREHOUSE] Delivered @@ -240,14 +267,16 @@ end -- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. -- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. --- @param depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. +-- @param AssetDescriptorValue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. -- @param #number nAsset Number of groups requested that match the asset specification. -- @param #WAREHOUSE.TransportType TransportType Type of transport. --- @return boolean If true, request is granted. --- --- @usage mywarehouse:Request(AIRBASE:)... +-- @return #boolean If true, request is granted. function WAREHOUSE:onbeforeRequest(From, Event, To, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) + -- Default. + nAsset=nAsset or 1 + TransportType=TransportType or WAREHOUSE.TransportType.SELFPROPELLED + -- Distance from warehouse to local distance=self.coordinate:Get2DDistance(Airbase:GetCoordinate()) @@ -256,120 +285,177 @@ function WAREHOUSE:onbeforeRequest(From, Event, To, Airbase, AssetDescriptor, As -- Asset is not in stock ==> request denied. if #_stockrequest < nAsset then - self:E(self.wid..string.format("Request denied! Not enought assets currently in stock. Requested %d < %d in stock.", nAsset, #_stockrequest)) + local text=string.format("Request denied! Not enought assets currently in stock. Requested %d < %d in stock.", nAsset, #_stockrequest) + MESSAGE:New(text, 10):ToCoalitionIf(self.coalition, self.Report or self.Debug) + self:E(self.wid..text) return false end + -- Get the attibute of the requested asset. + local _stockitem=_stockrequest[1] --#WAREHOUSE.Stockitem + local _assetattribute=self:_GetAttribute(_stockitem.templatename) + + --if _assetattribute==WAREHOUSE.Attribute. + -- Shortcut local _TT=TransportType:lower() + local _instock + -- Check the availability of transport units. if _TT == WAREHOUSE.TransportType.AIRPLANE then - -- here check the availability of transport units! + _instock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.TRANSPORT_PLANE) elseif _TT == WAREHOUSE.TransportType.HELICOPTER then - + _instock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.TRANSPORT_HELO) elseif _TT == WAREHOUSE.TransportType.GROUND then - + _instock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.TRANSPORT_APC) elseif _TT == WAREHOUSE.TransportType.SHIP then - + _instock=0 elseif _TT == WAREHOUSE.TransportType.TRAIN then - + _instock=0 elseif _TT == WAREHOUSE.TransportType.SELFPROPELLED then - + _instock=_stockrequest else self:E(self.wid..string.format("ERROR: unknown transport type requested! type = %s", tostring(TransportType))) + return false end + + if #_instock==0 then + local text=string.format("Request denied! No transport unit currently available.") + MESSAGE:New(text, 10):ToCoalitionIf(self.coalition, self.Report or self.Debug) + self:E(self.wid..text) + return false + end + return true end ---- On before "Request" event. Checks if the request can be fullfilled. +--- On after "Request" event. Initiates the transport of the assets to the requesting airbase. -- @param #WAREHOUSE self -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. -- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. --- @param depends AssetDescriptorvalue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. +-- @param AssetDescriptorValue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. -- @param #number nAsset Number of groups requested that match the asset specification. -- @param #WAREHOUSE.TransportType TransportType Type of transport. --- @return boolean If true, request is granted. --- --- @usage mywarehouse:Request(AIRBASE:)... function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) env.info(self.wid..string.format("Airbase %s requesting asset %s = %s.", Airbase:GetName(), tostring(AssetDescriptor), tostring(AssetDescriptorValue))) - local nAsset=nAsset or 1 - -- Filter the requested assets. - local _stock=self:_FilterStock(self.stock, AssetDescriptor, AssetDescriptorValue) + local _assetstock=self:_FilterStock(self.stock, AssetDescriptor, AssetDescriptorValue) -- Get a random template from the stock list. - local _chosenone=math.random(#_stock) + local _chosenone=math.random(#_assetstock) - -- Select template group name. - local template=_stock[_chosenone].templatename + -- Select asset template group name. + local assettemplate=_assetstock[_chosenone].templatename + + + -- New empty cargo set. + local CargoGroups = SET_CARGO:New() + + -- Spawn the assets. + local _delid={} + for i=1,nAsset do + + -- Get stock item. + local _assetitem=_assetstock[i] --#WAREHOUSE.Stockitem + table.insert(_delid,_assetitem.id) + + -- Spawn group in spawn zone. + local spawn=SPAWN(_assetitem.templatename) + local spawngroup=spawn:SpawnFromVec3(self.spawnzone:GetRandomPointVec3()) + + -- Add spawned group to cargo group object. + --TODO: check near and load radius. + local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) + CargoGroups:AddCargo(cargogroup) + end + + -- Delete spawned items from warehouse stock. + for _,_id in pairs(_delid) do + self:_DeleteStockItem(_id) + end + + --[[ + -- Spawn requested assets. + local spawn=SPAWN:New("Infantry Platoon Alpha") + self.homebase:GetZone():GetRandomCoordinate(inner,outer) + local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) + for i=1,nAsset do + local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) + local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) + CargoGroups:AddCargo(cargogroup) + end + ]] + + + -- Filter the requested assets. + local _transportstock + local _transportitem --#WAREHOUSE.Stockitem + if TransportType~=WAREHOUSE.TransportType.SELFPROPELLED then + _transportstock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, TransportType) + _chosenone=math.random(#_transportstock) + -- Select asset template group name. + _transportitem=_transportstock[_chosenone] + end if TransportType==WAREHOUSE.TransportType.AIRPLANE then - - - if template then - -- Spawn plane at warehouse homebase. - --TODO: this is wrong. we need to filter the transports and get the right template! - local Plane=SPAWN:New(template):SpawnAtAirbase(Airbase, nil, nil, nil, false) - - if Plane==nil then - -- Plane was not spawned correctly. Try again in 60 seconds. - self:__Request(60, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) - return - else - -- Remove chosen asset from list. - table.remove(self.stock,_stock.pos) - end - - -- New empty cargo set. - local CargoGroups = SET_CARGO:New() - - -- Spawn requested assets. - local spawn=SPAWN:New("Infantry Platoon Alpha") - - for i=1,nAsset do - local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) - local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) - CargoGroups:AddCargo(cargogroup) - end - - -- Define cargo airplane. - local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) - - -- Pickup cargo at homebase. - CargoPlane:__Pickup(5, self.homebase) - - -- Set warehouse state so that we can retreive it later. - Plane:SetState(Plane, "WAREHOUSE", self) - - --- Once the cargo was loaded start off to deploy airbase. - function CargoPlane:OnAfterLoaded(Airplane, From, Event, To) - CargoPlane:__Deploy(10, Airbase, 500) - end - - --- Function called when cargo has arrived and was unloaded. - function CargoPlane:OnAfterUnloaded(Airplane, From, Event, To) - - local group=CargoPlane.Cargo:GetObject() - local Airplane=Airplane --Wrapper.Group#GROUP - local warehouse=Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE - - -- Trigger Delivered event. - warehouse:__Delivered(1, group) - end - + -- Spawn plane at warehouse homebase. + --TODO: Check available parking spots in onbefore! + local Plane=SPAWN:New(_transportitem.templatename):SpawnAtAirbase(Airbase, SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.OpenBig, false) + + if Plane==nil then + -- Plane was not spawned correctly. Try again in 60 seconds. + local text="Technical problems with the transport plane occurred. Request was cancelled! Try again later." + --self:__Request(60, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) + --TODO: despawn units and but them back into the warehouse. + return else - self:E(self.wid.."ERROR: template does not exist!") + -- Remove chosen transport asset from list. + self:_DeleteStockItem() end + -- Define cargo airplane. + local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) + + -- Pickup cargo at homebase. + CargoPlane:__Pickup(5, self.homebase) + + -- Set warehouse state so that we can retreive it later. + Plane:SetState(Plane, "WAREHOUSE", self) + + --- Once the cargo was loaded start off to deploy airbase. + function CargoPlane:OnAfterLoaded(Airplane, From, Event, To) + CargoPlane:__Deploy(10, Airbase, 500) + end + + --- Function called when cargo has arrived and was unloaded. + function CargoPlane:OnAfterUnloaded(Airplane, From, Event, To) + + local group=CargoPlane.Cargo:GetObject() + local Airplane=Airplane --Wrapper.Group#GROUP + local warehouse=Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE + + -- Trigger Delivered event. + warehouse:__Delivered(1, group) + end + + elseif TransportType==WAREHOUSE.TransportType.HELICOPTER then + + elseif TransportType==WAREHOUSE.TransportType.APC then + + elseif TransportType==WAREHOUSE.TransportType.TRAIN then + + elseif TransportType==WAREHOUSE.TransportType.SHIP then + + elseif TransportType==WAREHOUSE.TransportType.SELFPROPELLED then + else self:E(self.wid.."ERROR: unknown transport type!") end @@ -405,6 +491,7 @@ end -- @return #WAREHOUSE self function WAREHOUSE:AddAsset(templategroupname, ngroups, istransport) + -- Set default. local n=ngroups or 1 local group=GROUP:FindByName(templategroupname) @@ -424,57 +511,17 @@ function WAREHOUSE:AddAsset(templategroupname, ngroups, istransport) env.info(string.format("type = %s", DCStype)) self:E({desc=DCSdesc}) - -- Get generalized attributes. - local transport=group:HasAttribute("Transport helicopters") or group:HasAttribute("Transports") or group:HasAttribute("Infantry carriers") - local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") - local tanker=group:HasAttribute("Tankers") - local awacs=group:HasAttribute("AWACS") - local artillery=group:HasAttribute("Artillery") - local infantry=group:HasAttribute("Infantry") - local attackhelicopter=group:HasAttribute("Attack helicopters") - local bomber=group:HasAttribute("Bombers") - local tank=group:HasAttribute("Old Tanks") or group:HasAttribute("Modern Tanks") - - -- Debug output. - env.info(string.format("attribute transport = %s", tostring(transport))) - env.info(string.format("attribute figther = %s", tostring(fighter))) - env.info(string.format("attribute tanker = %s", tostring(tanker))) - env.info(string.format("attribute awacs = %s", tostring(awacs))) - env.info(string.format("attribute artillery = %s", tostring(artillery))) - env.info(string.format("attribute infantry = %s", tostring(infantry))) - env.info(string.format("attribute attackhelo = %s", tostring(attackhelicopter))) - env.info(string.format("attribute bomber = %s", tostring(bomber))) - env.info(string.format("attribute tank = %s", tostring(tank))) - - - local attribute="unknown" --#WAREHOUSE.Attribute - if transport then - attribute=WAREHOUSE.Attribute.TRANSPORT - elseif fighter then - attribute=WAREHOUSE.Attribute.FIGHTER - elseif tanker then - attribute=WAREHOUSE.Attribute.TANKER - elseif awacs then - attribute=WAREHOUSE.Attribute.AWACS - elseif artillery then - attribute=WAREHOUSE.Attribute.ARTILLERY - elseif infantry then - attribute=WAREHOUSE.Attribute.INFANTRY - elseif attackhelicopter then - attribute=WAREHOUSE.Attribute.ATTACKHELICOPTER - elseif bomber then - attribute=WAREHOUSE.Attribute.BOMBER - elseif tank then - attribute=WAREHOUSE.Attribute.TANK - end + local attribute=self:_GetAttribute(templategroupname) -- Add this n times to the table. for i=1,n do local stockitem={} --#WAREHOUSE.Stockitem + self.assetid=self.assetid+1 + stockitem.id=self.assetid stockitem.templatename=templategroupname stockitem.category=DCScategory - stockitem.attribute=attribute stockitem.unittype=DCStype + stockitem.attribute=attribute table.insert(self.stock, stockitem) end @@ -494,7 +541,7 @@ end -- @param #WAREHOUSE self -- @param #table stock Table holding all assets in stock of the warehouse. Each entry is of type @{#WAREHOUSE.Stockitem}. -- @param #string item Descriptor --- @param depends value Value of the descriptor. +-- @param value Value of the descriptor. -- @return #table Filtered stock items table. function WAREHOUSE:_FilterStock(stock, item, value) @@ -524,7 +571,109 @@ function WAREHOUSE:_DisplayStockItems(stock) end env.info(text) - MESSAGE:New(text,30):ToAll() + MESSAGE:New(text, 10):ToAll() +end + +--- Check if a group has a generalized attribute. +-- @param #WAREHOUSE self +-- @param #string groupname Name of the group. +-- @param #WAREHOUSE.Attribute attribute Attribute to check. +-- @return #boolean True if group has the specified attribute. +function WAREHOUSE:_HasAttribute(groupname, attribute) + + local group=GROUP:FindByName(groupname) + + if group then + local groupattribute=self:_HasAttribute(groupname,attribute) + return groupattribute==attribute + end + + return false +end + +--- Get the generalized attribute of a group. +-- @param #WAREHOUSE self +-- @param #string groupname Name of the group. +-- @return #WAREHOUSE.Attribute Generalized attribute of the group. +function WAREHOUSE:_GetAttribute(groupname) + + local group=GROUP:FindByName(groupname) + + local attribute=WAREHOUSE.Attribute.OTHER --#WAREHOUSE.Attribute + + if group then + + -- Get generalized attributes. + -- Transports: Helos, planes and APCs + local transportplane=group:HasAttribute("Transports") and group:HasAttribute("Planes") + local transporthelo=group:HasAttribute("Transport helicopters") + local transportapc=group:HasAttribute("Infantry carriers") + local fighter=group:HasAttribute("Fighters") or group:HasAttribute("Interceptors") or group:HasAttribute("Multirole fighters") + local tanker=group:HasAttribute("Tankers") + local awacs=group:HasAttribute("AWACS") + local artillery=group:HasAttribute("Artillery") + local infantry=group:HasAttribute("Infantry") + local attackhelicopter=group:HasAttribute("Attack helicopters") + local bomber=group:HasAttribute("Bombers") + local tank=group:HasAttribute("Old Tanks") or group:HasAttribute("Modern Tanks") + local truck=group:HasAttribute("Trucks") + + -- Debug output. + env.info(string.format("transport pane = %s", tostring(transportplane))) + env.info(string.format("transport helo = %s", tostring(transporthelo))) + env.info(string.format("transport apc = %s", tostring(transportapc))) + env.info(string.format("figther = %s", tostring(fighter))) + env.info(string.format("tanker = %s", tostring(tanker))) + env.info(string.format("awacs = %s", tostring(awacs))) + env.info(string.format("artillery = %s", tostring(artillery))) + env.info(string.format("infantry = %s", tostring(infantry))) + env.info(string.format("attack helo = %s", tostring(attackhelicopter))) + env.info(string.format("bomber = %s", tostring(bomber))) + env.info(string.format("tank = %s", tostring(tank))) + env.info(string.format("truck = %s", tostring(truck))) + + if transportplane then + attribute=WAREHOUSE.Attribute.TRANSPORT_PLANE + elseif transporthelo then + attribute=WAREHOUSE.Attribute.TRANSPORT_HELO + elseif transportapc then + attribute=WAREHOUSE.Attribute.TRANSPORT_APC + elseif fighter then + attribute=WAREHOUSE.Attribute.FIGHTER + elseif tanker then + attribute=WAREHOUSE.Attribute.TANKER + elseif awacs then + attribute=WAREHOUSE.Attribute.AWACS + elseif artillery then + attribute=WAREHOUSE.Attribute.ARTILLERY + elseif infantry then + attribute=WAREHOUSE.Attribute.INFANTRY + elseif attackhelicopter then + attribute=WAREHOUSE.Attribute.ATTACKHELICOPTER + elseif bomber then + attribute=WAREHOUSE.Attribute.BOMBER + elseif tank then + attribute=WAREHOUSE.Attribute.TANK + elseif truck then + attribute=WAREHOUSE.Attribute.TRUCK + else + attribute=WAREHOUSE.Attribute.OTHER + end + + end + + return attribute +end + +--- Delete item from stock. +-- @param #WAREHOUSE self +-- @param #number uid The id of the item to be deleted. +function WAREHOUSE:_DeleteStockItem(uid) + for _i,_item in pairs(self.stock) do + if _item.id==uid then + self.stock[_i]=nil + end + end end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 9c32fb42c..ed6f169d5 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -349,7 +349,7 @@ function AIRBASE.GetAllAirbases(coalition) local airbases={} for _,airbase in pairs(_DATABASE.AIRBASES) do - if (coalition~=nil and self:GetCoalition()==coalition) or coalition==nil then + if (coalition~=nil and airbase:GetCoalition()==coalition) or coalition==nil then table.insert(airbases, airbase) end end From 4a424dd3d8dab18cfe57a0a812af863597a2da70 Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Fri, 3 Aug 2018 00:01:41 +0200 Subject: [PATCH 09/29] WAREHOUSE --- .../Moose/AI/AI_Cargo_Airplane.lua | 5 +- .../Moose/Functional/Warehouse.lua | 146 ++++++++++++------ 2 files changed, 99 insertions(+), 52 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index b1422cb11..f1fdfab54 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -274,7 +274,8 @@ end -- @param Wrapper.Point#COORDINATE Coordinate function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) - if Airplane and Airplane:IsAlive() then + if Airplane and Airplane:IsAlive()==true or Airplane:IsAlive()==false then + --if Airplane then for _, Cargo in pairs( self.CargoSet:GetSet() ) do local Cargo=Cargo --Cargo.Cargo#CARGO @@ -472,6 +473,8 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed ) self:T3( Points ) Template.route.points = Points + + Template.uncontrolled=false --self:Respawn( Template ) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 3d90f7c65..6c983738a 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -22,7 +22,8 @@ -- @field DCS#Coalition coalition Coalition the warehouse belongs to. -- @field Wrapper.Airbase#AIRBASE homebase Airbase the warehouse belongs to. -- @field Core.Point#COORDINATE coordinate Coordinate of the warehouse. --- @field Core.Zone#ZONE spawnzone Zone in which assets are spawned. +-- @field Core.Zone#ZONE spawnzone Zone in which assets are spawned. +-- @field #number markerid ID of the warehouse marker at the airbase. -- @field #number assetid Unique id of asset items in stock. Essentially a running number starting at one and incremented when a new asset is added. -- @field #table stock Table holding all assets in stock. Table entries are of type @{#WAREHOUSE.Stock}. -- @extends Core.Fsm#FSM @@ -62,6 +63,7 @@ WAREHOUSE = { homebase = nil, coordinate = nil, spawnzone = nil, + markerid = nil, assetid = 0, stock = {}, } @@ -153,7 +155,9 @@ function WAREHOUSE:NewAirbase(airbase) local _road=self.coordinate:GetClosestPointToRoad():GetVec2() -- Define the default spawn zone. - self.spawnzone=ZONE:New("Spawnzone",_road, 200) + self.spawnzone=ZONE_RADIUS:New("Spawnzone",_road, 200) + self.spawnzone:BoundZone(60,country.id.GERMANY) + self.spawnzone:GetCoordinate():MarkToAll("Spawnzone") -- Add FSM transitions. self:AddTransition("*", "Start", "Running") @@ -232,14 +236,15 @@ end -- @param #string Event Event. -- @param #string To To state. function WAREHOUSE:onafterStart(From, Event, To) - env.info("FF starting warehouse at airbase "..self.homebase:GetName()) + self:E(self.wid..string.format("Starting warehouse at airbase %s.", self.homebase:GetName())) -- handle events -- event takeoff -- event landing -- event crash/dead -- event base captured - self:__Status(-5) + + self:__Status(5) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -250,10 +255,32 @@ end -- @param #string Event Event. -- @param #string To To state. function WAREHOUSE:onafterStatus(From, Event, To) - env.info("FF checking warehouse status of airbase "..self.homebase:GetName()) + self:E(self.wid..string.format("Checking warehouse status of airbase %s", self.homebase:GetName())) - --env.info(string.format("FF warehouse at %s: number of stock = %d", self.homebase:GetName(), #self.stock)) - self:_DisplayStockItems(self.stock) + -- Create a mark with the current assets in stock. + if self.markerid~=nil then + trigger.action.removeMark(self.markerid) + end + local marktext="Warehouse stock:\n" + local text="Warehouse stock:\n" + + local _data=self:GetStockInfo(self.stock) + for _attribute,_count in pairs(_data) do + marktext=marktext..string.format("%s=%d, ", _attribute,_count) -- Dont use \n because too many make DCS crash! + text=text..string.format("%s = %d\n", _attribute,_count) + end + self.markerid=self.coordinate:MarkToCoalition(marktext, self.coalition, true) + + -- Debug output. + self:E(self.wid..text) + MESSAGE:New(text, 10):ToAllIf(self.Debug) + + -- Display complete list of stock itmes. + if self.Debug then + --self:_DisplayStockItems(self.stock) + end + + -- Call status again in 30 sec. self:__Status(30) end @@ -272,7 +299,8 @@ end -- @param #WAREHOUSE.TransportType TransportType Type of transport. -- @return #boolean If true, request is granted. function WAREHOUSE:onbeforeRequest(From, Event, To, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) - + env.info(self.wid..string.format("Airbase %s requesting asset %s = %s.", Airbase:GetName(), tostring(AssetDescriptor), tostring(AssetDescriptorValue))) + -- Default. nAsset=nAsset or 1 TransportType=TransportType or WAREHOUSE.TransportType.SELFPROPELLED @@ -294,13 +322,11 @@ function WAREHOUSE:onbeforeRequest(From, Event, To, Airbase, AssetDescriptor, As -- Get the attibute of the requested asset. local _stockitem=_stockrequest[1] --#WAREHOUSE.Stockitem local _assetattribute=self:_GetAttribute(_stockitem.templatename) - - --if _assetattribute==WAREHOUSE.Attribute. - + -- Shortcut - local _TT=TransportType:lower() - local _instock + local _instock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, TransportType) + --[[ -- Check the availability of transport units. if _TT == WAREHOUSE.TransportType.AIRPLANE then _instock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, WAREHOUSE.Attribute.TRANSPORT_PLANE) @@ -318,15 +344,16 @@ function WAREHOUSE:onbeforeRequest(From, Event, To, Airbase, AssetDescriptor, As self:E(self.wid..string.format("ERROR: unknown transport type requested! type = %s", tostring(TransportType))) return false end + ]] - if #_instock==0 then + -- Check that a transport unit is available. + if #_instock==0 and TransportType~=WAREHOUSE.TransportType.SELFPROPELLED then local text=string.format("Request denied! No transport unit currently available.") MESSAGE:New(text, 10):ToCoalitionIf(self.coalition, self.Report or self.Debug) self:E(self.wid..text) return false end - return true end @@ -343,54 +370,43 @@ end -- @param #WAREHOUSE.TransportType TransportType Type of transport. function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, AssetDescriptorValue, nAsset, TransportType) env.info(self.wid..string.format("Airbase %s requesting asset %s = %s.", Airbase:GetName(), tostring(AssetDescriptor), tostring(AssetDescriptorValue))) - + + -- Filter the requested assets. local _assetstock=self:_FilterStock(self.stock, AssetDescriptor, AssetDescriptorValue) - -- Get a random template from the stock list. - local _chosenone=math.random(#_assetstock) - - -- Select asset template group name. - local assettemplate=_assetstock[_chosenone].templatename - - -- New empty cargo set. local CargoGroups = SET_CARGO:New() - + -- Spawn the assets. local _delid={} + local _spawngroups={} for i=1,nAsset do -- Get stock item. local _assetitem=_assetstock[i] --#WAREHOUSE.Stockitem table.insert(_delid,_assetitem.id) - -- Spawn group in spawn zone. - local spawn=SPAWN(_assetitem.templatename) - local spawngroup=spawn:SpawnFromVec3(self.spawnzone:GetRandomPointVec3()) - - -- Add spawned group to cargo group object. - --TODO: check near and load radius. - local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) - CargoGroups:AddCargo(cargogroup) + -- Find a random point within the spawn zone. + local spawnvec3=self.spawnzone:GetRandomVec3() + local spawncoord=COORDINATE:NewFromVec3(spawnvec3) + spawncoord:MarkToAll(string.format("spawnpoint %d",i)) + + -- Spawn with ALIAS here or DCS crashes! + _spawngroups[i]=SPAWN:NewWithAlias(_assetitem.templatename,string.format("%s_%d", _assetitem.templatename,i)):SpawnFromVec3(spawnvec3) end + -- Add spawned groups to cargo group object. + for _i,_spawngroup in pairs(_spawngroups) do + --TODO: check near and load radius. + local cargogroup = CARGO_GROUP:New(_spawngroup, AssetDescriptorValue, string.format("%s %d",AssetDescriptorValue, _i), 5000, 35) + CargoGroups:AddCargo(cargogroup) + end + -- Delete spawned items from warehouse stock. for _,_id in pairs(_delid) do - self:_DeleteStockItem(_id) + self:_DeleteStockItem(_id) end - - --[[ - -- Spawn requested assets. - local spawn=SPAWN:New("Infantry Platoon Alpha") - self.homebase:GetZone():GetRandomCoordinate(inner,outer) - local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) - for i=1,nAsset do - local spawngroup=spawn:SpawnFromVec3(self.homebase:GetZone():GetRandomPointVec3(100,500)) - local cargogroup = CARGO_GROUP:New(spawngroup, "Infantry", string.format( "Infantry Platoon %d", i), 5000, 35) - CargoGroups:AddCargo(cargogroup) - end - ]] -- Filter the requested assets. @@ -398,7 +414,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass local _transportitem --#WAREHOUSE.Stockitem if TransportType~=WAREHOUSE.TransportType.SELFPROPELLED then _transportstock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, TransportType) - _chosenone=math.random(#_transportstock) + local _chosenone=math.random(#_transportstock) -- Select asset template group name. _transportitem=_transportstock[_chosenone] end @@ -408,7 +424,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass -- Spawn plane at warehouse homebase. --TODO: Check available parking spots in onbefore! - local Plane=SPAWN:New(_transportitem.templatename):SpawnAtAirbase(Airbase, SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.OpenBig, false) + local Plane=SPAWN:New(_transportitem.templatename):InitUnControlled(true):SpawnAtAirbase(self.homebase, SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.OpenBig, false) if Plane==nil then -- Plane was not spawned correctly. Try again in 60 seconds. @@ -421,11 +437,14 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass self:_DeleteStockItem() end - -- Define cargo airplane. + -- Define cargo airplane object. local CargoPlane = AI_CARGO_AIRPLANE:New(Plane, CargoGroups) + CargoPlane.Airbase=self.homebase -- Pickup cargo at homebase. - CargoPlane:__Pickup(5, self.homebase) + --CargoPlane:Pickup(self.homebase) + --CargoPlane:__Landed(1) + CargoPlane:__Load(1, Plane:GetCoordinate()) -- Set warehouse state so that we can retreive it later. Plane:SetState(Plane, "WAREHOUSE", self) @@ -618,7 +637,8 @@ function WAREHOUSE:_GetAttribute(groupname) local tank=group:HasAttribute("Old Tanks") or group:HasAttribute("Modern Tanks") local truck=group:HasAttribute("Trucks") - -- Debug output. + -- Debug output. + --[[ env.info(string.format("transport pane = %s", tostring(transportplane))) env.info(string.format("transport helo = %s", tostring(transporthelo))) env.info(string.format("transport apc = %s", tostring(transportapc))) @@ -631,7 +651,8 @@ function WAREHOUSE:_GetAttribute(groupname) env.info(string.format("bomber = %s", tostring(bomber))) env.info(string.format("tank = %s", tostring(tank))) env.info(string.format("truck = %s", tostring(truck))) - + ]] + if transportplane then attribute=WAREHOUSE.Attribute.TRANSPORT_PLANE elseif transporthelo then @@ -665,6 +686,29 @@ function WAREHOUSE:_GetAttribute(groupname) return attribute end +--- Returns the number of assets for each generalized attribute. +-- @param #WAREHOUSE self +-- @param #table stock The stock of the warehouse. +-- @return #table Data table holding the numbers. +function WAREHOUSE:GetStockInfo(stock) + + local _data={} + for _j,_attribute in pairs(WAREHOUSE.Attribute) do + + local n=0 + for _i,_item in pairs(stock) do + local _ite=_item --#WAREHOUSE.Stockitem + if _ite.attribute==_attribute then + n=n+1 + end + end + + _data[_attribute]=n + end + + return _data +end + --- Delete item from stock. -- @param #WAREHOUSE self -- @param #number uid The id of the item to be deleted. From 77f78260843eb8a0854ae8b339279e8dce50a9aa Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Fri, 3 Aug 2018 16:02:16 +0200 Subject: [PATCH 10/29] WAREHOUSE --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 4 +- .../Moose/AI/AI_Cargo_Helicopter.lua | 23 ++-- .../Moose/Functional/Warehouse.lua | 118 +++++++++++++++--- 3 files changed, 117 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index a69f0aa27..13f88324e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -139,7 +139,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) -- @function [parent=#AI_CARGO_APC] __Pickup -- @param #AI_CARGO_APC self -- @param #number Delay - -- @param Core.Point#COORDINATE Coordinate + -- @param Core.Point#COORDINATE Coordinate Pickup place. If not given, loading starts at the current location. -- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do. --- Deploy Handler OnBefore for AI_CARGO_APC @@ -170,8 +170,8 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) --- Deploy Asynchronous Trigger for AI_CARGO_APC -- @function [parent=#AI_CARGO_APC] __Deploy -- @param #AI_CARGO_APC self - -- @param Core.Point#COORDINATE Coordinate -- @param #number Delay + -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do. diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 7a272178a..54d2050c8 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -73,17 +73,20 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- @param #string Event -- @param #string To -- @param Core.Point#COORDINATE Coordinate + -- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. --- Pickup Trigger for AI_CARGO_HELICOPTER -- @function [parent=#AI_CARGO_HELICOPTER] Pickup -- @param #AI_CARGO_HELICOPTER self -- @param Core.Point#COORDINATE Coordinate + -- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. --- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER -- @function [parent=#AI_CARGO_HELICOPTER] __Pickup -- @param #AI_CARGO_HELICOPTER self - -- @param #number Delay + -- @param #number Delay Delay in seconds. -- @param Core.Point#COORDINATE Coordinate + -- @param #number Speed Speed in km/h to go to the pickup coordinate. Default is 50% of max possible speed the unit can go. --- Deploy Handler OnBefore for AI_CARGO_HELICOPTER -- @function [parent=#AI_CARGO_HELICOPTER] OnBeforeDeploy @@ -91,7 +94,8 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- @param #string From -- @param #string Event -- @param #string To - -- @param Core.Point#COORDINATE Coordinate + -- @param Core.Point#COORDINATE Coordinate Place at which cargo is deployed. + -- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. -- @return #boolean --- Deploy Handler OnAfter for AI_CARGO_HELICOPTER @@ -101,18 +105,21 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) -- @param #string Event -- @param #string To -- @param Core.Point#COORDINATE Coordinate + -- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. --- Deploy Trigger for AI_CARGO_HELICOPTER -- @function [parent=#AI_CARGO_HELICOPTER] Deploy -- @param #AI_CARGO_HELICOPTER self - -- @param Core.Point#COORDINATE Coordinate + -- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed. + -- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. --- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER -- @function [parent=#AI_CARGO_HELICOPTER] __Deploy + -- @param #number Delay Delay in seconds. -- @param #AI_CARGO_HELICOPTER self - -- @param Core.Point#COORDINATE Coordinate - -- @param #number Delay - + -- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed. + -- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. + -- We need to capture the Crash events for the helicopters. -- The helicopter reference is used in the semaphore AI_CARGO_QUEUE. @@ -632,11 +639,11 @@ end --- On after Deploy event. -- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Group#GROUP Helicopter +-- @param Wrapper.Group#GROUP Helicopter Transport helicopter. -- @param From -- @param Event -- @param To --- @param Core.Point#COORDINATE Coordinate +-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed. -- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go. function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed ) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 6c983738a..48d365019 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -124,7 +124,13 @@ WAREHOUSE.version="0.1.0" -- TODO: Warehuse todo list. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- TODO: A lot! +-- TODO: Add event handlers. +-- TODO: Add AI_APC +-- TODO: Add AI_HELICOPTER +-- TODO: Write documentation. +-- TODO: Put active groups into the warehouse. +-- TODO: Spawn warehouse assets as uncontrolled or AI off and activate them when requested. +-- TODO: Handle cases with immobile units. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor(s) @@ -388,32 +394,46 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass table.insert(_delid,_assetitem.id) -- Find a random point within the spawn zone. - local spawnvec3=self.spawnzone:GetRandomVec3() - local spawncoord=COORDINATE:NewFromVec3(spawnvec3) + --local spawnvec3=self.spawnzone:GetRandomVec3 + local spawncoord=self.spawnzone:GetRandomCoordinate() spawncoord:MarkToAll(string.format("spawnpoint %d",i)) -- Spawn with ALIAS here or DCS crashes! - _spawngroups[i]=SPAWN:NewWithAlias(_assetitem.templatename,string.format("%s_%d", _assetitem.templatename,i)):SpawnFromVec3(spawnvec3) + _spawngroups[i]=SPAWN:NewWithAlias(_assetitem.templatename,string.format("%s_%d", _assetitem.templatename,i)):SpawnFromCoordinate(spawncoord) --:SpawnFromVec3(spawnvec3) end - - -- Add spawned groups to cargo group object. - for _i,_spawngroup in pairs(_spawngroups) do - --TODO: check near and load radius. - local cargogroup = CARGO_GROUP:New(_spawngroup, AssetDescriptorValue, string.format("%s %d",AssetDescriptorValue, _i), 5000, 35) - CargoGroups:AddCargo(cargogroup) - end - + -- Delete spawned items from warehouse stock. for _,_id in pairs(_delid) do self:_DeleteStockItem(_id) end + if TransportType==WAREHOUSE.TransportType.SELFPROPELLED then + for _i,_spawngroup in pairs(_spawngroups) do + local group=_spawngroup --Wrapper.Group#GROUP + local ToCoordinate=Airbase:GetZone():GetRandomCoordinate() + group:RouteGroundOnRoad(ToCoordinate) + end + end + + + --TODO: naje nearradius depended on types. + local _loadradius=5000 + local _nearradius=35 + + -- Add spawned groups to cargo group object. + for _i,_spawngroup in pairs(_spawngroups) do + --TODO: check near and load radius. + local cargogroup = CARGO_GROUP:New(_spawngroup, AssetDescriptorValue, string.format("%s %d",AssetDescriptorValue, _i), _loadradius, _nearradius) + CargoGroups:AddCargo(cargogroup) + end + + + -- Filter the requested assets. - local _transportstock local _transportitem --#WAREHOUSE.Stockitem - if TransportType~=WAREHOUSE.TransportType.SELFPROPELLED then - _transportstock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, TransportType) + if TransportType ~= WAREHOUSE.TransportType.SELFPROPELLED then + local _transportstock=self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, TransportType) local _chosenone=math.random(#_transportstock) -- Select asset template group name. _transportitem=_transportstock[_chosenone] @@ -434,7 +454,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass return else -- Remove chosen transport asset from list. - self:_DeleteStockItem() + self:_DeleteStockItem(_transportitem.id) end -- Define cargo airplane object. @@ -442,8 +462,6 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass CargoPlane.Airbase=self.homebase -- Pickup cargo at homebase. - --CargoPlane:Pickup(self.homebase) - --CargoPlane:__Landed(1) CargoPlane:__Load(1, Plane:GetCoordinate()) -- Set warehouse state so that we can retreive it later. @@ -467,11 +485,75 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass elseif TransportType==WAREHOUSE.TransportType.HELICOPTER then + local Helo=SPAWN:New(_transportitem.templatename):SpawnAtAirbase(self.homebase, SPAWN.Takeoff.Cold, nil, AIRBASE.TerminalType.HelicopterUsable, false) + + if Helo==nil then + -- Plane was not spawned correctly. Try again in 60 seconds. + local text="Technical problems with the transport helicopter occurred. Request was cancelled! Try again later." + return + else + -- Remove chosen transport asset from list. + self:_DeleteStockItem(_transportitem.id) + end + + -- Define cargo airplane object. + local CargoHelo = AI_CARGO_HELICOPTER:New(Helo, CargoGroups) + + -- Pickup cargo from the spawn zone. + CargoHelo:__Pickup(5, self.spawnzone:GetCoordinate()) + + --- Once the cargo was loaded start off to deploy airbase. + function CargoHelo:OnAfterLoaded(Carrier, From, Event, To) + CargoHelo:__Deploy(10, Airbase:GetZone():GetRandomCoordinate()) + end + + --- Function called when cargo has arrived and was unloaded. + function CargoHelo:OnAfterUnloaded(Airplane, From, Event, To) + + local group=CargoHelo.Cargo:GetObject() + local Airplane=Airplane --Wrapper.Group#GROUP + local warehouse=Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE + + -- Trigger Delivered event. + warehouse:__Delivered(1, group) + end + + elseif TransportType==WAREHOUSE.TransportType.APC then + + -- Spawn APC in spawn zone. + local APC=SPAWN:New(_transportitem.templatename):SpawnFromCoordinate(self.spawnzone:GetCoordinate()) + + -- Set up cargo APC. + local CargoAPC=AI_CARGO_APC:New(APC, CargoGroups, 0) + + -- Init pickup/loading of cargo. (No drive-to coordinate given, since we are already at in the spawn zone.) + CargoAPC:__Pickup(5) + + --- Once the cargo was loaded start off to deploy airbase. + function CargoAPC:OnAfterLoaded(Airplane, From, Event, To) + CargoAPC:__Deploy(5, Airbase:GetZone():GetCoordinate()) + end + + --- Function called when cargo has arrived and was unloaded. + function CargoAPC:OnAfterUnloaded(Airplane, From, Event, To) + + local group=CargoAPC.Cargo:GetObject() + local Airplane=Airplane --Wrapper.Group#GROUP + local warehouse=Airplane:GetState(Airplane, "WAREHOUSE") --#WAREHOUSE + + -- Trigger Delivered event. + warehouse:__Delivered(1, group) + end + elseif TransportType==WAREHOUSE.TransportType.TRAIN then + self:E(self.wid.."ERROR: transport by train not supported yet!") + elseif TransportType==WAREHOUSE.TransportType.SHIP then + + self:E(self.wid.."ERROR: transport by ship not supported yet!") elseif TransportType==WAREHOUSE.TransportType.SELFPROPELLED then From e93f2c54b283ed47e7c99a1d581a88f175b6a650 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 4 Aug 2018 16:47:18 +0200 Subject: [PATCH 11/29] Working version, but needs to be upgraded. --- .../Moose/AI/AI_Cargo_Airplane.lua | 32 ++++++- .../Moose/AI/AI_Cargo_Dispatcher.lua | 93 ++++++++++++++++--- .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 2 +- .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 32 ++++--- .../AI/AI_Cargo_Dispatcher_Helicopter.lua | 2 +- Moose Development/Moose/Core/Set.lua | 39 ++++++++ 6 files changed, 171 insertions(+), 29 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index bbbe19ed0..dc3076e95 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -111,6 +111,18 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) end +function AI_CARGO_AIRPLANE:IsTransporting() + + return self.Transporting == true +end + +function AI_CARGO_AIRPLANE:IsRelocating() + + return self.Relocating == true +end + + + --- Set the Carrier. -- @param #AI_CARGO_AIRPLANE self -- @param Wrapper.Group#GROUP Airplane @@ -155,7 +167,8 @@ function AI_CARGO_AIRPLANE:SetCarrier( Airplane ) function Airplane:OnEventEngineShutdown( EventData ) - AICargo:Landed() + self:F("Calling") + AICargo:Landed( self.Airplane ) end self.Coalition = self.Airplane:GetCoalition() @@ -199,6 +212,10 @@ end -- @param #number Speed function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To ) + self:F({Airplane, From, Event, To}) + self:F({IsAlive=Airplane:IsAlive()}) + self:F({RoutePickup=self.RoutePickup}) + if Airplane and Airplane:IsAlive() then if self.RoutePickup == true then @@ -230,6 +247,8 @@ function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Sp self:Route( Airplane, Airbase, Speed ) self.RoutePickup = true self.Airbase = Airbase + self.Transporting = true + self.Relocating = false end end @@ -248,6 +267,8 @@ function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Sp self:Route( Airplane, Airbase, Speed ) self.RouteDeploy = true self.Airbase = Airbase + self.Transporting = false + self.Relocating = false end end @@ -260,7 +281,9 @@ function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) if Airplane and Airplane:IsAlive() then for _, Cargo in pairs( self.CargoSet:GetSet() ) do - if Cargo:IsInLoadRadius( Coordinate ) then + self:F({Cargo:GetName()}) + local InRadius = Cargo:IsInLoadRadius( Coordinate ) + if InRadius then self:__Board( 5 ) Cargo:Board( Airplane, 25 ) self.Cargo = Cargo @@ -359,6 +382,7 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed ) FromWaypoint.helipadId = nil FromWaypoint.airdromeId = nil + local ParkingSpots = self.Airbase:FindFreeParkingSpotForAircraft( Airplane, AIRBASE.TerminalType.OpenBig ) local AirbaseID = self.Airbase:GetID() local AirbaseCategory = self.Airbase:GetDesc().category @@ -377,8 +401,8 @@ function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed ) -- These cause a lot of confusion. local UnitTemplate = Template.units[UnitID] - UnitTemplate.parking = 15 - UnitTemplate.parking_id = "1" + UnitTemplate.parking = nil + UnitTemplate.parking_id = nil UnitTemplate.alt = 0 local SX = UnitTemplate.x diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 0b1700e04..6b3732121 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -74,7 +74,7 @@ AI_CARGO_DISPATCHER = { ClassName = "AI_CARGO_DISPATCHER", SetCarrier = nil, - SetDeployZones = nil, + DeployZonesSet = nil, AI_Cargo = {}, PickupCargo = {} } @@ -90,23 +90,21 @@ AI_CARGO_DISPATCHER.PickupCargo = {} -- @param #AI_CARGO_DISPATCHER self -- @param Core.Set#SET_GROUP SetCarrier -- @param Core.Set#SET_CARGO SetCargo --- @param Core.Set#SET_ZONE SetDeployZones -- @return #AI_CARGO_DISPATCHER -- @usage -- -- -- Create a new cargo dispatcher --- SetCarrier = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() --- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() +-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() -- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() --- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo ) -- -function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones ) +function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo ) local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER self.SetCarrier = SetCarrier -- Core.Set#SET_GROUP self.SetCargo = SetCargo -- Core.Set#SET_CARGO - self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE self:SetStartState( "Idle" ) @@ -144,6 +142,58 @@ function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones ) end +--- Creates a new AI_CARGO_DISPATCHER object. +-- @param #AI_CARGO_DISPATCHER self +-- @param Core.Set#SET_GROUP SetCarrier +-- @param Core.Set#SET_CARGO SetCargo +-- @param Core.Set#SET_ZONE DeployZonesSet +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() +-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- DeployZonesSet = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone ) +-- +function AI_CARGO_DISPATCHER:NewWithZones( SetCarriers, SetCargos, DeployZonesSet ) + + local self = AI_CARGO_DISPATCHER:New( SetCarriers, SetCargos ) -- #AI_CARGO_DISPATCHER + + self.DeployZonesSet = DeployZonesSet + + return self +end + + +--- Creates a new AI_CARGO_DISPATCHER object. +-- @param #AI_CARGO_DISPATCHER self +-- @param Core.Set#SET_GROUP SetCarrier +-- @param Core.Set#SET_CARGO SetCargo +-- @param Core.Set#SET_AIRBASE PickupAirbasesSet +-- @param Core.Set#SET_AIRBASE DeployAirbasesSet +-- @return #AI_CARGO_DISPATCHER +-- @usage +-- +-- -- Create a new cargo dispatcher +-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart() +-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- PickupAirbasesSet = SET_AIRBASES:New() +-- DeployAirbasesSet = SET_AIRBASES:New() +-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, PickupAirbasesSet, DeployAirbasesSet ) +-- +function AI_CARGO_DISPATCHER:NewWithAirbases( SetCarriers, SetCargos, PickupAirbasesSet, DeployAirbasesSet ) + + local self = AI_CARGO_DISPATCHER:New( SetCarriers, SetCargos ) -- #AI_CARGO_DISPATCHER + + self.DeployAirbasesSet = DeployAirbasesSet + self.PickupAirbasesSet = PickupAirbasesSet + + return self +end + + + --- Set the home zone. -- When there is nothing anymore to pickup, the carriers will go to a random coordinate in this zone. -- They will await here new orders. @@ -361,7 +411,16 @@ function AI_CARGO_DISPATCHER:onafterMonitor() if PickupCargo then self.CarrierHome[Carrier] = nil local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius ) - AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) ) + + if self.PickupAirbasesSet then + -- Find airbase within 2km from the cargo with the set. + local PickupAirbase = self.PickupAirbasesSet:FindAirbaseInRange( PickupCoordinate, 4000 ) + if PickupAirbase then + AI_Cargo:Pickup( PickupAirbase, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) ) + end + else + AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) ) + end break else if self.HomeZone then @@ -464,12 +523,22 @@ end -- @return #AI_CARGO_DISPATCHER function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, Carrier, Cargo ) - local DeployZone = self.SetDeployZones:GetRandomZone() + if self.DeployZonesSet then - local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius ) - self.AI_Cargo[Carrier]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) + local DeployZone = self.DeployZonesSet:GetRandomZone() + + local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius ) + self.AI_Cargo[Carrier]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) - self.PickupCargo[Carrier] = nil + end + + if self.DeployAirbasesSet then + + local DeployAirbase = self.DeployAirbasesSet:GetRandomAirbase() + self.AI_Cargo[Carrier]:Deploy( DeployAirbase, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) + end + + self.PickupCargo[Carrier] = nil end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index 561125786..413ca7c26 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -101,7 +101,7 @@ AI_CARGO_DISPATCHER_APC = { -- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() -- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, 500 ) -- -function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, CombatRadius ) +function AI_CARGO_DISPATCHER_APC:NewWithZones( SetAPC, SetCargo, SetDeployZone, CombatRadius ) local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) ) -- #AI_CARGO_DISPATCHER_APC diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua index c208bab9a..52dd0a712 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -16,8 +16,8 @@ --- Brings a dynamic cargo handling capability for AI groups. -- -- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation. --- The AI\_CARGO\_DISPATCHER\_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework. --- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_AIRPLANE object recognize the cargo. +-- The AI_CARGO_DISPATCHER_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework. +-- CARGO derived objects must be declared within the mission to make the AI_CARGO_DISPATCHER_AIRPLANE object recognize the cargo. -- Please consult the @{Cargo} module for more information. -- -- @@ -29,23 +29,33 @@ AI_CARGO_DISPATCHER_AIRPLANE = { --- Creates a new AI_CARGO_DISPATCHER_AIRPLANE object. -- @param #AI_CARGO_DISPATCHER_AIRPLANE self --- @param Core.Set#SET_GROUP SetAirplane --- @param Core.Set#SET_CARGO SetCargo --- @param Core.Set#SET_ZONE SetDeployZone +-- @param Core.Set#SET_GROUP SetAirplanes +-- @param Core.Set#SET_CARGO SetCargos +-- @param Core.Set#SET_AIRBASE PickupAirbasesSet +-- @param Core.Set#SET_AIRBASE DeployAirbasesSet -- @return #AI_CARGO_DISPATCHER_AIRPLANE -- @usage -- -- -- Create a new cargo dispatcher --- SetAirplane = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart() --- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() --- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() --- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo ) +-- SetAirplanes = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart() +-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart() +-- PickupAirbasesSet = SET_AIRBASE:New() +-- DeployAirbasesSet = SET_AIRBASE:New() +-- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet ) -- -function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo, SetDeployZones ) +function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet ) - local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAirplane, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE + local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithAirbases( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE + + self:SetDeploySpeed( 200, 150 ) + self:SetPickupSpeed( 200, 150 ) + self:SetPickupRadius( 0, 0 ) + self:SetDeployRadius( 0, 0 ) return self end +function AI_CARGO_DISPATCHER_AIRPLANE:AICargo( Airplane, SetCargo ) + return AI_CARGO_AIRPLANE:New( Airplane, SetCargo ) +end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua index eaf9666d2..26b5d9aab 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Helicopter.lua @@ -102,7 +102,7 @@ AI_CARGO_DISPATCHER_HELICOPTER = { -- function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZones ) - local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER + local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithZones( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER self:SetDeploySpeed( 200, 150 ) self:SetPickupSpeed( 200, 150 ) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index e81beb007..7183623e0 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -4010,6 +4010,45 @@ function SET_AIRBASE:FindAirbase( AirbaseName ) end +--- Finds an Airbase in range of a coordinate. +-- @param #SET_AIRBASE self +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Range +-- @return Wrapper.Airbase#AIRBASE The found Airbase. +function SET_AIRBASE:FindAirbaseInRange( Coordinate, Range ) + + local AirbaseFound = nil + + for AirbaseName, AirbaseObject in pairs( self.Set ) do + + local AirbaseCoordinate = AirbaseObject:GetCoordinate() + local Distance = Coordinate:Get2DDistance( AirbaseCoordinate ) + + self:F({Distance=Distance}) + + if Distance <= Range then + AirbaseFound = AirbaseObject + break + end + + end + + return AirbaseFound +end + + +--- Finds a random Airbase in the set. +-- @param #SET_AIRBASE self +-- @return Wrapper.Airbase#AIRBASE The found Airbase. +function SET_AIRBASE:GetRandomAirbase() + + local RandomAirbase = self:GetRandom() + self:F( { RandomAirbase = RandomAirbase:GetName() } ) + + return RandomAirbase +end + + --- Builds a set of airbases of coalitions. -- Possible current coalitions are red, blue and neutral. From 1ce55f3d3d638a9fe3cf6d251bc848814da695cc Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Sat, 4 Aug 2018 18:27:44 +0200 Subject: [PATCH 12/29] WAREHOUSE --- .../Moose/Functional/Warehouse.lua | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 48d365019..0eea6eeaf 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -89,31 +89,31 @@ WAREHOUSE.Descriptor = { --- Warehouse unit categories. These are used for -- @type WAREHOUSE.Attribute WAREHOUSE.Attribute = { - TRANSPORT_PLANE="transportplane", - TRANSPORT_HELO="transporthelo", - TRANSPORT_APC="transportapc", - FIGHTER="fighter", - TANKER="tanker", - AWACS="awacs", - ARTILLERY="artillery", - ATTACKHELICOPTER="attackhelicopter", - INFANTRY="infantry", - BOMBER="bomber", - TANK="tank", - TRUCK="truck", - OTHER="other", + TRANSPORT_PLANE="Transport_Plane", + TRANSPORT_HELO="Transport_Helo", + TRANSPORT_APC="Transport_APC", + FIGHTER="Fighter", + TANKER="Tanker", + AWACS="AWACS", + ARTILLERY="Artillery", + ATTACKHELICOPTER="Attackhelicopter", + INFANTRY="Infantry", + BOMBER="Bomber", + TANK="Tank", + TRUCK="Truck", + SHIP="Ship", + OTHER="Other", } --- Cargo transport type. -- @type WAREHOUSE.TransportType --- @field #string AIRPLANE plane blabla WAREHOUSE.TransportType = { - AIRPLANE = "transportplane", - HELICOPTER = "transporthelo", - APC = "transportapc", - SHIP = "ship", - TRAIN = "train", - SELFPROPELLED = "selfporpelled", + AIRPLANE = "Transport_Plane", + HELICOPTER = "Transport_Helo", + APC = "Transport_APC", + SHIP = "Ship", + TRAIN = "Train", + SELFPROPELLED = "Selfporpelled", } --- Warehouse class version. @@ -131,6 +131,7 @@ WAREHOUSE.version="0.1.0" -- TODO: Put active groups into the warehouse. -- TODO: Spawn warehouse assets as uncontrolled or AI off and activate them when requested. -- TODO: Handle cases with immobile units. +-- TODO: Add queue. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor(s) @@ -209,9 +210,7 @@ function WAREHOUSE:NewAirbase(airbase) --- Triggers the FSM event "Request" after a delay. -- @function [parent=#WAREHOUSE] __Request -- @param #WAREHOUSE self - -- @param #string From From state. - -- @param #string Event Event. - -- @param #string To To state. + -- @param #number Delay Delay in seconds. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase requesting supply. -- @param #WAREHOUSE.Descriptor AssetDescriptor Descriptor describing the asset that is requested. -- @param AssetDescriptorValue Value of the asset descriptor. Type depends on descriptor, i.e. could be a string, etc. @@ -225,8 +224,8 @@ function WAREHOUSE:NewAirbase(airbase) --- Triggers the FSM event "Delivered" after a delay. -- @function [parent=#WAREHOUSE] __Delivered - -- @param #number delay Delay in seconds. -- @param #WAREHOUSE self + -- @param #number delay Delay in seconds. -- @param Wrapper.Group#GROUP group Group that was delivered. return self @@ -423,9 +422,13 @@ function WAREHOUSE:onafterRequest(From, Event, To, Airbase, AssetDescriptor, Ass -- Add spawned groups to cargo group object. for _i,_spawngroup in pairs(_spawngroups) do --TODO: check near and load radius. - local cargogroup = CARGO_GROUP:New(_spawngroup, AssetDescriptorValue, string.format("%s %d",AssetDescriptorValue, _i), _loadradius, _nearradius) + local _name=string.format("%s %d",AssetDescriptorValue, _i) + env.info(string.format("FF cargo group %d: %s",_i,_name)) + local cargogroup = CARGO_GROUP:New(_spawngroup, AssetDescriptorValue, _name, _loadradius, _nearradius) CargoGroups:AddCargo(cargogroup) - end + end + + env.info(string.format("FF cargo set object names %s", CargoGroups:GetObjectNames())) From d53c444c621df010d61999e2a4c89613e1c7577b Mon Sep 17 00:00:00 2001 From: funkyfranky Date: Mon, 6 Aug 2018 00:21:22 +0200 Subject: [PATCH 13/29] Warehouse and other things --- .../Moose/AI/AI_Cargo_Airplane.lua | 328 +++++++++--------- .../Moose/AI/AI_Cargo_Dispatcher_Airplane.lua | 10 +- .../Moose/AI/AI_G2G_Dispatcher.lua | 139 -------- Moose Development/Moose/Cargo/Cargo.lua | 8 + Moose Development/Moose/Cargo/CargoGroup.lua | 30 +- Moose Development/Moose/Cargo/CargoUnit.lua | 12 +- Moose Development/Moose/Core/Point.lua | 31 ++ Moose Development/Moose/Functional/JTAC.lua | 172 --------- .../Moose/Functional/Warehouse.lua | 45 +-- Moose Development/Moose/Wrapper/Group.lua | 132 +++---- Moose Setup/Moose.files | 1 - 11 files changed, 308 insertions(+), 600 deletions(-) delete mode 100644 Moose Development/Moose/AI/AI_G2G_Dispatcher.lua delete mode 100644 Moose Development/Moose/Functional/JTAC.lua diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 37ae630b9..c591acace 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -51,34 +51,41 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) --- Pickup Handler OnBefore for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] OnBeforePickup -- @param #AI_CARGO_AIRPLANE self - -- @param #string From - -- @param #string Event - -- @param #string To + -- @param Wrapper.Group#GROUP Airplane Cargo transport plane. + -- @param #string From From state. + -- @param #string Event Event. + -- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. + -- @param #number Speed in km/h for travelling to pickup base. -- @return #boolean --- Pickup Handler OnAfter for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] OnAfterPickup -- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Group#GROUP Airplane Cargo plane. -- @param #string From -- @param #string Event -- @param #string To -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. + -- @param #number Speed in km/h for travelling to pickup base. --- Pickup Trigger for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] Pickup -- @param #AI_CARGO_AIRPLANE self -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. + -- @param #number Speed in km/h for travelling to pickup base. --- Pickup Asynchronous Trigger for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] __Pickup -- @param #AI_CARGO_AIRPLANE self -- @param #number Delay Delay in seconds. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up. + -- @param #number Speed in km/h for travelling to pickup base. --- Deploy Handler OnBefore for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] OnBeforeDeploy -- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Group#GROUP Airplane Cargo plane. -- @param #string From -- @param #string Event -- @param #string To @@ -89,6 +96,7 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) --- Deploy Handler OnAfter for AI_CARGO_AIRPLANE -- @function [parent=#AI_CARGO_AIRPLANE] OnAfterDeploy -- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Group#GROUP Airplane Cargo plane. -- @param #string From -- @param #string Event -- @param #string To @@ -107,7 +115,16 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- @param #number Delay Delay in seconds. -- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed. -- @param #number Speed Speed in km/h for travelling to deploy base. + + --- On after Loaded event, i.e. triggered when the cargo is inside the carrier. + -- @function [parent=#AI_CARGO_AIRPLANE] OnAfterLoaded + -- @param #AI_CARGO_AIRPLANE self + -- @param Wrapper.Group#GROUP Airplane Cargo plane. + -- @param From + -- @param Event + -- @param To + -- Set carrier. self:SetCarrier( Airplane ) return self @@ -126,10 +143,10 @@ end ---- Set the Carrier. +--- Set the Carrier (controllable). Also initializes events for carrier and defines the coalition. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane --- @return #AI_CARGO_AIRPLANE +-- @param Wrapper.Group#GROUP Airplane Transport plane. +-- @return #AI_CARGO_AIRPLANE self function AI_CARGO_AIRPLANE:SetCarrier( Airplane ) local AICargo = self @@ -184,7 +201,7 @@ end --- Find a free Carrier within a range. -- @param #AI_CARGO_AIRPLANE self - -- @param Wrapper.Airbase#AIRBASE Airbase +-- @param Wrapper.Airbase#AIRBASE Airbase -- @param #number Radius -- @return Wrapper.Group#GROUP NewCarrier function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius ) @@ -206,9 +223,9 @@ function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius ) end ---- On after "Landed" event. Called on engine shutdown. +--- On after "Landed" event. Called on engine shutdown and initiates the pickup mission or unloading event. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane Transport plane. +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. -- @param From -- @param Event -- @param To @@ -220,11 +237,13 @@ function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then + -- Aircraft was sent to this airbase to pickup troops. Initiate loadling. if self.RoutePickup == true then self:Load( Airplane:GetPointVec2() ) self.RoutePickup = false end + -- Aircraft was send to this airbase to deploy troops. Initiate unloading. if self.RouteDeploy == true then self:Unload() self.RouteDeploy = false @@ -237,48 +256,66 @@ end --- On after "Pickup" event. Routes transport to pickup airbase. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane --- @param From --- @param Event --- @param To --- @param Wrapper.Airbase#AIRBASE Airbase --- @param #number Speed +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where the troops as picked up. +-- @param #number Speed in km/h for travelling to pickup base. function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Speed ) if Airplane and Airplane:IsAlive() then - -- Aircraft might be on the ground of the pickup airbase already. + -- Two cases. Aircraft spawned in air or at an airbase. if Airplane:InAir() then - self:Route( Airplane, Airbase, Speed ) + self.Airbase=nil + else + self.Airbase=Airplane:GetCoordinate():GetClosestAirbase() end - -- TODO: Improve :Route() so that the aircraft can be routed from another airbase to the pickup airbase. - - self.RoutePickup = true + -- Route aircraft to pickup airbase. + self:Route( Airplane, Airbase, Speed ) + -- Set airbase as starting point in the next Route() call. self.Airbase = Airbase + + -- Aircraft is on a pickup mission. + self.RoutePickup = true + + -- Unclear!? self.Transporting = true self.Relocating = false end end ---- On after Depoly event. Routes plane to deploy airbase. +--- On after Depoly event. Routes plane to the airbase where the troops are deployed. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane --- @param From --- @param Event --- @param To +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. -- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troups should be deployed. -- @param #number Speed Speed in km/h for travelling to deploy base. function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Speed ) - if Airplane and Airplane:IsAlive() then - - -- Route to + if Airplane and Airplane:IsAlive()~=nil then + + -- Activate uncontrolled airplane. + if Airplane:IsAlive()==false then + Airplane:SetCommand({id = 'Start', params = {}}) + end + + -- Route to destination airbase. self:Route( Airplane, Airbase, Speed ) + + -- Aircraft is on a depoly mission. self.RouteDeploy = true + + -- Set destination airbase for next :Route() command. self.Airbase = Airbase + + -- Unclear?! self.Transporting = false self.Relocating = false end @@ -286,17 +323,16 @@ function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Sp end ---- On after Load event. +--- On after Load event. Checks if cargo is inside the load radius and if so starts the boarding process. -- @param #AI_CARGO_AIRPLANE self -- @param Wrapper.Group#GROUP Airplane Transport plane. --- @param From --- @param Event --- @param To --- @param Wrapper.Point#COORDINATE Coordinate +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @param Wrapper.Point#COORDINATE Coordinate Place where the cargo is guided to if it is inside the load radius. function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) - if Airplane and Airplane:IsAlive()==true or Airplane:IsAlive()==false then - --if Airplane then + if Airplane and Airplane:IsAlive()~=nil then for _, Cargo in pairs( self.CargoSet:GetSet() ) do self:F({Cargo:GetName()}) @@ -313,12 +349,12 @@ function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) end ---- On after Board event. +--- On after Board event. Cargo is inside the load radius and boarding is performed. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane Cargo plane. --- @param From --- @param Event --- @param To +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -332,26 +368,28 @@ function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) end ---- On after Loaded event. +--- On after Loaded event. Cargo is inside the carrier and ready to be transported. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane Cargo plane. --- @param From --- @param Event --- @param To +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To ) + env.info("FF troops loaded into cargo plane") + if Airplane and Airplane:IsAlive() then end end ---- On after Unload event. +--- On after Unload event. Cargo is beeing unloaded, i.e. the unboarding process is started. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane Cargo plane. --- @param From --- @param Event --- @param To +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -361,12 +399,12 @@ function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) end ---- On after Unboard event. +--- On after Unboard event. Checks if unboarding process is finished. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane Cargo plane. --- @param From --- @param Event --- @param To +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -379,12 +417,12 @@ function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) end ---- On after Unloaded event. +--- On after Unloaded event. Cargo has been unloaded, i.e. the unboarding process is finished. -- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane Cargo plane. --- @param From --- @param Event --- @param To +-- @param Wrapper.Group#GROUP Airplane Cargo transport plane. +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then @@ -393,119 +431,75 @@ function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To ) end +--- Route the airplane from one airport or it's current position to another airbase. +-- @param #AI_CARGO_AIRPLANE self +-- @param Wrapper.Group#GROUP Airplane Airplane group to be routed. +-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase. +-- @param #number Speed Speed in km/h. Default is 80% of max possible speed the group can do. +-- @param #boolean Uncontrolled If true, spawn group in uncontrolled state. +function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Uncontrolled ) ---- @param #AI_CARGO_AIRPLANE self --- @param Wrapper.Group#GROUP Airplane --- @param Wrapper.Airbase#AIRBASE Airbase --- @param #number Speed -function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed ) + if Airplane and Airplane:IsAlive()~=nil then - if Airplane and Airplane:IsAlive() then - - local PointVec3 = Airplane:GetPointVec3() - - local Takeoff = SPAWN.Takeoff.Hot + -- Set takeoff type. + local Takeoff = SPAWN.Takeoff.Cold + -- Get template of group. local Template = Airplane:GetTemplate() - - if Template then - - local Points = {} - - if self.Airbase then - - local FromWaypoint = Template.route.points[1] - -- These are only for ships. - FromWaypoint.linkUnit = nil - FromWaypoint.helipadId = nil - FromWaypoint.airdromeId = nil - - local ParkingSpots = self.Airbase:FindFreeParkingSpotForAircraft( Airplane, AIRBASE.TerminalType.OpenBig ) - local AirbaseID = self.Airbase:GetID() - local AirbaseCategory = self.Airbase:GetDesc().category - - FromWaypoint.airdromeId = AirbaseID - - FromWaypoint.alt = 0 - - FromWaypoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type - FromWaypoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action - - - -- Translate the position of the Group Template to the Vec3. - for UnitID = 1, #Template.units do - self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. Template.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. Template.units[UnitID].y ) - - -- These cause a lot of confusion. - local UnitTemplate = Template.units[UnitID] - - UnitTemplate.parking = nil - UnitTemplate.parking_id = nil - UnitTemplate.alt = 0 - - local SX = UnitTemplate.x - local SY = UnitTemplate.y - local BX = FromWaypoint.x - local BY = FromWaypoint.y - local TX = PointVec3.x + ( SX - BX ) - local TY = PointVec3.z + ( SY - BY ) - - UnitTemplate.x = TX - UnitTemplate.y = TY - - self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y ) - end - - FromWaypoint.x = PointVec3.x - FromWaypoint.y = PointVec3.z - - Points[#Points+1] = FromWaypoint - else - - local GroupPoint = Airplane:GetVec2() - local GroupVelocity = Airplane:GetUnit(1):GetDesc().speedMax - - local FromWaypoint = {} - FromWaypoint.x = GroupPoint.x - FromWaypoint.y = GroupPoint.y - FromWaypoint.type = "Turning Point" - FromWaypoint.action = "Turning Point" - FromWaypoint.speed = GroupVelocity - - Points[#Points+1] = FromWaypoint - end - - local AirbasePointVec2 = Airbase:GetPointVec2() - local ToWaypoint = AirbasePointVec2:WaypointAir( - POINT_VEC3.RoutePointAltType.BARO, - "Land", - "Landing", - Speed or Airplane:GetUnit(1):GetDesc().speedMax - ) - - ToWaypoint["airdromeId"] = Airbase:GetID() - ToWaypoint["speed_locked"] = true, - - self:F( ToWaypoint ) - - Points[#Points+1] = ToWaypoint - - Template.x = PointVec3.x - Template.y = PointVec3.z - - self:T3( Points ) - Template.route.points = Points - - Template.uncontrolled=false - - --self:Respawn( Template ) - - local GroupSpawned = Airplane:Respawn( Template ) - - return GroupSpawned + -- Nil check + if Template==nil then + return end - end + -- Waypoints of the route. + local Points={} + + -- To point. + local AirbasePointVec2 = Airbase:GetPointVec2() + local ToWaypoint = AirbasePointVec2:WaypointAir( + POINT_VEC3.RoutePointAltType.BARO, + "Land", + "Landing", + Speed or Airplane:GetSpeedMax()*0.8 + ) + ToWaypoint["airdromeId"] = Airbase:GetID() + ToWaypoint["speed_locked"] = true + + + -- If self.Airbase~=nil then group is currently at an airbase, where it should be respawned. + if self.Airbase then + + -- Second point of the route. First point is done in RespawnAtCurrentAirbase() routine. + Template.route.points[2] = ToWaypoint + + -- Respawn group at the current airbase. + Airplane:RespawnAtCurrentAirbase(Template, Takeoff, Uncontrolled) + + else + -- From point. + local GroupPoint = Airplane:GetVec2() + local FromWaypoint = {} + FromWaypoint.x = GroupPoint.x + FromWaypoint.y = GroupPoint.y + FromWaypoint.type = "Turning Point" + FromWaypoint.action = "Turning Point" + FromWaypoint.speed = Airplane:GetSpeedMax()*0.8 + + -- The two route points. + Points[1] = FromWaypoint + Points[2] = ToWaypoint + + local PointVec3 = Airplane:GetPointVec3() + Template.x = PointVec3.x + Template.y = PointVec3.z + + Template.route.points = Points + + local GroupSpawned = Airplane:Respawn(Template) + + end + end end + diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua index 52dd0a712..300fef9ae 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_Airplane.lua @@ -29,11 +29,11 @@ AI_CARGO_DISPATCHER_AIRPLANE = { --- Creates a new AI_CARGO_DISPATCHER_AIRPLANE object. -- @param #AI_CARGO_DISPATCHER_AIRPLANE self --- @param Core.Set#SET_GROUP SetAirplanes --- @param Core.Set#SET_CARGO SetCargos --- @param Core.Set#SET_AIRBASE PickupAirbasesSet --- @param Core.Set#SET_AIRBASE DeployAirbasesSet --- @return #AI_CARGO_DISPATCHER_AIRPLANE +-- @param Core.Set#SET_GROUP SetAirplanes Set of cargo transport airplanes. +-- @param Core.Set#SET_CARGO SetCargos Set of cargo, which is supposed to be transported. +-- @param Core.Set#SET_AIRBASE PickupAirbasesSet Set of airbases where the cargo has to be picked up. +-- @param Core.Set#SET_AIRBASE DeployAirbasesSet Set of airbases where the cargo is deployed. Choice for each cargo is random. +-- @return #AI_CARGO_DISPATCHER_AIRPLANE self -- @usage -- -- -- Create a new cargo dispatcher diff --git a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua b/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua deleted file mode 100644 index 734c4ef4d..000000000 --- a/Moose Development/Moose/AI/AI_G2G_Dispatcher.lua +++ /dev/null @@ -1,139 +0,0 @@ ---- **AI** - (R2.4) - Manages automatic ground troups dispatching to the battle field. --- --- --- Features: --- --- * Some nice stuff. --- --- # QUICK START GUIDE --- --- === --- --- ### Authors: **funkyfranky** --- --- @module AI.AI_G2G_Dispatcher --- @image AI_Air_To_Air_Dispatching.JPG - -do -- AI_G2G_DISPATCHER - - --- AI_G2G_DISPATCHER class. - -- @type AI_G2G_DISPATCHER - -- @field #string ClassName Name of the class. - -- @field Functional.Detection#DETECTION_AREAS Detection Detection object responsible for identifying enemies. - -- @extends Tasking.DetectionManager#DETECTION_MANAGER - - --- Create an automatic ground . - -- - -- === - -- - -- # Demo Missions - -- - -- ### [AI\_A2A\_DISPATCHER Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/AID%20-%20AI%20Dispatching) - -- - -- === - -- - -- # YouTube Channel - -- - -- ### [DCS WORLD - MOOSE - A2A GCICAP - Build an automatic A2A Defense System](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl0S4KMNUUJpaUs6zZHjLKNx) - -- - -- === - -- - -- ![Banner Image](..\Presentations\AI_A2A_DISPATCHER\Dia3.JPG) - -- - -- Blabla. - -- - -- === - -- - -- # USAGE GUIDE - -- - -- - -- - -- @field #AI_G2G_DISPATCHER - AI_G2G_DISPATCHER = { - ClassName = "AI_G2G_DISPATCHER", - Detection = nil, - Homebase = {}, - } - - - - --- AI_G2G_DISPATCHER constructor. Creates a new AI_G2G_DISPATCHER object. - -- @param #AI_G2G_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE Detection The DETECTION object that will detects targets using the the Early Warning Radar network. - -- @return #AI_G2G_DISPATCHER self - function AI_G2G_DISPATCHER:New(Detection) - - -- Inherits from DETECTION_MANAGER - local self = BASE:Inherit(self, DETECTION_MANAGER:New(nil, Detection)) -- #AI_G2G_DISPATCHER - - self.Detection = Detection -- Functional.Detection#DETECTION_AREAS - - self:AddTransition( "Started", "Assign", "Started" ) - - self:__Start(5) - - return self - end - - --- Adds an APC group to transport troops to the front line. - -- @param #AI_G2G_DISPATCHER self - -- @param Wrapper.Group#GROUP group APC group. - -- @return #AI_G2G_DISPATCHER self - function AI_G2G_DISPATCHER:AddTransportAPC(group, homebase, resources) - self.TransportAPC[group]={} - self.TransportAPC[group].group=group - self.TransportAPC[group].homebase=homebase - self.TransportAPC[group].resources=resources - - -- Add homebase - if not self:GetHomebase(homebase) then - self:AddHomebase(homebase) - end - end - - --- Adds an APC group to transport troops to the front line. - -- @param #AI_G2G_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem The detected item. - function AI_G2G_DISPATCHER:EvaluateDetectedItem(DetectedItem) - local _coord=DetectedItem.Coordinate - _coord:MarkToAll("detected") - - - local _id=DetectedItem.ID - - - - end - - --- Adds an APC group to transport troops to the front line. - -- @param #AI_G2G_DISPATCHER self - -- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object. - -- @return #boolean True if you want the task assigning to continue while false will cancel the loop. - function AI_G2G_DISPATCHER:ProcessDetected(Detection) - - - -- Now that all obsolete tasks are removed, loop through the detected targets. - for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do - - local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem - local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT - local DetectedCount = DetectedSet:Count() - local DetectedZone = DetectedItem.Zone - - self:F( { "Target ID", DetectedItem.ItemID } ) - DetectedSet:Flush( self ) - - local DetectedID = DetectedItem.ID - local DetectionIndex = DetectedItem.Index - local DetectedItemChanged = DetectedItem.Changed - - env.info(string.format("FF detected item id %d, index = %d, changed = %s", DetectedID, DetectedItem.Index, tostring(DetectedItem.Changed))) - - - - end - - end - -end - diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 42d309c6a..5c2526919 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -1203,6 +1203,10 @@ end -- @param #string From -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #number Speed +-- @param #number BoardDistance +-- @param #number LoadDistance +-- @param #number Angle function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) self:F() @@ -1218,6 +1222,7 @@ end -- @param #string Event -- @param #string From -- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier -- @param #number Speed -- @param #number UnLoadDistance -- @param #number UnBoardDistance @@ -1261,6 +1266,7 @@ end -- @param #string From -- @param #string To -- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #number Speed function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) self:F() @@ -1304,6 +1310,8 @@ end -- @param #string Event -- @param #string From -- @param #string To +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param #number Speed -- @param #number Distance -- @param #number Angle function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle ) diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 459da2a0f..c2d45f142 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -61,8 +61,8 @@ do -- CARGO_GROUP -- @param #number LoadRadius (optional) Distance in meters until which a cargo is loaded into the carrier. Cargo outside this radius has to be routed by other means to within the radius to be loaded. -- @param #number NearRadius (optional) Once the units are within this radius of the carrier, they are actually loaded, i.e. disappear from the scene. -- @return #CARGO_GROUP Cargo group object. - function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius ) ) -- #CARGO_GROUP + function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP self:F( { Type, Name, LoadRadius } ) self.CargoSet = SET_CARGO:New() @@ -98,7 +98,7 @@ do -- CARGO_GROUP local Unit = UNIT:Register( CargoUnitName ) --local WeightUnit = Unit:GetDesc().massEmpty --WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10 ) + local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10, LoadRadius, NearRadius ) self.CargoSet:Add( CargoUnitName, CargoUnit ) end @@ -257,10 +257,11 @@ do -- CARGO_GROUP --- Enter Boarding State. -- @param #CARGO_GROUP self - -- @param Wrapper.Unit#UNIT CargoCarrier -- @param #string Event -- @param #string From -- @param #string To + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @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, ... ) --self:F( { CargoCarrier.UnitName, From, Event, To } ) @@ -303,11 +304,12 @@ do -- CARGO_GROUP end --- Leave Boarding State. - -- @param #CARGO_GROUP self - -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #CARGO_GROUP self -- @param #string Event -- @param #string From -- @param #string To + -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) --self:F( { CargoCarrier.UnitName, From, Event, To } ) @@ -359,10 +361,11 @@ do -- CARGO_GROUP --- Enter UnBoarding State. -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 ToPointVec2 -- @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:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) self:F( {From, Event, To, ToPointVec2, NearRadius } ) @@ -401,10 +404,11 @@ do -- CARGO_GROUP --- Leave UnBoarding State. -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 ToPointVec2 -- @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:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) --self:F( { From, Event, To, ToPointVec2, NearRadius } ) @@ -438,10 +442,11 @@ do -- CARGO_GROUP --- UnBoard Event. -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 ToPointVec2 -- @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 } ) @@ -454,10 +459,10 @@ do -- CARGO_GROUP --- Enter UnLoaded State. -- @param #CARGO_GROUP self - -- @param Core.Point#POINT_VEC2 -- @param #string Event -- @param #string From -- @param #string To + -- @param Core.Point#POINT_VEC2 function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) --self:F( { From, Event, To, ToPointVec2 } ) @@ -467,7 +472,7 @@ do -- CARGO_GROUP self.CargoSet:ForEach( function( Cargo ) --Cargo:UnLoad( ToPointVec2 ) - local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10) + local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10) Cargo:UnLoad( RandomVec2 ) end ) @@ -592,8 +597,7 @@ do -- CARGO_GROUP -- @param #CARGO_GROUP self -- @param Wrapper.Group#GROUP CargoCarrier -- @param #number NearRadius - -- @return #boolean The Cargo is near to the Carrier. - -- @return #nil The Cargo is not near to the Carrier. + -- @return #boolean The Cargo is near to the Carrier or #nil if the Cargo is not near to the Carrier. function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) self:F( {NearRadius = NearRadius } ) diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 2a5f009ac..c7992256c 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -42,9 +42,9 @@ do -- CARGO_UNIT -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_UNIT - function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT - self:I( { Type, Name, Weight, NearRadius } ) + function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_UNIT + self:I( { Type, Name, Weight, LoadRadius, NearRadius } ) self:T( CargoUnit ) self.CargoObject = CargoUnit @@ -62,6 +62,7 @@ do -- CARGO_UNIT -- @param #string From -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #number NearRadius (optional) Defaut 25 m. function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) self:F( { From, Event, To, ToPointVec2, NearRadius } ) @@ -131,6 +132,7 @@ do -- CARGO_UNIT -- @param #string From -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #number NearRadius (optional) Defaut 100 m. function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) self:F( { From, Event, To, ToPointVec2, NearRadius } ) @@ -158,6 +160,7 @@ do -- CARGO_UNIT -- @param #string From -- @param #string To -- @param Core.Point#POINT_VEC2 ToPointVec2 + -- @param #number NearRadius (optional) Defaut 100 m. function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) self:F( { From, Event, To, ToPointVec2, NearRadius } ) @@ -281,7 +284,7 @@ do -- CARGO_UNIT -- @param #string From -- @param #string To -- @param Wrapper.Client#CLIENT CargoCarrier - -- @param #number NearRadius + -- @param #number NearRadius Default 25 m. function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) --self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) @@ -338,6 +341,7 @@ do -- CARGO_UNIT -- @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 } ) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index e3c478b14..311d94b22 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -1095,6 +1095,37 @@ do -- COORDINATE return RoutePoint end + + --- Gets the nearest airbase with respect to the current coordinates. + -- @param #COORDINATE self + -- @param #number AirbaseCategory Category of the airbase. + -- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate. + -- @return #number Distance to the closest airbase in meters. + function COORDINATE:GetClosestAirbase(AirbaseCategory) + local airbases=AIRBASE.GetAllAirbases() + + local closest=nil + local distmin=nil + -- Loop over all airbases. + for _,_airbase in pairs(airbases) do + local airbase=_airbase --Wrapper.Airbase#AIRBASE + local category=airbase:GetDesc().category + if AirbaseCategory and AirbaseCategory==category or AirbaseCategory==nil then + local dist=self:Get2DDistance(airbase:GetCoordinate()) + if closest==nil then + distmin=dist + closest=airbase + else + if dist Date: Wed, 8 Aug 2018 21:36:23 +0200 Subject: [PATCH 20/29] WAREHOUSE --- .../Moose/AI/AI_Cargo_Helicopter.lua | 3 +- .../Moose/Functional/Warehouse.lua | 109 +++++++++++------- 2 files changed, 67 insertions(+), 45 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index b774acf95..1e3141649 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -224,7 +224,8 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To ) if self.RoutePickup == true then if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then - self:Load( Helicopter:GetPointVec2() ) + --self:Load( Helicopter:GetPointVec2() ) + self:Load() self.RoutePickup = false self.Relocating = true end diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 9ccef42e3..cf134349b 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -252,6 +252,15 @@ function WAREHOUSE:NewAirbase(airbase) return self end +--- Set a zone where the (ground) assets of the warehouse are spawned once requested. +-- @param #WAREHOUSE self +-- @param Core.Zone#ZONE zone The spawn zone. +-- @return #WAREHOUSE self +function WAREHOUSE:SetSpawnZone(zone) + self.spawnzone=zone + return self +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- FSM states ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -262,7 +271,7 @@ end -- @param #string Event Event. -- @param #string To To state. function WAREHOUSE:onafterStart(From, Event, To) - self:E(self.wid..string.format("Starting warehouse at airbase %s.", self.homebase:GetName())) + self:E(self.wid..string.format("Starting warehouse at airbase %s, category %d, coalition %d.", self.homebase:GetName(), self.category, self.coalition)) -- handle events -- event takeoff @@ -307,13 +316,7 @@ function WAREHOUSE:onafterStatus(From, Event, To) end -- Print queue. - env.info(self.wid.."Queue:") - for _,_qitem in ipairs(self.queue) do - local qitem=_qitem --#WAREHOUSE.Queueitem - local text=string.format("uid=%d, prio=%d, airbase=%s, descriptor: %s=%s, nasssets=%d, transport=%s, ntransport=%d", - qitem.uid, qitem.prio, qitem.airbase:GetName(), qitem.assetdesc,tostring(qitem.assetdescval),qitem.nasset,qitem.transporttype,qitem.ntransport) - env.info(text) - end + self:_PrintQueue() -- Check queue and handle requests if possible. local request=self:_CheckQueue() @@ -325,7 +328,7 @@ function WAREHOUSE:onafterStatus(From, Event, To) end -- Call status again in 30 sec. - self:__Status(30) + self:__Status(10) end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -384,12 +387,15 @@ function WAREHOUSE:_CheckQueue() local okay=true -- Check if number of requested assets is in stock. local _instock=#self:_FilterStock(self.stock, qitem.assetdesc, qitem.assetdescval) + env.info(string.format("FF desc = %s val=%s number=%d", qitem.assetdesc, tostring(qitem.assetdescval),_instock)) if qitem.nasset > _instock then + env.info("FF check queue nasset > instock okay=false") okay=false end -- Check if enough transport units are in stock. _instock=#self:_FilterStock(self.stock, WAREHOUSE.Descriptor.ATTRIBUTE, qitem.transporttype) if qitem.ntransport > _instock then + env.info("FF check queue ntransport > instock okay=false") okay=false end return okay @@ -468,6 +474,13 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) ---------------------------------------------------------------- + -- New empty cargo set in case we need it. + local CargoGroups = SET_CARGO:New() + + --TODO: make nearradius depended on transport type and asset type. + local _loadradius=5000 + local _nearradius=35 + -- Filter the requested assets. local _assetstock=self:_FilterStock(self.stock, Request.assetdesc, Request.assetdescval) @@ -482,17 +495,20 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) local _assetitem=_assetstock[i] --#WAREHOUSE.Stockitem -- Find a random point within the spawn zone. - local spawncoord=self.spawnzone:GetRandomCoordinate() - - spawncoord:MarkToAll(string.format("spawnpoint %d",i)) + local spawncoord=self.spawnzone:GetRandomCoordinate() -- Alias of the group. Spawn with ALIAS here or DCS crashes! - local _alias=string.format("%s_WHID%04d", _assetitem.templatename,_assetitem.id) + local _alias=string.format("%s_AssetID-%04d_RequestID-%04d", _assetitem.templatename,_assetitem.id,Request.uid) local _spawn=SPAWN:NewWithAlias(_assetitem.templatename,_alias) - local _group + local _group=nil --Wrapper.Group#GROUP + + -- Set a marker for the spawned group. + spawncoord:MarkToAll(string.format("Spawnpoint %s",_alias)) + if _assetitem.category==Group.Category.GROUND then -- Spawn ground troops. - _group=_spawn:SpawnFromCoordinate(spawncoord) + _group=_spawn:SpawnFromCoordinate(spawncoord) + env.info(string.format("FF spawning group %s", _alias)) elseif _assetitem.category==Group.Category.AIRPLANE or _assetitem.category==Group.Category.HELICOPTER then -- Spawn air units. local _takeoff=SPAWN.Takeoff.Cold @@ -512,6 +528,12 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) _cargotype=_assetitem.attribute _cargocategory=_assetitem.category table.insert(_delid,_assetitem.id) + + if Request.transporttype ~= WAREHOUSE.TransportType.SELFPROPELLED then + local cargogroup = CARGO_GROUP:New(_group, _alias, _alias, _loadradius, _nearradius) + CargoGroups:AddCargo(cargogroup) + end + end end @@ -551,22 +573,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) return end - ---------------------------------------------------------------- - -- New empty cargo set. - local CargoGroups = SET_CARGO:New() - - --TODO: make nearradius depended on transport type and asset type. - local _loadradius=5000 - local _nearradius=35 - - -- Add spawned groups to cargo group object. - for _i,_spawngroup in pairs(_spawngroups) do - local _name=string.format("%s %d", Request.assetdescval, _i) - env.info(string.format("FF cargo group %d: %s",_i,_name)) - local cargogroup = CARGO_GROUP:New(_spawngroup, Request.assetdescval, _name, _loadradius, _nearradius) - CargoGroups:AddCargo(cargogroup) - end - + env.info("FF cargo set name(s) = "..CargoGroups:GetObjectNames()) ---------------------------------------------------------------- local TransportSet = SET_GROUP:New() --:AddGroupsByName(Plane:GetName()) @@ -574,7 +581,7 @@ function WAREHOUSE:onafterRequest(From, Event, To, Request) -- Pickup and depoly locations. local PickupAirbaseSet = SET_AIRBASE:New():AddAirbase(self.homebase) local DeployAirbaseSet = SET_AIRBASE:New():AddAirbase(Request.airbase) - local DeployZoneSet = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() + local DeployZoneSet = SET_ZONE:New():FilterPrefixes("Deploy"):FilterStart() --local bla=SET_ZONE:New():AddZonesByName(AddZoneNames) local CargoTransport --AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER @@ -764,9 +771,8 @@ end -- @param #WAREHOUSE self -- @param #string templategroupname Name of the late activated template group as defined in the mission editor. -- @param #number ngroups Number of groups to add to the warehouse stock. Default is 1. --- @param #boolean istransport If true, this group will act as transport unit to transport other assets to another airbase. If false, this unit will not be used as transport unit. By default the behavior is determined for the group's attributes. -- @return #WAREHOUSE self -function WAREHOUSE:AddAsset(templategroupname, ngroups, istransport) +function WAREHOUSE:AddAsset(templategroupname, ngroups) -- Set default. local n=ngroups or 1 @@ -1069,10 +1075,11 @@ end -- @param #WAREHOUSE self -- @param #number _uid The unique id of the item to be deleted. function WAREHOUSE:_DeleteStockItem(_uid) - for _i,_item in pairs(self.stock) do - local item=_item --#WAREHOUSE.Stockitem + for i=1,#self.stock do + local item=self.stock[i] --#WAREHOUSE.Stockitem if item.id==_uid then - self.stock[_i]=nil + table.remove(self.stock,i) + break end end end @@ -1081,27 +1088,41 @@ end -- @param #WAREHOUSE self -- @param #number _uid The id of the item to be deleted. function WAREHOUSE:_DeleteQueueItem(_uid) - for _i,_item in pairs(self.queue) do - local item=_item --#WAREHOUSE.Queueitem + env.info("FF BEFORE delete queue") + self:_PrintQueue() + for i=1,#self.queue do + local item=self.queue[i] --#WAREHOUSE.Queueitem if item.uid==_uid then - self.queue[_i]=nil + table.remove(self.queue,i) + break end end + env.info("FF AFTER delete queue") + self:_PrintQueue() end --- Sort requests queue wrt prio and request uid. -- @param #WAREHOUSE self function WAREHOUSE:_SortQueue() - self:F2() - - -- Sort results table wrt times they have already been engaged. + self:F3() + -- Sort. local function _sort(a, b) return (a.prio < b.prio) or (a.prio==b.prio and a.uid < b.uid) end table.sort(self.queue, _sort) - end +--- Prints the queue to DCS.log file. +-- @param #WAREHOUSE self +function WAREHOUSE:_PrintQueue() + env.info(self.wid.."Queue:") + for _,_qitem in ipairs(self.queue) do + local qitem=_qitem --#WAREHOUSE.Queueitem + local text=string.format("uid=%d, prio=%d, airbase=%s (category=%d), descriptor: %s=%s, nasssets=%d, transport=%s, ntransport=%d", + qitem.uid, qitem.prio, qitem.airbase:GetName(),qitem.category, qitem.assetdesc,tostring(qitem.assetdescval),qitem.nasset,qitem.transporttype,qitem.ntransport) + env.info(text) + end +end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From a14c2ef58977d9dab3460dd4df37133675bf750d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 8 Aug 2018 22:41:02 +0200 Subject: [PATCH 21/29] Work in progress. Limit functions for POSITIONABLE. --- .../Moose/AI/AI_Cargo_Airplane.lua | 4 +- .../Moose/AI/AI_Cargo_Dispatcher.lua | 1 + .../Moose/Wrapper/Positionable.lua | 139 ++++++++++++------ 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 003100967..54f8b0cdd 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -188,7 +188,6 @@ function AI_CARGO_AIRPLANE:SetCarrier( Airplane ) function Airplane:OnEventEngineShutdown( EventData ) - self:F("Calling") AICargo:Landed( self.Airplane ) end @@ -233,8 +232,6 @@ end function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To ) self:F({Airplane, From, Event, To}) - self:F({IsAlive=Airplane:IsAlive()}) - self:F({RoutePickup=self.RoutePickup}) if Airplane and Airplane:IsAlive()~=nil then @@ -406,6 +403,7 @@ function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To ) env.info("FF troops loaded into cargo plane") if Airplane and Airplane:IsAlive() then + -- Check if another cargo can be loaded into the airplane. end end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 7ac009283..ea76ec694 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -403,6 +403,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() -- 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( { IsTransporting = AI_Cargo:IsTransporting() } ) if AI_Cargo:IsTransporting() == false then -- ok, so there is a free Carrier diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 23b85806a..888cf3232 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -798,56 +798,99 @@ function POSITIONABLE:GetLaserCode() --R2.1 return self.LaserCode end ---- Add cargo. --- @param #POSITIONABLE self --- @param Core.Cargo#CARGO Cargo --- @return #POSITIONABLE -function POSITIONABLE:AddCargo( Cargo ) - self.__.Cargo[Cargo] = Cargo - return self -end +do -- Cargo ---- Get all contained cargo. --- @param #POSITIONABLE self --- @return #POSITIONABLE -function POSITIONABLE:GetCargo() - return self.__.Cargo -end - - - ---- Remove cargo. --- @param #POSITIONABLE self --- @param Core.Cargo#CARGO Cargo --- @return #POSITIONABLE -function POSITIONABLE:RemoveCargo( Cargo ) - self.__.Cargo[Cargo] = nil - return self -end - ---- Returns if carrier has given cargo. --- @param #POSITIONABLE self --- @return Core.Cargo#CARGO Cargo -function POSITIONABLE:HasCargo( Cargo ) - return self.__.Cargo[Cargo] -end - ---- Clear all cargo. --- @param #POSITIONABLE self -function POSITIONABLE:ClearCargo() - self.__.Cargo = {} -end - ---- Get cargo item count. --- @param #POSITIONABLE self --- @return Core.Cargo#CARGO Cargo -function POSITIONABLE:CargoItemCount() - local ItemCount = 0 - for CargoName, Cargo in pairs( self.__.Cargo ) do - ItemCount = ItemCount + Cargo:GetCount() + --- Add cargo. + -- @param #POSITIONABLE self + -- @param Core.Cargo#CARGO Cargo + -- @return #POSITIONABLE + function POSITIONABLE:AddCargo( Cargo ) + self.__.Cargo[Cargo] = Cargo + return self end - return ItemCount -end + + --- Get all contained cargo. + -- @param #POSITIONABLE self + -- @return #POSITIONABLE + function POSITIONABLE:GetCargo() + return self.__.Cargo + end + + + + --- Remove cargo. + -- @param #POSITIONABLE self + -- @param Core.Cargo#CARGO Cargo + -- @return #POSITIONABLE + function POSITIONABLE:RemoveCargo( Cargo ) + self.__.Cargo[Cargo] = nil + return self + end + + --- Returns if carrier has given cargo. + -- @param #POSITIONABLE self + -- @return Core.Cargo#CARGO Cargo + function POSITIONABLE:HasCargo( Cargo ) + return self.__.Cargo[Cargo] + end + + --- Clear all cargo. + -- @param #POSITIONABLE self + function POSITIONABLE:ClearCargo() + self.__.Cargo = {} + end + + --- Get cargo item count. + -- @param #POSITIONABLE self + -- @return Core.Cargo#CARGO Cargo + function POSITIONABLE:CargoItemCount() + local ItemCount = 0 + for CargoName, Cargo in pairs( self.__.Cargo ) do + ItemCount = ItemCount + Cargo:GetCount() + end + return ItemCount + end + + --- Get Cargo Bay Free Volume in m3. + -- @param #POSITIONABLE self + -- @return #number CargoBayFreeVolume + function POSITIONABLE:GetCargoBayFreeVolume() + local CargoVolume = 0 + for CargoName, Cargo in pairs( self.__.Cargo ) do + CargoVolume = CargoVolume + Cargo:GetVolume() + end + return self.__.CargoBayVolumeLimit - CargoVolume + end + + --- Get Cargo Bay Free Weight in kg. + -- @param #POSITIONABLE self + -- @return #number CargoBayFreeWeight + function POSITIONABLE:GetCargoBayFreeWeight() + local CargoWeight = 0 + for CargoName, Cargo in pairs( self.__.Cargo ) do + CargoWeight = CargoWeight + Cargo:GetWeight() + end + return self.__.CargoBayWeightLimit - CargoWeight + end + + --- Get Cargo Bay Volume Limit in m3. + -- @param #POSITIONABLE self + -- @param #number VolumeLimit + function POSITIONABLE:SetCargoBayVolumeLimit( VolumeLimit ) + self.__.CargoBayVolumeLimit = VolumeLimit + end + + --- Get Cargo Bay Weight Limit in kg. + -- @param #POSITIONABLE self + -- @param #number WeightLimit + function POSITIONABLE:GetCargoBayFreeWeightLimit( WeightLimit ) + self.__.CargoBayWeightLimit = WeightLimit + end + + + + +end --- Cargo --- Signal a flare at the position of the POSITIONABLE. -- @param #POSITIONABLE self From 7f9f9b33fd4b1f64040c911e810ade946a28493d Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sat, 11 Aug 2018 11:33:43 +0200 Subject: [PATCH 22/29] - Have added cargo bay limits based on volume and weight. - AI Cargo Dispatcher works with cargo bay limits for carrier. (i still need to add options to set the parameters for this). - Carriers load now multiple cargo. - Added weight and volume attached to cargo objects for units. I reworked the respawning of cargo units, so that these volumes and weights are collected from the unit Descriptor properties! - There are still bugs, which I need to resolve, but it is going in the right direction. --- .../Moose/AI/AI_Cargo_Airplane.lua | 89 ++++++++++++++----- .../Moose/AI/AI_Cargo_Dispatcher.lua | 12 +-- Moose Development/Moose/Cargo/Cargo.lua | 23 +++++ Moose Development/Moose/Cargo/CargoGroup.lua | 31 ++++++- .../Moose/Wrapper/Identifiable.lua | 2 +- .../Moose/Wrapper/Positionable.lua | 3 +- 6 files changed, 129 insertions(+), 31 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 54f8b0cdd..28a71989f 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -34,10 +34,10 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) self:SetStartState( "Unloaded" ) - self:AddTransition( "Unloaded", "Pickup", "*" ) + self:AddTransition( { "Unloaded", "Loaded" }, "Pickup", "*" ) self:AddTransition( "Loaded", "Deploy", "*" ) - self:AddTransition( "Unloaded", "Load", "Boarding" ) + self:AddTransition( { "Unloaded", "Loaded" }, "Load", "Boarding" ) self:AddTransition( "Boarding", "Board", "Boarding" ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) @@ -128,6 +128,11 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- Set carrier. self:SetCarrier( Airplane ) + Airplane:SetCargoBayWeightLimit( 5000 ) + Airplane:SetCargoBayVolumeLimit( 15 ) + + self.Relocating = true + return self end @@ -188,6 +193,7 @@ function AI_CARGO_AIRPLANE:SetCarrier( Airplane ) function Airplane:OnEventEngineShutdown( EventData ) + AICargo.Relocating = false AICargo:Landed( self.Airplane ) end @@ -355,17 +361,21 @@ end -- @param Wrapper.Point#COORDINATE Coordinate Place where the cargo is guided to if it is inside the load radius. function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate ) - if Airplane and Airplane:IsAlive()~=nil then + if Airplane and Airplane:IsAlive() ~= nil then for _,_Cargo in pairs( self.CargoSet:GetSet() ) do self:F({_Cargo:GetName()}) local Cargo=_Cargo --Cargo.Cargo#CARGO local InRadius = Cargo:IsInLoadRadius( Coordinate ) if InRadius then - self:__Board( 5 ) - Cargo:Board( Airplane, 25 ) - self.Cargo = Cargo - break + + -- Is there a cargo still unloaded? + if Cargo:IsUnLoaded() == true then + + self:__Board( 5, Cargo ) + Cargo:Board( Airplane, 25 ) + break + end end end @@ -379,14 +389,16 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To ) +function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To, Cargo ) if Airplane and Airplane:IsAlive() then - self:F({ IsLoaded = self.Cargo:IsLoaded() } ) - if not self.Cargo:IsLoaded() then - self:__Board( 10 ) + + self:F({ IsLoaded = Cargo:IsLoaded() } ) + + if not Cargo:IsLoaded() then + self:__Board( 10, Cargo ) else - self:__Loaded( 1 ) + self:__Loaded( 1, Cargo ) end end @@ -398,12 +410,46 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To ) +function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To, Cargo ) env.info("FF troops loaded into cargo plane") if Airplane and Airplane:IsAlive() then + -- Check if another cargo can be loaded into the airplane. + for _,_Cargo in pairs( self.CargoSet:GetSet() ) do + + self:F({_Cargo:GetName()}) + local Cargo =_Cargo --Cargo.Cargo#CARGO + + -- Is there a cargo still unloaded? + if Cargo:IsUnLoaded() == true then + + -- Only when the cargo is within load radius. + local InRadius = Cargo:IsInLoadRadius( Airplane:GetCoordinate() ) + if InRadius then + + local CargoBayFreeWeight = Airplane:GetCargoBayFreeWeight() + local CargoBayFreeVolume = Airplane:GetCargoBayFreeVolume() + + local CargoWeight = Cargo:GetWeight() + local CargoVolume = Cargo:GetVolume() + + -- Only when there is space within the bay to load the next cargo item! + if CargoBayFreeWeight > CargoWeight and CargoBayFreeVolume > CargoVolume then + + -- ok, board. + self:__Load( 5, Airplane:GetCoordinate() ) + + -- And start the boarding loop for the AI_CARGO_AIRPLANE object until the cargo is boarded. + --Cargo:Board( Airplane, 25 ) + return + end + end + end + end + self:F( { "Transporting" } ) + self.Transporting = true -- This will only be executed when there is no cargo boarded anymore. The dispatcher will then kick-off the deploy cycle! end end @@ -418,8 +464,11 @@ end function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then - self.Cargo:UnBoard() - self:__Unboard( 10 ) + local Cargos = Airplane:GetCargo() + for CargoID, Cargo in pairs( Cargos ) do + Cargo:UnBoard() + self:__Unboard( 10, Cargo ) + end end end @@ -430,13 +479,13 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To ) +function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To, Cargo ) if Airplane and Airplane:IsAlive() then - if not self.Cargo:IsUnLoaded() then - self:__Unboard( 10 ) + if not Cargo:IsUnLoaded() then + self:__Unboard( 10, Cargo ) else - self:__Unloaded( 1 ) + self:__Unloaded( 1, Cargo ) end end @@ -448,7 +497,7 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. -function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To ) +function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To, Cargo ) if Airplane and Airplane:IsAlive() then self.Airplane = Airplane diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index ea76ec694..9a5082f52 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -404,8 +404,8 @@ function AI_CARGO_DISPATCHER:onafterMonitor() -- 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( { IsTransporting = AI_Cargo:IsTransporting() } ) - if AI_Cargo:IsTransporting() == false then + self:I( { IsRelocating = AI_Cargo:IsRelocating() } ) + if AI_Cargo:IsRelocating() == false then -- ok, so there is a free Carrier -- now find the first cargo that is Unloaded @@ -560,9 +560,11 @@ function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, Carrier, Cargo ) end if self.DeployAirbasesSet then - - local DeployAirbase = self.DeployAirbasesSet:GetRandomAirbase() - self.AI_Cargo[Carrier]:Deploy( DeployAirbase, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) + + if self.AI_Cargo[Carrier]:IsTransporting() == true then + local DeployAirbase = self.DeployAirbasesSet:GetRandomAirbase() + self.AI_Cargo[Carrier]:Deploy( DeployAirbase, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) ) + end end self.PickupCargo[Carrier] = nil diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 5c2526919..e0b6f4d4a 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -875,6 +875,13 @@ do -- CARGO return self.CargoObject:GetCoordinate() end + --- Get the weight of the cargo. + -- @param #CARGO self + -- @return #number Weight The weight in kg. + function CARGO:GetWeight() + return self.Weight + end + --- Set the weight of the cargo. -- @param #CARGO self -- @param #number Weight The weight in kg. @@ -884,6 +891,22 @@ do -- CARGO return self end + --- Get the volume of the cargo. + -- @param #CARGO self + -- @return #number Volume The volume in kg. + function CARGO:GetVolume() + return self.Volume + end + + --- Set the volume of the cargo. + -- @param #CARGO self + -- @param #number Volume The volume in kg. + -- @return #CARGO + function CARGO:SetVolume( Volume ) + self.Volume = Volume + return self + end + --- Send a CC message to a @{Wrapper.Group}. -- @param #CARGO self -- @param #string Message diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index c2d45f142..b7c78a713 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -73,6 +73,7 @@ do -- CARGO_GROUP self:SetDeployed( false ) local WeightGroup = 0 + local VolumeGroup = 0 self.CargoGroup:Destroy() @@ -96,10 +97,7 @@ do -- CARGO_GROUP -- And we register the spawned unit as part of the CargoSet. local Unit = UNIT:Register( CargoUnitName ) - --local WeightUnit = Unit:GetDesc().massEmpty - --WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10, LoadRadius, NearRadius ) - self.CargoSet:Add( CargoUnitName, CargoUnit ) + end -- Then we register the new group in the database @@ -107,6 +105,31 @@ do -- CARGO_GROUP -- Now we spawn the new group based on the template created. self.CargoObject = _DATABASE:Spawn( GroupTemplate ) + + for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do + local Desc = CargoUnit:GetDesc() + self:I( { Desc = Desc } ) + local WeightUnit = math.random( 80, 120 ) + if Desc then + WeightUnit = Desc.massEmpty + end + + local Box = CargoUnit:GetBoundingBox() + local VolumeUnit = ( Box.max.x - Box.min.x ) * ( Box.max.y - Box.min.y ) * ( Box.max.z - Box.min.z ) + self:I( { VolumeUnit = VolumeUnit, WeightUnit = WeightUnit } ) + + + local CargoUnitName = CargoUnit:GetName() + + local Cargo = CARGO_UNIT:New( CargoUnit, Type, CargoUnitName, 0, LoadRadius, NearRadius ) + Cargo:SetWeight( WeightUnit ) + Cargo:SetVolume( VolumeUnit ) + self.CargoSet:Add( CargoUnitName, Cargo ) + + WeightGroup = WeightGroup + WeightUnit + VolumeGroup = VolumeGroup + VolumeUnit + + end self:SetWeight( WeightGroup ) self.CargoLimit = 10 diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index 6e226a466..0f6e14f06 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -216,7 +216,7 @@ end function IDENTIFIABLE:GetDesc() self:F2( self.IdentifiableName ) - local DCSIdentifiable = self:GetDCSObject() + local DCSIdentifiable = self:GetDCSObject() -- DCS#Object if DCSIdentifiable then local IdentifiableDesc = DCSIdentifiable:getDesc() diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 888cf3232..44fa06d52 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -868,6 +868,7 @@ do -- Cargo function POSITIONABLE:GetCargoBayFreeWeight() local CargoWeight = 0 for CargoName, Cargo in pairs( self.__.Cargo ) do + self:F( { Cargo = Cargo } ) CargoWeight = CargoWeight + Cargo:GetWeight() end return self.__.CargoBayWeightLimit - CargoWeight @@ -883,7 +884,7 @@ do -- Cargo --- Get Cargo Bay Weight Limit in kg. -- @param #POSITIONABLE self -- @param #number WeightLimit - function POSITIONABLE:GetCargoBayFreeWeightLimit( WeightLimit ) + function POSITIONABLE:SetCargoBayWeightLimit( WeightLimit ) self.__.CargoBayWeightLimit = WeightLimit end From 74e9599df942c142f3d2dec278715e2f069940fa Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 13 Aug 2018 07:38:18 +0200 Subject: [PATCH 23/29] Got the airplanes finally to load together ... --- .../Moose/AI/AI_Cargo_Airplane.lua | 83 ++++++++++--------- .../Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- Moose Development/Moose/Cargo/Cargo.lua | 22 ++++- Moose Development/Moose/Cargo/CargoGroup.lua | 19 +---- Moose Development/Moose/Cargo/CargoUnit.lua | 6 +- .../Moose/Wrapper/Positionable.lua | 36 ++++---- 6 files changed, 86 insertions(+), 82 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 28a71989f..75f3f2873 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -37,7 +37,7 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) self:AddTransition( { "Unloaded", "Loaded" }, "Pickup", "*" ) self:AddTransition( "Loaded", "Deploy", "*" ) - self:AddTransition( { "Unloaded", "Loaded" }, "Load", "Boarding" ) + self:AddTransition( { "Unloaded", "Boarding" }, "Load", "Boarding" ) self:AddTransition( "Boarding", "Board", "Boarding" ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) @@ -128,8 +128,13 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- Set carrier. self:SetCarrier( Airplane ) - Airplane:SetCargoBayWeightLimit( 5000 ) - Airplane:SetCargoBayVolumeLimit( 15 ) + local Desc = Airplane:GetUnit(1):GetDesc() + + self:F({Desc=Desc}) + + + Airplane:SetCargoBayWeightLimit( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) ) + --Airplane:SetCargoBayVolumeLimit( 15 ) self.Relocating = true @@ -344,8 +349,7 @@ function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Sp -- Set destination airbase for next :Route() command. self.Airbase = Airbase - -- Unclear?! - self.Transporting = false + self.Transporting = true self.Relocating = false end @@ -398,6 +402,38 @@ function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To, Cargo ) if not Cargo:IsLoaded() then self:__Board( 10, Cargo ) else + -- Check if another cargo can be loaded into the airplane. + for _,_Cargo in pairs( self.CargoSet:GetSet() ) do + + self:F({_Cargo:GetName()}) + local Cargo =_Cargo --Cargo.Cargo#CARGO + + -- Is there a cargo still unloaded? + if Cargo:IsUnLoaded() == true then + + -- Only when the cargo is within load radius. + local InRadius = Cargo:IsInLoadRadius( Airplane:GetCoordinate() ) + if InRadius then + + local CargoBayFreeWeight = Airplane:GetCargoBayFreeWeight() + --local CargoBayFreeVolume = Airplane:GetCargoBayFreeVolume() + + local CargoWeight = Cargo:GetWeight() + --local CargoVolume = Cargo:GetVolume() + + -- Only when there is space within the bay to load the next cargo item! + if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then + + -- ok, board. + self:__Load( 5, Airplane:GetCoordinate() ) + + -- And start the boarding loop for the AI_CARGO_AIRPLANE object until the cargo is boarded. + --Cargo:Board( Airplane, 25 ) + return + end + end + end + end self:__Loaded( 1, Cargo ) end end @@ -415,41 +451,8 @@ function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To, Cargo ) env.info("FF troops loaded into cargo plane") if Airplane and Airplane:IsAlive() then - - -- Check if another cargo can be loaded into the airplane. - for _,_Cargo in pairs( self.CargoSet:GetSet() ) do - - self:F({_Cargo:GetName()}) - local Cargo =_Cargo --Cargo.Cargo#CARGO - - -- Is there a cargo still unloaded? - if Cargo:IsUnLoaded() == true then - - -- Only when the cargo is within load radius. - local InRadius = Cargo:IsInLoadRadius( Airplane:GetCoordinate() ) - if InRadius then - - local CargoBayFreeWeight = Airplane:GetCargoBayFreeWeight() - local CargoBayFreeVolume = Airplane:GetCargoBayFreeVolume() - - local CargoWeight = Cargo:GetWeight() - local CargoVolume = Cargo:GetVolume() - - -- Only when there is space within the bay to load the next cargo item! - if CargoBayFreeWeight > CargoWeight and CargoBayFreeVolume > CargoVolume then - - -- ok, board. - self:__Load( 5, Airplane:GetCoordinate() ) - - -- And start the boarding loop for the AI_CARGO_AIRPLANE object until the cargo is boarded. - --Cargo:Board( Airplane, 25 ) - return - end - end - end - end - self:F( { "Transporting" } ) - self.Transporting = true -- This will only be executed when there is no cargo boarded anymore. The dispatcher will then kick-off the deploy cycle! + self:F( { "Transporting" } ) + self.Transporting = true -- This will only be executed when there is no cargo boarded anymore. The dispatcher will then kick-off the deploy cycle! end end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 9a5082f52..c7a0ea4b9 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -405,7 +405,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() -- 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( { IsRelocating = AI_Cargo:IsRelocating() } ) - if AI_Cargo:IsRelocating() == false then + 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 diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index e0b6f4d4a..50cade298 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -1020,13 +1020,27 @@ do -- CARGO_REPRESENTABLE -- @param #CARGO_REPRESENTABLE self -- @param #string Type -- @param #string Name - -- @param #number Weight -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, LoadRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE - self:F( { Type, Name, Weight, LoadRadius, NearRadius } ) + function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE + self:F( { Type, Name, LoadRadius, NearRadius } ) + + local Desc = CargoObject:GetDesc() + self:I( { Desc = Desc } ) + local Weight = math.random( 80, 120 ) + if Desc then + Weight = Desc.massEmpty + end + + self:SetWeight( Weight ) + +-- local Box = CargoUnit:GetBoundingBox() +-- local VolumeUnit = ( Box.max.x - Box.min.x ) * ( Box.max.y - Box.min.y ) * ( Box.max.z - Box.min.z ) +-- self:I( { VolumeUnit = VolumeUnit, WeightUnit = WeightUnit } ) + --self:SetVolume( VolumeUnit ) + return self end diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index b7c78a713..72a3430cf 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -107,32 +107,19 @@ do -- CARGO_GROUP self.CargoObject = _DATABASE:Spawn( GroupTemplate ) for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do - local Desc = CargoUnit:GetDesc() - self:I( { Desc = Desc } ) - local WeightUnit = math.random( 80, 120 ) - if Desc then - WeightUnit = Desc.massEmpty - end - - local Box = CargoUnit:GetBoundingBox() - local VolumeUnit = ( Box.max.x - Box.min.x ) * ( Box.max.y - Box.min.y ) * ( Box.max.z - Box.min.z ) - self:I( { VolumeUnit = VolumeUnit, WeightUnit = WeightUnit } ) local CargoUnitName = CargoUnit:GetName() - local Cargo = CARGO_UNIT:New( CargoUnit, Type, CargoUnitName, 0, LoadRadius, NearRadius ) - Cargo:SetWeight( WeightUnit ) - Cargo:SetVolume( VolumeUnit ) + local Cargo = CARGO_UNIT:New( CargoUnit, Type, CargoUnitName, LoadRadius, NearRadius ) self.CargoSet:Add( CargoUnitName, Cargo ) - WeightGroup = WeightGroup + WeightUnit - VolumeGroup = VolumeGroup + VolumeUnit + WeightGroup = WeightGroup + Cargo:GetWeight() + --VolumeGroup = VolumeGroup + VolumeUnit end self:SetWeight( WeightGroup ) - self.CargoLimit = 10 self:T( { "Weight Cargo", WeightGroup } ) diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index c7992256c..90eceeda9 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -42,9 +42,9 @@ do -- CARGO_UNIT -- @param #number LoadRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_UNIT - function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, LoadRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_UNIT - self:I( { Type, Name, Weight, LoadRadius, NearRadius } ) + function CARGO_UNIT:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) + local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) ) -- #CARGO_UNIT + self:I( { Type, Name, LoadRadius, NearRadius } ) self:T( CargoUnit ) self.CargoObject = CargoUnit diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 44fa06d52..1de5c21fe 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -851,17 +851,17 @@ do -- Cargo return ItemCount end - --- Get Cargo Bay Free Volume in m3. - -- @param #POSITIONABLE self - -- @return #number CargoBayFreeVolume - function POSITIONABLE:GetCargoBayFreeVolume() - local CargoVolume = 0 - for CargoName, Cargo in pairs( self.__.Cargo ) do - CargoVolume = CargoVolume + Cargo:GetVolume() - end - return self.__.CargoBayVolumeLimit - CargoVolume - end - +-- --- Get Cargo Bay Free Volume in m3. +-- -- @param #POSITIONABLE self +-- -- @return #number CargoBayFreeVolume +-- function POSITIONABLE:GetCargoBayFreeVolume() +-- local CargoVolume = 0 +-- for CargoName, Cargo in pairs( self.__.Cargo ) do +-- CargoVolume = CargoVolume + Cargo:GetVolume() +-- end +-- return self.__.CargoBayVolumeLimit - CargoVolume +-- end +-- --- Get Cargo Bay Free Weight in kg. -- @param #POSITIONABLE self -- @return #number CargoBayFreeWeight @@ -874,13 +874,13 @@ do -- Cargo return self.__.CargoBayWeightLimit - CargoWeight end - --- Get Cargo Bay Volume Limit in m3. - -- @param #POSITIONABLE self - -- @param #number VolumeLimit - function POSITIONABLE:SetCargoBayVolumeLimit( VolumeLimit ) - self.__.CargoBayVolumeLimit = VolumeLimit - end - +-- --- Get Cargo Bay Volume Limit in m3. +-- -- @param #POSITIONABLE self +-- -- @param #number VolumeLimit +-- function POSITIONABLE:SetCargoBayVolumeLimit( VolumeLimit ) +-- self.__.CargoBayVolumeLimit = VolumeLimit +-- end + --- Get Cargo Bay Weight Limit in kg. -- @param #POSITIONABLE self -- @param #number WeightLimit From 4d7812b368eaf7453c951a7a4a8bfb5fe7bdd891 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Mon, 13 Aug 2018 21:42:44 +0200 Subject: [PATCH 24/29] Working version for airplanes, now need to debug to make it also happen for helicopters and apcs --- .../Moose/AI/AI_Cargo_Airplane.lua | 35 ++++++++++++++++--- .../Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 75f3f2873..8cacb48ea 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -42,7 +42,7 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) self:AddTransition( "Unboarding", "Unboard", "Unboarding" ) - self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) + self:AddTransition( "Unboarding" , "Unloaded", "Unloaded" ) self:AddTransition( "*", "Landed", "*" ) self:AddTransition( "*", "Home" , "*" ) @@ -469,7 +469,15 @@ function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To ) if Airplane and Airplane:IsAlive() then local Cargos = Airplane:GetCargo() for CargoID, Cargo in pairs( Cargos ) do - Cargo:UnBoard() + + local Angle = 180 + local CargoCarrierHeading = Airplane:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + self:T( { CargoCarrierHeading, CargoDeployHeading } ) + local CargoDeployCoordinate = Airplane:GetPointVec2():Translate( 150, CargoDeployHeading ) + + Cargo:UnBoard( CargoDeployCoordinate ) + Cargo:SetDeployed( true ) self:__Unboard( 10, Cargo ) end end @@ -484,14 +492,30 @@ end -- @param #string To To state. function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To, Cargo ) + self:E( { "Unboard", Cargo } ) + if Airplane and Airplane:IsAlive() then if not Cargo:IsUnLoaded() then self:__Unboard( 10, Cargo ) else + local Cargos = Airplane:GetCargo() + for CargoID, Cargo in pairs( Cargos ) do + if Cargo:IsLoaded() then + local Angle = 180 + local CargoCarrierHeading = Airplane:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) + self:T( { CargoCarrierHeading, CargoDeployHeading } ) + local CargoDeployCoordinate = Airplane:GetPointVec2():Translate( 150, CargoDeployHeading ) + Cargo:UnBoard( CargoDeployCoordinate ) + Cargo:SetDeployed( true ) + + self:__Unboard( 10, Cargo ) + return + end + end self:__Unloaded( 1, Cargo ) end end - end --- On after Unloaded event. Cargo has been unloaded, i.e. the unboarding process is finished. @@ -500,12 +524,15 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. +-- @param Cargo.Cargo#CARGO Cargo function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To, Cargo ) + self:E( { "Unloaded", Cargo } ) + if Airplane and Airplane:IsAlive() then self.Airplane = Airplane + self.Transporting = false -- This will only be executed when there is no cargo onboard anymore. The dispatcher will then kick-off the pickup cycle! end - end --- Route the airplane from one airport or it's current position to another airbase. diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index c7a0ea4b9..c19d760a8 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -414,7 +414,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() for CargoName, Cargo in pairs( self.SetCargo:GetSet() ) 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() and not Cargo:IsDeployed() then + if Cargo:IsUnLoaded() == true and Cargo:IsDeployed() == false then local CargoCoordinate = Cargo:GetCoordinate() local CoordinateFree = true for CarrierPickup, Coordinate in pairs( self.PickupCargo ) do From e4f8b5afc3586e3c8b2b69159e75ac510a5e2355 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 14 Aug 2018 21:04:11 +0200 Subject: [PATCH 25/29] Working plane cargo AI dispatcher, but still need to work on the collisions on the runway etc of moving vehicles with planes... --- Moose Development/Moose/Cargo/CargoGroup.lua | 4 +-- Moose Development/Moose/Core/Database.lua | 35 +++++++++++--------- Moose Development/Moose/Core/Event.lua | 2 +- Moose Development/Moose/Wrapper/Group.lua | 14 ++++---- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 72a3430cf..b51e5502c 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -89,7 +89,7 @@ do -- CARGO_GROUP for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do UnitTemplate.name = UnitTemplate.name .. "#CARGO" - local CargoUnitName = UnitTemplate.name + local CargoUnitName = UnitTemplate.name self.CargoUnitTemplate[CargoUnitName] = UnitTemplate GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName] @@ -101,7 +101,7 @@ do -- CARGO_GROUP end -- Then we register the new group in the database - self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID ) -- Now we spawn the new group based on the template created. self.CargoObject = _DATABASE:Spawn( GroupTemplate ) diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 3b0fb0337..59e4676e4 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -374,14 +374,15 @@ do -- cargo -- @return #DATABASE self function DATABASE:_RegisterCargos() + local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug! - for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do + for CargoGroupName, CargoGroup in pairs( Groups ) do + self:I( { Cargo = CargoGroupName } ) if self:IsCargo( CargoGroupName ) then local CargoInfo = CargoGroupName:match("~CARGO(.*)") local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)") local CargoName1 = CargoGroupName:match("(.*)~CARGO%(.*%)") local CargoName2 = CargoGroupName:match(".*~CARGO%(.*%)(.*)") - self:E({CargoName1 = CargoName1, CargoName2 = CargoName2 }) local CargoName = CargoName1 .. ( CargoName2 or "" ) local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName @@ -459,7 +460,7 @@ end function DATABASE:AddGroup( GroupName ) if not self.GROUPS[GroupName] then - self:E( { "Add GROUP:", GroupName } ) + self:I( { "Add GROUP:", GroupName } ) self.GROUPS[GroupName] = GROUP:Register( GroupName ) end @@ -471,7 +472,7 @@ end function DATABASE:AddPlayer( UnitName, PlayerName ) if PlayerName then - self:E( { "Add player for unit:", UnitName, PlayerName } ) + self:I( { "Add player for unit:", UnitName, PlayerName } ) self.PLAYERS[PlayerName] = UnitName self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName ) self.PLAYERSJOINED[PlayerName] = PlayerName @@ -483,7 +484,7 @@ end function DATABASE:DeletePlayer( UnitName, PlayerName ) if PlayerName then - self:E( { "Clean player:", PlayerName } ) + self:I( { "Clean player:", PlayerName } ) self.PLAYERS[PlayerName] = nil self.PLAYERUNITS[PlayerName] = nil end @@ -750,7 +751,7 @@ function DATABASE:_RegisterPlayers() local UnitName = UnitData:getName() local PlayerName = UnitData:getPlayerName() if not self.PLAYERS[PlayerName] then - self:E( { "Add player for unit:", UnitName, PlayerName } ) + self:I( { "Add player for unit:", UnitName, PlayerName } ) self:AddPlayer( UnitName, PlayerName ) end end @@ -773,13 +774,13 @@ function DATABASE:_RegisterGroupsAndUnits() if DCSGroup:isExist() then local DCSGroupName = DCSGroup:getName() - self:E( { "Register Group:", DCSGroupName } ) + self:I( { "Register Group:", DCSGroupName } ) self:AddGroup( DCSGroupName ) for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do local DCSUnitName = DCSUnit:getName() - self:E( { "Register Unit:", DCSUnitName } ) + self:I( { "Register Unit:", DCSUnitName } ) self:AddUnit( DCSUnitName ) end else @@ -788,6 +789,11 @@ function DATABASE:_RegisterGroupsAndUnits() end end + + self:I("Groups:") + for GroupName, Group in pairs( self.GROUPS ) do + self:I( { "Group:", GroupName } ) + end return self end @@ -798,7 +804,7 @@ end function DATABASE:_RegisterClients() for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do - self:E( { "Register Client:", ClientName } ) + self:I( { "Register Client:", ClientName } ) self:AddClient( ClientName ) end @@ -809,14 +815,14 @@ end function DATABASE:_RegisterStatics() local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) } - self:E( { Statics = CoalitionsData } ) + self:I( { Statics = CoalitionsData } ) for CoalitionId, CoalitionData in pairs( CoalitionsData ) do for DCSStaticId, DCSStatic in pairs( CoalitionData ) do if DCSStatic:isExist() then local DCSStaticName = DCSStatic:getName() - self:E( { "Register Static:", DCSStaticName } ) + self:I( { "Register Static:", DCSStaticName } ) self:AddStatic( DCSStaticName ) else self:E( { "Static does not exist: ", DCSStatic } ) @@ -836,7 +842,7 @@ function DATABASE:_RegisterAirbases() local DCSAirbaseName = DCSAirbase:getName() - self:E( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } ) + self:I( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } ) self:AddAirbase( DCSAirbaseName ) end end @@ -866,9 +872,8 @@ function DATABASE:_EventOnBirth( Event ) Event.IniUnit = self:FindUnit( Event.IniDCSUnitName ) Event.IniGroup = self:FindGroup( Event.IniDCSGroupName ) local PlayerName = Event.IniUnit:GetPlayerName() - self:E( { "PlayerName:", PlayerName } ) if PlayerName then - self:E( { "Player Joined:", PlayerName } ) + self:I( { "Player Joined:", PlayerName } ) if not self.PLAYERS[PlayerName] then self:AddPlayer( Event.IniUnitName, PlayerName ) end @@ -937,7 +942,7 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event ) if Event.IniObjectCategory == 1 then local PlayerName = Event.IniUnit:GetPlayerName() if PlayerName and self.PLAYERS[PlayerName] then - self:E( { "Player Left:", PlayerName } ) + self:I( { "Player Left:", PlayerName } ) local Settings = SETTINGS:Set( PlayerName ) Settings:RemovePlayerMenu( Event.IniUnit ) self:DeletePlayer( Event.IniUnit, PlayerName ) diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index a1be00587..c7f937c8b 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -719,7 +719,7 @@ do -- Event Creation -- @param #EVENT self -- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created. function EVENT:CreateEventNewCargo( Cargo ) - self:F( { Cargo } ) + self:I( { Cargo } ) local Event = { id = EVENTS.NewCargo, diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 1cf57eb77..81d26911e 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -121,13 +121,16 @@ GROUPTEMPLATE.Takeoff = { -- @return #GROUP self function GROUP:NewTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID ) local GroupName = GroupTemplate.name + _DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName ) - self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) - self:F2( GroupName ) + + local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) self.GroupName = GroupName - - _DATABASE:AddGroup( GroupName ) - + + if not _DATABASE.GROUPS[GroupName] then + _DATABASE.GROUPS[GroupName] = self + end + self:SetEventPriority( 4 ) return self end @@ -140,7 +143,6 @@ end -- @return #GROUP self function GROUP:Register( GroupName ) local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) -- #GROUP - self:F( GroupName ) self.GroupName = GroupName self:SetEventPriority( 4 ) From 965012976933c4f0aa7856fb7bdf724c43c532fa Mon Sep 17 00:00:00 2001 From: FlightControl Date: Tue, 14 Aug 2018 22:40:28 +0200 Subject: [PATCH 26/29] AI helicopter dispatcher working to load multiple infantry groups ! --- .../Moose/AI/AI_Cargo_Airplane.lua | 11 ++- .../Moose/AI/AI_Cargo_Dispatcher.lua | 2 +- .../Moose/AI/AI_Cargo_Helicopter.lua | 85 ++++++++++++------- Moose Development/Moose/Cargo/CargoGroup.lua | 2 +- .../Moose/Wrapper/Positionable.lua | 11 +++ 5 files changed, 71 insertions(+), 40 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 8cacb48ea..638211643 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -129,10 +129,7 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) self:SetCarrier( Airplane ) local Desc = Airplane:GetUnit(1):GetDesc() - self:F({Desc=Desc}) - - Airplane:SetCargoBayWeightLimit( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) ) --Airplane:SetCargoBayVolumeLimit( 15 ) @@ -251,12 +248,15 @@ function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To ) env.info("FF load airplane "..Airplane:GetName()) self:Load( Airplane:GetCoordinate() ) self.RoutePickup = false + self.Relocating = true end -- Aircraft was send to this airbase to deploy troops. Initiate unloading. if self.RouteDeploy == true then self:Unload() self.RouteDeploy = false + self.Transporting = false + self.Relocating = false end end @@ -451,10 +451,9 @@ function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To, Cargo ) env.info("FF troops loaded into cargo plane") if Airplane and Airplane:IsAlive() then - self:F( { "Transporting" } ) - self.Transporting = true -- This will only be executed when there is no cargo boarded anymore. The dispatcher will then kick-off the deploy cycle! + self:F( { "Transporting" } ) + self.Transporting = true -- This will only be executed when there is no cargo boarded anymore. The dispatcher will then kick-off the deploy cycle! end - end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index c19d760a8..933556713 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -404,7 +404,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() -- 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( { IsRelocating = AI_Cargo:IsRelocating() } ) + self:I( { 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 diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 1e3141649..faa85affc 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -43,7 +43,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) self:AddTransition( "Unloaded", "Pickup", "*" ) self:AddTransition( "Loaded", "Deploy", "*" ) - self:AddTransition( "Unloaded", "Load", "Boarding" ) + self:AddTransition( { "Unloaded", "Loading" }, "Load", "Boarding" ) self:AddTransition( "Boarding", "Board", "Boarding" ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) @@ -144,6 +144,16 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) end ) + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local Desc = HelicopterUnit:GetDesc() + self:F({Desc=Desc}) + HelicopterUnit:SetCargoBayWeightLimit( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) ) + --Airplane:SetCargoBayVolumeLimit( 15 ) + end + + self.Relocating = false + self.Transporting = false + self:SetCarrier( Helicopter ) return self @@ -380,7 +390,6 @@ function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To) self.BoardingCount = 0 if Helicopter and Helicopter:IsAlive() then - self.Helicopter_Cargo = {} for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( self.CargoSet:GetSet() ) do @@ -393,10 +402,6 @@ function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To) Cargo:Board( HelicopterUnit, 25 ) self:__Board( 1, Cargo ) Boarding = true - - -- So now this APCUnit has Cargo that is being loaded. - -- This will be used further in the logic to follow and to check cargo status. - self.Helicopter_Cargo[HelicopterUnit] = Cargo break end end @@ -424,7 +429,27 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo ) if not Cargo:IsLoaded() then self:__Board( 10, Cargo ) else - self:__Loaded( 1, Cargo ) + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + if Cargo:IsUnLoaded() then + if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then + local CargoBayFreeWeight = HelicopterUnit:GetCargoBayFreeWeight() + local CargoWeight = Cargo:GetWeight() + + -- Only when there is space within the bay to load the next cargo item! + if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then + + Cargo:Board( HelicopterUnit, 25 ) + self:__Board( 10, Cargo ) + return + end + end + end + end + end + self:__Loaded( 1, Cargo ) -- Will only be executed when no more cargo is boarded. end end @@ -438,24 +463,12 @@ end -- @param #string To To state. -- @param Cargo.Cargo#CARGO Cargo Cargo object. -- @return #boolean Cargo is loaded. -function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To, Cargo ) +function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To, Cargo ) self:F( { Helicopter, From, Event, To, Cargo } ) - local Loaded = true - if Helicopter and Helicopter:IsAlive() then - for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do - local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) - if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then - Loaded = false - end - end - + self.Transporting = true end - - return Loaded - end @@ -471,9 +484,11 @@ function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To, Deploye for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do - Cargo:UnBoard() - Cargo:SetDeployed( true ) - self:__Unboard( 10, Cargo, Deployed ) + if Cargo:IsLoaded() then + Cargo:UnBoard() + Cargo:SetDeployed( true ) + self:__Unboard( 10, Cargo, Deployed ) + end end end end @@ -495,6 +510,17 @@ function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To, Cargo, if not Cargo:IsUnLoaded() then self:__Unboard( 10, Cargo, Deployed ) else + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do + if Cargo:IsLoaded() then + Cargo:UnBoard() + Cargo:SetDeployed( true ) + self:__Unboard( 10, Cargo, Deployed ) + return + end + end + end self:__Unloaded( 1, Cargo, Deployed ) end end @@ -519,21 +545,16 @@ function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To, Carg if Helicopter and Helicopter:IsAlive() then for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do - local CargoCheck = self.Helicopter_Cargo[HelicopterUnit] -- Cargo.Cargo#CARGO - if CargoCheck then - self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) - if CargoCheck:IsUnLoaded() == false then + local IsEmpty = HelicopterUnit:IsCargoEmpty() + self:I({ IsEmpty = IsEmpty }) + if not IsEmpty then AllUnloaded = false break - end end end if AllUnloaded == true then if Deployed == true then - for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do - local Cargo = Cargo -- Cargo.Cargo#CARGO - end self.Helicopter_Cargo = {} end self.Helicopter = Helicopter diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index b51e5502c..9a0294855 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -101,7 +101,7 @@ do -- CARGO_GROUP end -- Then we register the new group in the database - GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID ) + self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID ) -- Now we spawn the new group based on the template created. self.CargoObject = _DATABASE:Spawn( GroupTemplate ) diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 1de5c21fe..017c5f70f 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -840,6 +840,17 @@ do -- Cargo self.__.Cargo = {} end + --- Is cargo bay empty. + -- @param #POSITIONABLE self + function POSITIONABLE:IsCargoEmpty() + local IsEmpty = true + for _, Cargo in pairs( self.__.Cargo ) do + IsEmpty = false + break + end + return IsEmpty + end + --- Get cargo item count. -- @param #POSITIONABLE self -- @return Core.Cargo#CARGO Cargo From a02d3c195013fff3f79d87a22db46f768b8605e5 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Fri, 17 Aug 2018 07:59:53 +0200 Subject: [PATCH 27/29] Cargo Dispatcher APC - Multiple Cargo Groups and Weight in APC --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 97 +++++++++++++++---- .../Moose/AI/AI_Cargo_Dispatcher.lua | 5 + .../Moose/AI/AI_Cargo_Dispatcher_APC.lua | 4 +- .../Moose/AI/AI_Cargo_Helicopter.lua | 5 +- Moose Development/Moose/Cargo/Cargo.lua | 3 +- Moose Development/Moose/Cargo/CargoGroup.lua | 13 ++- .../Moose/Wrapper/Positionable.lua | 1 - 7 files changed, 97 insertions(+), 31 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 13f88324e..fbe2dd1f4 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -96,7 +96,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) self:AddTransition( "Loaded", "Deploy", "*" ) self:AddTransition( "*", "Load", "Boarding" ) - self:AddTransition( "Boarding", "Board", "Boarding" ) + self:AddTransition( { "Boarding", "Loaded" }, "Board", "Boarding" ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) self:AddTransition( "Unboarding", "Unboard", "Unboarding" ) @@ -194,8 +194,20 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) self:__Monitor( 1 ) - self:SetCarrier( APC ) + + for _, APCUnit in pairs( APC:GetUnits() ) do + local Desc = APCUnit:GetDesc() + self:F({Desc=Desc}) +-- local Box = CargoUnit:GetBoundingBox() + local VolumeUnit = ( Desc.box.max.x - Desc.box.min.x ) * ( Desc.box.max.y - Desc.box.min.y ) * ( Desc.box.max.z - Desc.box.min.z ) + self:F({VolumeUnit=VolumeUnit}) + local CargoBayWeightLimit = 1250 + APCUnit:SetCargoBayWeightLimit( CargoBayWeightLimit ) + self:F({CargoBayWeightLimit=CargoBayWeightLimit}) + --Airplane:SetCargoBayVolumeLimit( 15 ) + end + self.Transporting = false self.Relocating = false @@ -411,7 +423,6 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) self:F( { APC, From, Event, To } ) local Boarding = false - self.BoardingCount = 0 if APC and APC:IsAlive() then self.APC_Cargo = {} @@ -427,11 +438,11 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) --Cargo:Ungroup() Cargo:Board( APCUnit, 25 ) self:__Board( 1, Cargo ) - Boarding = true - + -- So now this APCUnit has Cargo that is being loaded. -- This will be used further in the logic to follow and to check cargo status. self.APC_Cargo[APCUnit] = Cargo + Boarding = true break end end @@ -458,7 +469,31 @@ function AI_CARGO_APC:onafterBoard( APC, From, Event, To, Cargo ) if not Cargo:IsLoaded() then self:__Board( 10, Cargo ) else - self:__Loaded( 1 ) + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + if Cargo:IsUnLoaded() then + if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then + local CargoBayFreeWeight = APCUnit:GetCargoBayFreeWeight() + local CargoWeight = Cargo:GetWeight() + + self:F({CargoBayFreeWeight=CargoBayFreeWeight}) + + -- Only when there is space within the bay to load the next cargo item! + if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then + Cargo:Board( APCUnit, 25 ) + self:__Board( 10, Cargo ) + -- So now this APCUnit has Cargo that is being loaded. + -- This will be used further in the logic to follow and to check cargo status. + self.APC_Cargo[APCUnit] = Cargo + return + end + end + end + end + end + self:__Loaded( 5, Cargo ) end end @@ -471,7 +506,7 @@ end -- @param #string Event Event. -- @param #string To To state. -- @return #boolean Cargo loaded. -function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To ) +function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To, Cargo ) self:F( { APC, From, Event, To } ) local Loaded = true @@ -484,7 +519,6 @@ function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To ) Loaded = false end end - end if Loaded == true then @@ -496,6 +530,9 @@ function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To ) end + + + --- On after Unload event. -- @param #AI_CARGO_APC self -- @param Wrapper.Group#GROUP APC @@ -512,6 +549,7 @@ function AI_CARGO_APC:onafterUnload( APC, From, Event, To, Deployed ) APC:RouteStop() for _, Cargo in pairs( APCUnit:GetCargo() ) do Cargo:UnBoard() + Cargo:SetDeployed( true ) self:__Unboard( 10, Cargo, Deployed ) end end @@ -534,6 +572,17 @@ function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo, Deployed ) if not Cargo:IsUnLoaded() then self:__Unboard( 10, Cargo, Deployed ) else + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( APCUnit:GetCargo() ) do + if Cargo:IsLoaded() then + Cargo:UnBoard() + Cargo:SetDeployed( true ) + self:__Unboard( 10, Cargo, Deployed ) + return + end + end + end self:__Unloaded( 1, Cargo, Deployed ) end end @@ -559,22 +608,16 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo, Deployed ) if APC and APC:IsAlive() then for _, APCUnit in pairs( APC:GetUnits() ) do local APCUnit = APCUnit -- Wrapper.Unit#UNIT - local CargoCheck = self.APC_Cargo[APCUnit] - if CargoCheck then - self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) - if CargoCheck:IsUnLoaded() == false then - AllUnloaded = false - break - end + local IsEmpty = APCUnit:IsCargoEmpty() + self:I({ IsEmpty = IsEmpty }) + if not IsEmpty then + AllUnloaded = false + break end end if AllUnloaded == true then if Deployed == true then - for APCUnit, Cargo in pairs( self.APC_Cargo ) do - local Cargo = Cargo -- Cargo.Cargo#CARGO - Cargo:SetDeployed( true ) - end self.APC_Cargo = {} end self:Guard() @@ -587,6 +630,21 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo, Deployed ) end +--- On after Unloaded event. +-- @param #AI_CARGO_APC self +-- @param Wrapper.Group#GROUP APC +-- @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. +-- @return #boolean All cargo unloaded. +function AI_CARGO_APC:onafterUnloaded( APC, From, Event, To, Cargo, Deployed ) + self:F( { APC, From, Event, To, Cargo:GetName(), Deployed = Deployed } ) + + self.Transporting = false + +end --- On after Follow event. -- @param #AI_CARGO_APC self @@ -632,7 +690,6 @@ function AI_CARGO_APC._Deploy( APC, self ) if APC:IsAlive() then self:Unload( true ) - self.Transporting = false self.Relocating = false end end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 933556713..9bbfe26a8 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -416,6 +416,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() 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() + self:F({CargoCoordinate = CargoCoordinate }) local CoordinateFree = true for CarrierPickup, Coordinate in pairs( self.PickupCargo ) do if CarrierPickup:IsAlive() == true then @@ -427,6 +428,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor() self.PickupCargo[CarrierPickup] = nil end end + self:F({CoordinateFree = CoordinateFree}) if CoordinateFree == true then self.PickupCargo[Carrier] = CargoCoordinate PickupCargo = Cargo @@ -435,6 +437,8 @@ function AI_CARGO_DISPATCHER:onafterMonitor() end end + self:F( { PickupCargo = PickupCargo} ) + if PickupCargo then self.CarrierHome[Carrier] = nil local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius ) @@ -567,6 +571,7 @@ function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, Carrier, Cargo ) end end + self:F({Carrier=Carrier}) self.PickupCargo[Carrier] = nil end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua index 413ca7c26..1612ce2c7 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher_APC.lua @@ -101,9 +101,9 @@ AI_CARGO_DISPATCHER_APC = { -- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart() -- AICargoDispatcher = AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, 500 ) -- -function AI_CARGO_DISPATCHER_APC:NewWithZones( SetAPC, SetCargo, SetDeployZone, CombatRadius ) +function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, CombatRadius ) - local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) ) -- #AI_CARGO_DISPATCHER_APC + local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithZones( SetAPC, SetCargo, SetDeployZone ) ) -- #AI_CARGO_DISPATCHER_APC self.CombatRadius = CombatRadius or 500 diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index faa85affc..df6865545 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -395,7 +395,7 @@ function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To) for _, Cargo in pairs( self.CargoSet:GetSet() ) do local Cargo = Cargo -- Cargo.Cargo#CARGO self:F( { IsUnLoaded = Cargo:IsUnLoaded() } ) - if Cargo:IsUnLoaded() then + if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then self:F( { "In radius", HelicopterUnit:GetName() } ) --Cargo:Ungroup() @@ -440,7 +440,6 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo ) -- Only when there is space within the bay to load the next cargo item! if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then - Cargo:Board( HelicopterUnit, 25 ) self:__Board( 10, Cargo ) return @@ -455,7 +454,7 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo ) end ---- On before Loaded event. Check if cargo is loaded. +--- On after Loaded event. Check if cargo is loaded. -- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -- @param #string From From state. diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 50cade298..3311a1bff 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -779,7 +779,8 @@ do -- CARGO local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) + local CargoCoordinate = self.CargoObject:GetCoordinate() + Distance = Coordinate:Get2DDistance( CargoCoordinate ) self:T( Distance ) if Distance <= self.LoadRadius then return true diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index 9a0294855..63f9203d1 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -500,8 +500,6 @@ do -- CARGO_GROUP -- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup. -- @return #nil There is no valid Cargo in the CargoGroup. function CARGO_GROUP:GetCoordinate() - self:F() - local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO if Cargo then @@ -635,12 +633,19 @@ do -- CARGO_GROUP if Cargo then local Distance = 0 + local CargoCoordinate if Cargo:IsLoaded() then - Distance = Coordinate:Get2DDistance( Cargo.CargoCarrier:GetCoordinate() ) + CargoCoordinate = Cargo.CargoCarrier:GetCoordinate() else - Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() ) + CargoCoordinate = Cargo.CargoObject:GetCoordinate() end +-- if CargoCoordinate then + Distance = Coordinate:Get2DDistance( CargoCoordinate ) +-- else +-- return false +-- end + self:F( { Distance = Distance, LoadRadius = self.LoadRadius } ) if Distance <= self.LoadRadius then return true diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 017c5f70f..287338c2b 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -879,7 +879,6 @@ do -- Cargo function POSITIONABLE:GetCargoBayFreeWeight() local CargoWeight = 0 for CargoName, Cargo in pairs( self.__.Cargo ) do - self:F( { Cargo = Cargo } ) CargoWeight = CargoWeight + Cargo:GetWeight() end return self.__.CargoBayWeightLimit - CargoWeight From 7a2dee41624ea9d4e7690455c2bac9624d2b639f Mon Sep 17 00:00:00 2001 From: FlightControl Date: Sun, 19 Aug 2018 07:26:50 +0200 Subject: [PATCH 28/29] OK. Revised cargo for AI is working. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 74 ++++++++++++++----- .../Moose/AI/AI_Cargo_Dispatcher.lua | 8 -- .../Moose/AI/AI_Cargo_Helicopter.lua | 58 +++++++++++++-- 3 files changed, 107 insertions(+), 33 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index fbe2dd1f4..acf565f81 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -198,14 +198,41 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) for _, APCUnit in pairs( APC:GetUnits() ) do local Desc = APCUnit:GetDesc() - self:F({Desc=Desc}) --- local Box = CargoUnit:GetBoundingBox() + local VolumeUnit = ( Desc.box.max.x - Desc.box.min.x ) * ( Desc.box.max.y - Desc.box.min.y ) * ( Desc.box.max.z - Desc.box.min.z ) - self:F({VolumeUnit=VolumeUnit}) - local CargoBayWeightLimit = 1250 + + local Weights = { + ["M1126 Stryker ICV"] = 9, + ["M-113"] = 9, + ["AAV7"] = 25, + ["M2A1_halftrack"] = 9, + ["BMD-1"] = 9, + ["BMP-1"] = 8, + ["BMP-2"] = 7, + ["BMP-3"] = 8, + ["Boman"] = 25, + ["BTR-80"] = 9, + ["BTR_D"] = 12, + ["Cobra"] = 8, + ["LAV-25"] = 6, + ["M-2 Bradley"] = 6, + ["M1043 HMMWV Armament"] = 4, + ["M1045 HMMWV TOW"] = 4, + ["M1126 Stryker ICV"] = 9, + ["M1134 Stryker ATGM"] = 9, + ["Marder"] = 6, + ["MCV-80"] = 9, + ["MLRS FDDM"] = 4, + ["MTLB"] = 25, + ["TPZ"] = 10, + } + + local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 70 + APCUnit:SetCargoBayWeightLimit( CargoBayWeightLimit ) - self:F({CargoBayWeightLimit=CargoBayWeightLimit}) --Airplane:SetCargoBayVolumeLimit( 15 ) + + self:F( {TypeName = Desc.typeName, Desc = Desc, WeightLimit = CargoBayWeightLimit } ) end self.Transporting = false @@ -434,16 +461,25 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then self:F( { "In radius", APCUnit:GetName() } ) - APC:RouteStop() - --Cargo:Ungroup() - Cargo:Board( APCUnit, 25 ) - self:__Board( 1, Cargo ) + + local CargoBayFreeWeight = APCUnit:GetCargoBayFreeWeight() + local CargoWeight = Cargo:GetWeight() + + self:F({CargoBayFreeWeight=CargoBayFreeWeight}) - -- So now this APCUnit has Cargo that is being loaded. - -- This will be used further in the logic to follow and to check cargo status. - self.APC_Cargo[APCUnit] = Cargo - Boarding = true - break + -- Only when there is space within the bay to load the next cargo item! + if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then + APC:RouteStop() + --Cargo:Ungroup() + Cargo:Board( APCUnit, 25 ) + self:__Board( 1, Cargo ) + + -- So now this APCUnit has Cargo that is being loaded. + -- This will be used further in the logic to follow and to check cargo status. + self.APC_Cargo[APCUnit] = Cargo + Boarding = true + break + end end end end @@ -548,10 +584,12 @@ function AI_CARGO_APC:onafterUnload( APC, From, Event, To, Deployed ) local APCUnit = APCUnit -- Wrapper.Unit#UNIT APC:RouteStop() for _, Cargo in pairs( APCUnit:GetCargo() ) do - Cargo:UnBoard() - Cargo:SetDeployed( true ) - self:__Unboard( 10, Cargo, Deployed ) - end + if Cargo:IsLoaded() then + Cargo:UnBoard() + Cargo:SetDeployed( true ) + self:__Unboard( 10, Cargo, Deployed ) + end + end end end diff --git a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua index 9bbfe26a8..602868607 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Dispatcher.lua @@ -416,7 +416,6 @@ function AI_CARGO_DISPATCHER:onafterMonitor() 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() - self:F({CargoCoordinate = CargoCoordinate }) local CoordinateFree = true for CarrierPickup, Coordinate in pairs( self.PickupCargo ) do if CarrierPickup:IsAlive() == true then @@ -428,7 +427,6 @@ function AI_CARGO_DISPATCHER:onafterMonitor() self.PickupCargo[CarrierPickup] = nil end end - self:F({CoordinateFree = CoordinateFree}) if CoordinateFree == true then self.PickupCargo[Carrier] = CargoCoordinate PickupCargo = Cargo @@ -437,8 +435,6 @@ function AI_CARGO_DISPATCHER:onafterMonitor() end end - self:F( { PickupCargo = PickupCargo} ) - if PickupCargo then self.CarrierHome[Carrier] = nil local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius ) @@ -571,10 +567,6 @@ function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, Carrier, Cargo ) end end - self:F({Carrier=Carrier}) self.PickupCargo[Carrier] = nil end - - - diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index df6865545..1341129f6 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -20,7 +20,8 @@ -- @field #AI_CARGO_HELICOPTER AI_CARGO_HELICOPTER = { ClassName = "AI_CARGO_HELICOPTER", - Coordinate = nil -- Core.Point#COORDINATE, + Coordinate = nil, -- Core.Point#COORDINATE, + Helicopter_Cargo = {}, } AI_CARGO_QUEUE = {} @@ -148,7 +149,6 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) local Desc = HelicopterUnit:GetDesc() self:F({Desc=Desc}) HelicopterUnit:SetCargoBayWeightLimit( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) ) - --Airplane:SetCargoBayVolumeLimit( 15 ) end self.Relocating = false @@ -398,11 +398,22 @@ function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To) if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then self:F( { "In radius", HelicopterUnit:GetName() } ) - --Cargo:Ungroup() - Cargo:Board( HelicopterUnit, 25 ) - self:__Board( 1, Cargo ) - Boarding = true - break + + local CargoBayFreeWeight = HelicopterUnit:GetCargoBayFreeWeight() + local CargoWeight = Cargo:GetWeight() + + self:F({CargoBayFreeWeight=CargoBayFreeWeight}) + + -- Only when there is space within the bay to load the next cargo item! + if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then + + --Cargo:Ungroup() + Cargo:Board( HelicopterUnit, 25 ) + self:__Board( 1, Cargo ) + self.Helicopter_Cargo[HelicopterUnit] = Cargo + Boarding = true + break + end end end end @@ -438,10 +449,13 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo ) local CargoBayFreeWeight = HelicopterUnit:GetCargoBayFreeWeight() local CargoWeight = Cargo:GetWeight() + self:F({CargoBayFreeWeight=CargoBayFreeWeight}) + -- Only when there is space within the bay to load the next cargo item! if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then Cargo:Board( HelicopterUnit, 25 ) self:__Board( 10, Cargo ) + self.Helicopter_Cargo[HelicopterUnit] = Cargo return end end @@ -454,6 +468,36 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo ) end + +--- On before Loaded event. +-- @param #AI_CARGO_HELICOPTER self +-- @param Wrapper.Group#GROUP Helicopter +-- @param #string From From state. +-- @param #string Event Event. +-- @param #string To To state. +-- @return #boolean Cargo loaded. +function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To, Cargo ) + self:F( { Helicopter, From, Event, To } ) + + local Loaded = true + + if Helicopter and Helicopter:IsAlive() then + for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), Helicopter:GetName() } ) + if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then + Loaded = false + end + end + end + + return Loaded + +end + + + + --- On after Loaded event. Check if cargo is loaded. -- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter From bf903c0cc71eade75171e20d3b35183199cc8ad6 Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 22 Aug 2018 20:41:37 +0200 Subject: [PATCH 29/29] New weight driven limits logic for cargo to load multiple cargo. Fixed near range issue for carriers. now the infantry disappearance range for boarding is calculated by the carrier bounding range, which is derived from the bounding rectangle on the Y-axis. The near range parameter can still be provided and will be interpreted as the loading range for static cargo objects! --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 37 +----- .../Moose/AI/AI_Cargo_Airplane.lua | 5 +- .../Moose/AI/AI_Cargo_Helicopter.lua | 4 +- Moose Development/Moose/Cargo/Cargo.lua | 2 +- Moose Development/Moose/Cargo/CargoUnit.lua | 11 +- .../Moose/Tasking/Task_CARGO.lua | 15 ++- .../Moose/Wrapper/Positionable.lua | 121 +++++++++++++++++- Moose Development/Moose/Wrapper/Unit.lua | 44 ------- 8 files changed, 134 insertions(+), 105 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index acf565f81..c1c871cdd 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -197,42 +197,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius ) self:SetCarrier( APC ) for _, APCUnit in pairs( APC:GetUnits() ) do - local Desc = APCUnit:GetDesc() - - local VolumeUnit = ( Desc.box.max.x - Desc.box.min.x ) * ( Desc.box.max.y - Desc.box.min.y ) * ( Desc.box.max.z - Desc.box.min.z ) - - local Weights = { - ["M1126 Stryker ICV"] = 9, - ["M-113"] = 9, - ["AAV7"] = 25, - ["M2A1_halftrack"] = 9, - ["BMD-1"] = 9, - ["BMP-1"] = 8, - ["BMP-2"] = 7, - ["BMP-3"] = 8, - ["Boman"] = 25, - ["BTR-80"] = 9, - ["BTR_D"] = 12, - ["Cobra"] = 8, - ["LAV-25"] = 6, - ["M-2 Bradley"] = 6, - ["M1043 HMMWV Armament"] = 4, - ["M1045 HMMWV TOW"] = 4, - ["M1126 Stryker ICV"] = 9, - ["M1134 Stryker ATGM"] = 9, - ["Marder"] = 6, - ["MCV-80"] = 9, - ["MLRS FDDM"] = 4, - ["MTLB"] = 25, - ["TPZ"] = 10, - } - - local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 70 - - APCUnit:SetCargoBayWeightLimit( CargoBayWeightLimit ) - --Airplane:SetCargoBayVolumeLimit( 15 ) - - self:F( {TypeName = Desc.typeName, Desc = Desc, WeightLimit = CargoBayWeightLimit } ) + APCUnit:SetCargoBayWeightLimit() end self.Transporting = false diff --git a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua index 638211643..1d5d1e398 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Airplane.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Airplane.lua @@ -128,10 +128,7 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet ) -- Set carrier. self:SetCarrier( Airplane ) - local Desc = Airplane:GetUnit(1):GetDesc() - self:F({Desc=Desc}) - Airplane:SetCargoBayWeightLimit( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) ) - --Airplane:SetCargoBayVolumeLimit( 15 ) + Airplane:SetCargoBayWeightLimit() self.Relocating = true diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 1341129f6..0148e9c79 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -146,9 +146,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet ) ) for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do - local Desc = HelicopterUnit:GetDesc() - self:F({Desc=Desc}) - HelicopterUnit:SetCargoBayWeightLimit( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) ) + HelicopterUnit:SetCargoBayWeightLimit() end self.Relocating = false diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 3311a1bff..82015511e 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -811,7 +811,7 @@ do -- CARGO end - --- Check if CargoCarrier is near the Cargo to be Loaded. + --- Check if CargoCarrier is near the coordinate within NearRadius. -- @param #CARGO self -- @param Core.Point#COORDINATE Coordinate -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 90eceeda9..da9c73f2b 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -226,8 +226,6 @@ do -- CARGO_UNIT function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) self:F( { From, Event, To, CargoCarrier, NearRadius } ) - local NearRadius = NearRadius or 25 - self.CargoInAir = self.CargoObject:InAir() local Desc = self.CargoObject:GetDesc() @@ -239,6 +237,9 @@ do -- CARGO_UNIT -- Only move the group to the carrier when the cargo is not in the air -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea). if not self.CargoInAir then + -- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius + -- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis. + local NearRadius = CargoCarrier:GetBoundingRadius( NearRadius ) if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then self:Load( CargoCarrier, NearRadius, ... ) else @@ -250,8 +251,6 @@ do -- CARGO_UNIT local Angle = 180 local Distance = 5 - NearRadius = NearRadius or 25 - 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 ) @@ -302,8 +301,6 @@ do -- CARGO_UNIT local Angle = 180 local Distance = 5 - NearRadius = NearRadius or 25 - 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 ) @@ -349,8 +346,6 @@ do -- CARGO_UNIT local Angle = 180 local Distance = 5 - local NearRadius = NearRadius or 25 - if From == "UnLoaded" or From == "Boarding" then end diff --git a/Moose Development/Moose/Tasking/Task_CARGO.lua b/Moose Development/Moose/Tasking/Task_CARGO.lua index fd1d60ef7..ae4ebc7b8 100644 --- a/Moose Development/Moose/Tasking/Task_CARGO.lua +++ b/Moose Development/Moose/Tasking/Task_CARGO.lua @@ -589,6 +589,12 @@ do -- TASK_CARGO Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) Fsm:AddTransition( "Failed", "Fail", "Failed" ) + for _, Group in pairs( SetGroup:GetSet() ) do + for __, Unit in pairs( Group:GetUnits() ) do + local Unit = Unit -- Wrapper.Unit#UNIT + Unit:SetCargoBayWeightLimit() + end + end ---- @param #FSM_PROCESS self -- @param Wrapper.Unit#UNIT TaskUnit @@ -610,7 +616,6 @@ do -- TASK_CARGO local TaskUnitName = TaskUnit:GetName() local MenuTime = Task:InitTaskControlMenu( TaskUnit ) local MenuControl = Task:GetTaskControlMenu( TaskUnit ) - local CargoItemCount = TaskUnit:CargoItemCount() Task.SetCargo:ForEachCargo( @@ -635,7 +640,13 @@ do -- TASK_CARGO local TaskGroup = TaskUnit:GetGroup() if Cargo:IsUnLoaded() then - if CargoItemCount < 1 then + local CargoBayFreeWeight = TaskUnit:GetCargoBayFreeWeight() + local CargoWeight = Cargo:GetWeight() + + self:F({CargoBayFreeWeight=CargoBayFreeWeight}) + + -- Only when there is space within the bay to load the next cargo item! + if CargoBayFreeWeight > CargoWeight then if Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then local NotInDeployZones = true for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 287338c2b..b0200fd24 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -243,7 +243,7 @@ end --- Get the bounding box of the underlying POSITIONABLE DCS Object. -- @param #POSITIONABLE self --- @return DCS#Distance The bounding box of the POSITIONABLE. +-- @return DCS#Box3 The bounding box of the POSITIONABLE. -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetBoundingBox() --R2.1 self:F2() @@ -264,6 +264,29 @@ function POSITIONABLE:GetBoundingBox() --R2.1 end +--- Get the bounding radius of the underlying POSITIONABLE DCS Object. +-- @param #POSITIONABLE self +-- @return DCS#Distance The bounding radius of the POSITIONABLE. +-- @return #nil The POSITIONABLE is not existing or alive. +function POSITIONABLE:GetBoundingRadius() + self:F2() + + local Box = self:GetBoundingBox() + + + if Box then + local X = Box.max.x - Box.min.x + local Z = Box.max.z - Box.min.z + local CX = X / 2 + local CZ = Z / 2 + return math.max( CX, CZ ) + end + + BASE:E( { "Cannot GetBoundingRadius", Positionable = self, Alive = self:IsAlive() } ) + + return nil +end + --- Returns the altitude of the POSITIONABLE. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Distance The altitude of the POSITIONABLE. @@ -323,7 +346,7 @@ end --- Returns the POSITIONABLE heading in degrees. -- @param Wrapper.Positionable#POSITIONABLE self --- @return #number The POSTIONABLE heading +-- @return #number The POSITIONABLE heading -- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetHeading() local DCSPositionable = self:GetDCSObject() @@ -347,6 +370,52 @@ function POSITIONABLE:GetHeading() return nil end +-- Is Methods + +--- Returns if the unit is of an air category. +-- If the unit is a helicopter or a plane, then this method will return true, otherwise false. +-- @param #POSITIONABLE self +-- @return #boolean Air category evaluation result. +function POSITIONABLE:IsAir() + self:F2() + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitDescriptor = DCSUnit:getDesc() + self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) + + local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER ) + + self:T3( IsAirResult ) + return IsAirResult + end + + return nil +end + +--- Returns if the unit is of an ground category. +-- If the unit is a ground vehicle or infantry, this method will return true, otherwise false. +-- @param #POSITIONABLE self +-- @return #boolean Ground category evaluation result. +function POSITIONABLE:IsGround() + self:F2() + + local DCSUnit = self:GetDCSObject() + + if DCSUnit then + local UnitDescriptor = DCSUnit:getDesc() + self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } ) + + local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT ) + + self:T3( IsGroundResult ) + return IsGroundResult + end + + return nil +end + --- Returns true if the POSITIONABLE is in the air. -- Polymorphic, is overridden in GROUP and UNIT. @@ -895,12 +964,50 @@ do -- Cargo -- @param #POSITIONABLE self -- @param #number WeightLimit function POSITIONABLE:SetCargoBayWeightLimit( WeightLimit ) - self.__.CargoBayWeightLimit = WeightLimit - end - - - + if WeightLimit then + self.__.CargoBayWeightLimit = WeightLimit + else + -- If weightlimit is not provided, we will calculate it depending on the type of unit. + + -- When an airplane or helicopter, we calculate the weightlimit based on the descriptor. + if self:IsAir() then + local Desc = self:GetDesc() + self:F({Desc=Desc}) + self.__.CargoBayWeightLimit = Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) + else + local Desc = self:GetDesc() + local Weights = { + ["M1126 Stryker ICV"] = 9, + ["M-113"] = 9, + ["AAV7"] = 25, + ["M2A1_halftrack"] = 9, + ["BMD-1"] = 9, + ["BMP-1"] = 8, + ["BMP-2"] = 7, + ["BMP-3"] = 8, + ["Boman"] = 25, + ["BTR-80"] = 9, + ["BTR_D"] = 12, + ["Cobra"] = 8, + ["LAV-25"] = 6, + ["M-2 Bradley"] = 6, + ["M1043 HMMWV Armament"] = 4, + ["M1045 HMMWV TOW"] = 4, + ["M1126 Stryker ICV"] = 9, + ["M1134 Stryker ATGM"] = 9, + ["Marder"] = 6, + ["MCV-80"] = 9, + ["MLRS FDDM"] = 4, + ["MTLB"] = 25, + ["TPZ"] = 10, + } + + local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 70 + self.__.CargoBayWeightLimit = CargoBayWeightLimit + end + end + end end --- Cargo --- Signal a flare at the position of the POSITIONABLE. diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 753b842f4..059a0266c 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -854,51 +854,7 @@ end --- Is methods ---- Returns if the unit is of an air category. --- If the unit is a helicopter or a plane, then this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Air category evaluation result. -function UNIT:IsAir() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) - - local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER ) - - self:T3( IsAirResult ) - return IsAirResult - end - - return nil -end - ---- Returns if the unit is of an ground category. --- If the unit is a ground vehicle or infantry, this method will return true, otherwise false. --- @param #UNIT self --- @return #boolean Ground category evaluation result. -function UNIT:IsGround() - self:F2() - - local DCSUnit = self:GetDCSObject() - - if DCSUnit then - local UnitDescriptor = DCSUnit:getDesc() - self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } ) - - local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT ) - - self:T3( IsGroundResult ) - return IsGroundResult - end - - return nil -end --- Returns if the unit is a friendly unit. -- @param #UNIT self