From 3b4b3854180da37b038b9fede14da2b2a831a199 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 8 Feb 2026 12:06:13 +0100 Subject: [PATCH 1/2] #CARGO Removal in Warehouse functions --- .../Moose/Functional/Warehouse.lua | 268 ++++-------------- Moose Development/Moose/Ops/FlightGroup.lua | 2 +- Moose Development/Moose/Ops/OpsGroup.lua | 20 +- Moose Development/Moose/Ops/OpsTransport.lua | 6 +- 4 files changed, 80 insertions(+), 216 deletions(-) diff --git a/Moose Development/Moose/Functional/Warehouse.lua b/Moose Development/Moose/Functional/Warehouse.lua index 6db991fd6..597c81fe1 100644 --- a/Moose Development/Moose/Functional/Warehouse.lua +++ b/Moose Development/Moose/Functional/Warehouse.lua @@ -35,7 +35,6 @@ -- === -- -- ### Author: **funkyfranky** --- ### Co-author: FlightControl (cargo dispatcher classes) -- -- === -- @@ -132,14 +131,7 @@ -- a reasonable degree in DCS at the moment and hence cannot be used yet. -- -- Furthermore, ground assets can be transferred between warehouses by transport units. These are APCs, helicopters and airplanes. The transportation process is modeled --- in a realistic way by using the corresponding cargo dispatcher classes, i.e. --- --- * @{AI.AI_Cargo_Dispatcher_APC#AI_DISPATCHER_APC} --- * @{AI.AI_Cargo_Dispatcher_Helicopter#AI_DISPATCHER_HELICOPTER} --- * @{AI.AI_Cargo_Dispatcher_Airplane#AI_DISPATCHER_AIRPLANE} --- --- Depending on which cargo dispatcher is used (ground or airbore), similar considerations like in the self propelled case are necessary. Howver, note that --- the dispatchers as of yet cannot use user defined off road paths for example since they are classes of their own and use a different routing logic. +-- in a realistic way by using the @{Ops.OpsTransport#OPSTRANSPORT} class. -- -- === -- @@ -230,18 +222,6 @@ -- of 630 kg. This is important as groups cannot be split between carrier units when transporting, i.e. the total weight of the whole group must be smaller than the -- cargo bay of the transport carrier. -- --- ### Setting the Load Radius --- Boading and loading of cargo into a carrier is modeled in a realistic fashion in the AI\_CARGO\DISPATCHER classes, which are used inernally by the WAREHOUSE class. --- Meaning that troops (cargo) will board, i.e. run or drive to the carrier, and only once they are in close proximity to the transporter they will be loaded (disappear). --- --- Unfortunately, there are some situations where problems can occur. For example, in DCS tanks have the strong tentendcy not to drive around obstacles but rather to roll over them. --- I have seen cases where an aircraft of the same coalition as the tank was in its way and the tank drove right through the plane waiting on a parking spot and destroying it. --- --- As a workaround it is possible to set a larger load radius so that the cargo units are despawned further away from the carrier via the optional **loadradius** parameter: --- --- warehouseBatumi:AddAsset("Leopard 2", nil, nil, nil, nil, 250) --- --- Adding the asset like this will cause the units to be loaded into the carrier already at a distance of 250 meters. -- -- ### Setting the AI Skill -- @@ -486,7 +466,7 @@ -- and the road connection is less than 3 km. -- -- The user can set the road connection manually with the @{#WAREHOUSE.SetRoadConnection} function. This is only functional for self propelled assets at the moment --- and not if using the AI dispatcher classes since these have a different logic to find the route. +-- and not if using the OPSTRANSPORT class since this has a different logic to find the route. -- -- ## Off Road Connections -- @@ -595,7 +575,7 @@ -- -- ## Cargo Bay and Weight Limitations -- --- The transportation of cargo is handled by the AI\_Dispatcher classes. These take the cargo bay of a carrier and the weight of +-- The transportation of cargo is handled by the `OPSTRANSPORT` class. This takes the cargo bay of a carrier and the weight of -- the cargo into account so that a carrier can only load a realistic amount of cargo. -- -- However, if troops are supposed to be transported between warehouses, there is one important limitations one has to keep in mind. @@ -1798,12 +1778,13 @@ _WAREHOUSEDB = { --- Warehouse class version. -- @field #string version -WAREHOUSE.version="1.0.2a" +WAREHOUSE.version="2.0.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: Warehouse todo list. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- DONE: Switch from AI Dispatchers to OPSTRANSPORT -- TODO: Add check if assets "on the move" are stationary. Can happen if ground units get stuck in buildings. If stationary auto complete transport by adding assets to request warehouse? Time? -- TODO: Optimize findpathonroad. Do it only once (first time) and safe paths between warehouses similar to off-road paths. -- NOGO: Spawn assets only virtually, i.e. remove requested assets from stock but do NOT spawn them ==> Interface to A2A dispatcher! Maybe do a negative sign on asset number? @@ -3743,12 +3724,15 @@ function WAREHOUSE:_JobDone() -- Check conditions for being back home. local ishome=false - if category==Group.Category.GROUND or category==Group.Category.HELICOPTER then - -- Units go back to the spawn zone, helicopters land and they should not move any more. - ishome=inspawnzone and onground and notmoving + if category==Group.Category.GROUND then + -- Ground units go back to the spawn zone and they should not move any more. + ishome=inspawnzone and notmoving elseif category==Group.Category.AIRPLANE then -- Planes need to be on ground at their home airbase and should not move any more. ishome=athomebase and onground and notmoving + elseif category==Group.Category.HELICOPTER then + -- Helicopters go back to their airbase or spawn zone and should not move any more. + ishome=(athomebase or inspawnzone) and onground and notmoving end -- Debug text. @@ -4697,136 +4681,48 @@ function WAREHOUSE:onafterRequestSpawned(From, Event, To, Request, CargoGroupSet ------------------------------------------------------------------------------------------------------------------------------------ -- Prepare cargo groups for transport ------------------------------------------------------------------------------------------------------------------------------------ + + -- TODO: set asset.weight for cargos - -- Board radius, i.e. when the cargo will begin to board the carrier - local _boardradius=500 + ------------------------- + -- Create OPSTRANSPORT -- + ------------------------- - if Request.transporttype==WAREHOUSE.TransportType.AIRPLANE then - _boardradius=5000 - elseif Request.transporttype==WAREHOUSE.TransportType.HELICOPTER then - --_loadradius=1000 - --_boardradius=nil - elseif Request.transporttype==WAREHOUSE.TransportType.APC then - --_boardradius=nil - elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER - or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then - _boardradius=6000 - end - - -- Empty cargo group set. - local CargoGroups=SET_CARGO:New() - - -- Add cargo groups to set. - for _,_group in pairs(CargoGroupSet:GetSetObjects()) do - - -- Find asset belonging to this group. - local asset=self:FindAssetInDB(_group) - -- New cargo group object. - local cargogroup=CARGO_GROUP:New(_group, _cargotype,_group:GetName(),_boardradius, asset.loadradius) - - -- Set weight for this group. - cargogroup:SetWeight(asset.weight) - - -- Add group to group set. - CargoGroups:AddCargo(cargogroup) - - end - - ------------------------ - -- Create Dispatchers -- - ------------------------ - - -- Cargo dispatcher. - local CargoTransport --AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER + -- OPSTRANSPORT + local CargoTransport --Ops.OpsTransport#OPSTRANSPORT if Request.transporttype==WAREHOUSE.TransportType.AIRPLANE then - -- Pickup and deploy zones. - local PickupAirbaseSet = SET_ZONE:New():AddZone(ZONE_AIRBASE:New(self.airbase:GetName())) - local DeployAirbaseSet = SET_ZONE:New():AddZone(ZONE_AIRBASE:New(Request.airbase:GetName())) - - -- Define dispatcher for this task. - CargoTransport = AI_CARGO_DISPATCHER_AIRPLANE:New(TransportGroupSet, CargoGroups, PickupAirbaseSet, DeployAirbaseSet) - - -- Set home zone. - CargoTransport:SetHomeZone(ZONE_AIRBASE:New(self.airbase:GetName())) + CargoTransport = OPSTRANSPORT:New(CargoGroupSet, ZONE_AIRBASE:New(self.airbase:GetName()), ZONE_AIRBASE:New(Request.airbase:GetName())) + CargoTransport:SetEmbarkZone(self.spawnzone) + CargoTransport:SetDisembarkZone(Request.warehouse.spawnzone) elseif Request.transporttype==WAREHOUSE.TransportType.HELICOPTER then - - -- Pickup and deploy zones. - local PickupZoneSet = SET_ZONE:New():AddZone(self.spawnzone) - local DeployZoneSet = SET_ZONE:New():AddZone(Request.warehouse.spawnzone) - - -- Define dispatcher for this task. - CargoTransport = AI_CARGO_DISPATCHER_HELICOPTER:New(TransportGroupSet, CargoGroups, PickupZoneSet, DeployZoneSet) - - -- Home zone. - CargoTransport:SetHomeZone(self.spawnzone) + + CargoTransport = OPSTRANSPORT:New(CargoGroupSet, self.spawnzone, Request.warehouse.spawnzone) elseif Request.transporttype==WAREHOUSE.TransportType.APC then - -- Pickup and deploy zones. - local PickupZoneSet = SET_ZONE:New():AddZone(self.spawnzone) - local DeployZoneSet = SET_ZONE:New():AddZone(Request.warehouse.spawnzone) - - -- Define dispatcher for this task. - CargoTransport = AI_CARGO_DISPATCHER_APC:New(TransportGroupSet, CargoGroups, PickupZoneSet, DeployZoneSet, 0) - - -- Set home zone. - CargoTransport:SetHomeZone(self.spawnzone) + CargoTransport = OPSTRANSPORT:New(CargoGroupSet, self.spawnzone, Request.warehouse.spawnzone) elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER - or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then - - -- Pickup and deploy zones. - local PickupZoneSet = SET_ZONE:New():AddZone(self.portzone) - PickupZoneSet:AddZone(self.harborzone) - local DeployZoneSet = SET_ZONE:New():AddZone(Request.warehouse.harborzone) - + or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then + + CargoTransport = OPSTRANSPORT:New(CargoGroupSet, self.portzone, Request.warehouse.portzone) + CargoTransport:SetEmbarkZone(self.spawnzone) + CargoTransport:SetDisembarkZone(Request.warehouse.spawnzone) -- Get the shipping lane to use and pass it to the Dispatcher local remotename = Request.warehouse.warehouse:GetName() local ShippingLane = self.shippinglanes[remotename][math.random(#self.shippinglanes[remotename])] - - -- Define dispatcher for this task. - CargoTransport = AI_CARGO_DISPATCHER_SHIP:New(TransportGroupSet, CargoGroups, PickupZoneSet, DeployZoneSet, ShippingLane) - - -- Set home zone - CargoTransport:SetHomeZone(self.portzone) + + -- TODO: Add shipping lane + -- CargoTransport:AddPathTransport(PathGroup) else self:E(self.lid.."ERROR: Unknown transporttype!") end - -- Set pickup and deploy radii. - -- The 20 m inner radius are to ensure that the helo does not land on the warehouse itself in the middle of the default spawn zone. - local pickupouter = 200 - local pickupinner = 0 - local deployouter = 200 - local deployinner = 0 - if Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER - or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then - pickupouter=1000 - pickupinner=20 - deployouter=1000 - deployinner=0 - else - pickupouter=200 - pickupinner=0 - if self.spawnzone.Radius~=nil then - pickupouter=self.spawnzone.Radius - pickupinner=20 - end - deployouter=200 - deployinner=0 - if self.spawnzone.Radius~=nil then - deployouter=Request.warehouse.spawnzone.Radius - deployinner=20 - end - end - CargoTransport:SetPickupRadius(pickupouter, pickupinner) - CargoTransport:SetDeployRadius(deployouter, deployinner) - -- Adjust carrier units. This has to come AFTER the dispatchers have been defined because they set the cargobay free weight! Request.carriercargo={} @@ -4847,111 +4743,63 @@ function WAREHOUSE:onafterRequestSpawned(From, Event, To, Request, CargoGroupSet end end - -------------------------------- - -- Dispatcher Event Functions -- - -------------------------------- + ---------------------------------- + -- Opstransport Event Functions -- + ---------------------------------- - --- Function called after carrier picked up something. - function CargoTransport:OnAfterPickedUp(From, Event, To, Carrier, PickupZone) - - -- Get warehouse state. - local warehouse=Carrier:GetState(Carrier, "WAREHOUSE") --#WAREHOUSE - - -- Debug message. - local text=string.format("Carrier group %s picked up at pickup zone %s.", Carrier:GetName(), PickupZone:GetName()) - warehouse:T(warehouse.lid..text) - - end - - --- Function called if something was deployed. - function CargoTransport:OnAfterDeployed(From, Event, To, Carrier, DeployZone) - - -- Get warehouse state. - local warehouse=Carrier:GetState(Carrier, "WAREHOUSE") --#WAREHOUSE - - -- Debug message. - -- TODO: Depoloy zone is nil! - --local text=string.format("Carrier group %s deployed at deploy zone %s.", Carrier:GetName(), DeployZone:GetName()) - --warehouse:T(warehouse.lid..text) - - end - - --- Function called if carrier group is going home. - function CargoTransport:OnAfterHome(From, Event, To, Carrier, Coordinate, Speed, Height, HomeZone) - - -- Get warehouse state. - local warehouse=Carrier:GetState(Carrier, "WAREHOUSE") --#WAREHOUSE - - -- Debug message. - local text=string.format("Carrier group %s going home to zone %s.", Carrier:GetName(), HomeZone:GetName()) - warehouse:T(warehouse.lid..text) - - end + CargoTransport.warehouse = self --- Function called when a carrier unit has loaded a cargo group. - function CargoTransport:OnAfterLoaded(From, Event, To, Carrier, Cargo, CarrierUnit, PickupZone) + function CargoTransport:OnAfterLoaded(From, Event, To, OpsGroupCargo, OpsGroupCarrier, CarrierElement) -- Get warehouse state. - local warehouse=Carrier:GetState(Carrier, "WAREHOUSE") --#WAREHOUSE - - -- Debug message. - local text=string.format("Carrier group %s loaded cargo %s into unit %s in pickup zone %s", Carrier:GetName(), Cargo:GetName(), CarrierUnit:GetName(), PickupZone:GetName()) - warehouse:T(warehouse.lid..text) + local warehouse=CargoTransport.warehouse --#WAREHOUSE -- Get cargo group object. - local group=Cargo:GetObject() --Wrapper.Group#GROUP + local group=OpsGroupCargo:GetGroup() --Cargo:GetObject() --Wrapper.Group#GROUP -- Get request. local request=warehouse:_GetRequestOfGroup(group, warehouse.pending) -- Add cargo group to this carrier. - table.insert(request.carriercargo[CarrierUnit:GetName()], warehouse:_GetNameWithOut(Cargo:GetName())) + table.insert(request.carriercargo[CarrierElement.name], warehouse:_GetNameWithOut(group:GetName())) end --- Function called when cargo has arrived and was unloaded. - function CargoTransport:OnAfterUnloaded(From, Event, To, Carrier, Cargo, CarrierUnit, DeployZone) + function CargoTransport:OnAfterUnloaded(From, Event, To, OpsGroupCargo, OpsGroupCarrier) -- Get warehouse state. - local warehouse=Carrier:GetState(Carrier, "WAREHOUSE") --#WAREHOUSE + local warehouse=CargoTransport.warehouse --Carrier:GetState(Carrier, "WAREHOUSE") --#WAREHOUSE -- Get group obejet. - local group=Cargo:GetObject() --Wrapper.Group#GROUP + local group=OpsGroupCargo:GetGroup() --Cargo:GetObject() --Wrapper.Group#GROUP -- Debug message. - local text=string.format("Cargo group %s was unloaded from carrier unit %s.", tostring(group:GetName()), tostring(CarrierUnit:GetName())) + local text=string.format("Cargo group %s was unloaded from carrier group %s.", tostring(group:GetName()), tostring(OpsGroupCarrier:GetName())) warehouse:T(warehouse.lid..text) - -- Load the cargo in the warehouse. - --Cargo:Load(warehouse.warehouse) - -- Trigger Arrived event. warehouse:Arrived(group) end + + -- TODO: Probably can also add some cargo/carrier dead functions here to simplify things at other places - --- On after BackHome event. - function CargoTransport:OnAfterBackHome(From, Event, To, Carrier) - - -- Intellisense. - local carrier=Carrier --Wrapper.Group#GROUP - - -- Get warehouse state. - local warehouse=carrier:GetState(carrier, "WAREHOUSE") --#WAREHOUSE - carrier:SmokeWhite() - - -- Debug info. - local text=string.format("Carrier %s is back home at warehouse %s.", tostring(Carrier:GetName()), tostring(warehouse.warehouse:GetName())) - MESSAGE:New(text, 5):ToAllIf(warehouse.Debug) - warehouse:I(warehouse.lid..text) - - -- Call arrived event for carrier. - warehouse:__Arrived(1, Carrier) + -- Assign cargo to carriers + for _,carriergroup in pairs(TransportGroupSet:GetSetObjects()) do + local opsgroup=nil + if Request.transporttype==WAREHOUSE.TransportType.AIRPLANE or Request.transporttype==WAREHOUSE.TransportType.HELICOPTER then + opsgroup=FLIGHTGROUP:New(carriergroup) + elseif Request.transporttype==WAREHOUSE.TransportType.APC then + opsgroup=ARMYGROUP:New(carriergroup) + elseif Request.transporttype==WAREHOUSE.TransportType.SHIP or Request.transporttype==WAREHOUSE.TransportType.AIRCRAFTCARRIER + or Request.transporttype==WAREHOUSE.TransportType.ARMEDSHIP or Request.transporttype==WAREHOUSE.TransportType.WARSHIP then + opsgroup=NAVYGROUP:New(carriergroup) + end + opsgroup:AddOpsTransport(CargoTransport) end - -- Start dispatcher. - CargoTransport:__Start(5) - end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Ops/FlightGroup.lua b/Moose Development/Moose/Ops/FlightGroup.lua index 269dae89e..86a2be4a0 100644 --- a/Moose Development/Moose/Ops/FlightGroup.lua +++ b/Moose Development/Moose/Ops/FlightGroup.lua @@ -2782,7 +2782,7 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n, N) -- Set current waypoint or we get problem that the _PassingWaypoint function is triggered too early, i.e. right now and not when passing the next WP. local current=self:GetCoordinate():WaypointAir(COORDINATE.WaypointAltType.BARO, waypointType, waypointAction, speed, true, nil, {}, "Current") table.insert(wp, current) - + -- Add remaining waypoints to route. for i=n, N do table.insert(wp, self.waypoints[i]) diff --git a/Moose Development/Moose/Ops/OpsGroup.lua b/Moose Development/Moose/Ops/OpsGroup.lua index 13b4597f4..7a1d8d3df 100644 --- a/Moose Development/Moose/Ops/OpsGroup.lua +++ b/Moose Development/Moose/Ops/OpsGroup.lua @@ -514,7 +514,7 @@ OPSGROUP.CargoStatus={ --- OpsGroup version. -- @field #string version -OPSGROUP.version="1.0.4" +OPSGROUP.version="1.0.5" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -2741,6 +2741,15 @@ function OPSGROUP:IsOutOfTorpedos() return self.outofTorpedos end +--- Check if the group is out of A2G Ammo +-- @param #OPSGROUP self +-- @return #boolean If `true`, group is out of torpedos. +function OPSGROUP:IsOutOfA2GAmmo() + if (self.outofMissilesAG and self.outofBombs and self.outofGuns) or self.outofAmmo then + return true + end + return false +end --- Check if the group has currently switched a LASER on. -- @param #OPSGROUP self @@ -5091,7 +5100,7 @@ function OPSGROUP:onafterTaskDone(From, Event, To, Task) if Task.description=="Task_Land_At" then self:T(self.lid.."Taske DONE Task_Land_At ==> Wait") - self:Cruise() + -- After the land task, we set the helo to wait. This is because of an issue that the passing waypoint function is triggered immidiately if we do not do this! self:Wait(20, 100) else self:T(self.lid.."Task Done but NO mission found ==> _CheckGroupDone in 1 sec") @@ -8322,7 +8331,8 @@ function OPSGROUP:_CheckCargoTransport() end -- Boarding finished ==> Transport cargo. - if gotcargo and self.cargoTransport:_CheckRequiredCargos(self.cargoTZC, self) and not boarding then + local required=self.cargoTransport:_CheckRequiredCargos(self.cargoTZC, self) + if gotcargo and required and not boarding then self:T(self.lid.."Boarding/loading finished ==> Loaded") self.Tloading=nil self:LoadingDone() @@ -9958,6 +9968,10 @@ function OPSGROUP:onafterTransport(From, Event, To) self:T(self.lid.."ERROR: No current task but landed at?!") end end + + if self:IsWaiting() then + self:__Cruise(-10) + end elseif self:IsArmygroup() then diff --git a/Moose Development/Moose/Ops/OpsTransport.lua b/Moose Development/Moose/Ops/OpsTransport.lua index f5c8e84f2..a6bbf9061 100644 --- a/Moose Development/Moose/Ops/OpsTransport.lua +++ b/Moose Development/Moose/Ops/OpsTransport.lua @@ -244,7 +244,7 @@ _OPSTRANSPORTID=0 --- Army Group version. -- @field #string version -OPSTRANSPORT.version="0.8.0" +OPSTRANSPORT.version="0.9.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -2127,7 +2127,9 @@ function OPSTRANSPORT:_CheckRequiredCargos(TransportZoneCombo, CarrierGroup) requiredCargos={} for _,_cargo in pairs(TransportZoneCombo.Cargos) do local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup - table.insert(requiredCargos, cargo.opsgroup) + if not cargo.delivered then + table.insert(requiredCargos, cargo.opsgroup) + end end end From dfcbe6fd9bd937d58af2eb2fd3676378e29be242 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Sun, 8 Feb 2026 12:32:31 +0100 Subject: [PATCH 2/2] # CARGO CLASS Removal --- Moose Development/Moose/Cargo/Cargo.lua | 1401 ----------------- Moose Development/Moose/Cargo/CargoCrate.lua | 340 ---- Moose Development/Moose/Cargo/CargoGroup.lua | 777 --------- .../Moose/Cargo/CargoSlingload.lua | 277 ---- Moose Development/Moose/Cargo/CargoUnit.lua | 397 ----- Moose Development/Moose/Core/Database.lua | 111 -- Moose Development/Moose/Core/Event.lua | 82 +- Moose Development/Moose/Core/Point.lua | 19 - Moose Development/Moose/Core/Set.lua | 450 ------ .../Moose/Functional/Artillery.lua | 49 - .../Moose/Functional/ZoneGoalCargo.lua | 458 ------ Moose Development/Moose/Globals.lua | 3 - Moose Development/Moose/Modules.lua | 6 - Moose Development/Moose/Wrapper/Client.lua | 33 +- 14 files changed, 11 insertions(+), 4392 deletions(-) delete mode 100644 Moose Development/Moose/Cargo/Cargo.lua delete mode 100644 Moose Development/Moose/Cargo/CargoCrate.lua delete mode 100644 Moose Development/Moose/Cargo/CargoGroup.lua delete mode 100644 Moose Development/Moose/Cargo/CargoSlingload.lua delete mode 100644 Moose Development/Moose/Cargo/CargoUnit.lua delete mode 100644 Moose Development/Moose/Functional/ZoneGoalCargo.lua diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua deleted file mode 100644 index 76307dd78..000000000 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ /dev/null @@ -1,1401 +0,0 @@ ---- **Cargo** - Management of CARGO logistics, that can be transported from and to transportation carriers. --- --- === --- --- ![Banner Image](..\Images\deprecated.png) --- --- # 1) MOOSE Cargo System. --- --- #### Those who have used the mission editor, know that the DCS mission editor provides cargo facilities. --- However, these are merely static objects. Wouldn't it be nice if cargo could bring a new dynamism into your --- simulations? Where various objects of various types could be treated also as cargo? --- --- This is what MOOSE brings to you, a complete new cargo object model that used the cargo capabilities of --- DCS world, but enhances it. --- --- MOOSE Cargo introduces also a new concept, called a "carrier". These can be: --- --- - Helicopters --- - Planes --- - Ground Vehicles --- - Ships --- --- With the MOOSE Cargo system, you can: --- --- - Take full control of the cargo as objects within your script (see below). --- - Board/Unboard infantry into carriers. Also other objects can be boarded, like mortars. --- - Load/Unload dcs world cargo objects into carriers. --- - Load/Unload other static objects into carriers (like tires etc). --- - Slingload cargo objects. --- - Board units one by one... --- --- # 2) MOOSE Cargo Objects. --- --- In order to make use of the MOOSE cargo system, you need to **declare** the DCS objects as MOOSE cargo objects! --- --- This sounds complicated, but it is actually quite simple. --- --- See here an example: --- --- local EngineerCargoGroup = CARGO_GROUP:New( GROUP:FindByName( "Engineers" ), "Workmaterials", "Engineers", 250 ) --- --- The above code declares a MOOSE cargo object called `EngineerCargoGroup`. --- It actually just refers to an infantry group created within the sim called `"Engineers"`. --- The infantry group now becomes controlled by the MOOSE cargo object `EngineerCargoGroup`. --- A MOOSE cargo object also has properties, like the type of cargo, the logical name, and the reporting range. --- --- There are 4 types of MOOSE cargo objects possible, each represented by its own class: --- --- - @{Cargo.CargoGroup#CARGO_GROUP}: A MOOSE cargo that is represented by a DCS world GROUP object. --- - @{Cargo.CargoCrate#CARGO_CRATE}: A MOOSE cargo that is represented by a DCS world cargo object (static object). --- - @{Cargo.CargoUnit#CARGO_UNIT}: A MOOSE cargo that is represented by a DCS world unit object or static object. --- - @{Cargo.CargoSlingload#CARGO_SLINGLOAD}: A MOOSE cargo that is represented by a DCS world cargo object (static object), that can be slingloaded. --- --- Note that a CARGO crate is not meant to be slingloaded (it can, but it is not **meant** to be handled like that. --- Instead, a CARGO_CRATE is able to load itself into the bays of a carrier. --- --- Each of these MOOSE cargo objects behave in its own way, and have methods to be handled. --- --- local InfantryGroup = GROUP:FindByName( "Infantry" ) --- local InfantryCargo = CARGO_GROUP:New( InfantryGroup, "Engineers", "Infantry Engineers", 2000 ) --- local CargoCarrier = UNIT:FindByName( "Carrier" ) --- -- This call will make the Cargo run to the CargoCarrier. --- -- Upon arrival at the CargoCarrier, the Cargo will be Loaded into the Carrier. --- -- This process is now fully automated. --- InfantryCargo:Board( CargoCarrier, 25 ) --- --- The above would create a MOOSE cargo object called `InfantryCargo`, and using that object, --- you can board the cargo into the carrier `CargoCarrier`. --- Simple, isn't it? Told you, and this is only the beginning. --- --- The boarding, unboarding, loading, unloading of cargo is however something that is not meant to be coded manually by mission designers. --- It would be too low-level and not end-user friendly to deal with cargo handling complexity. --- Things can become really complex if you want to make cargo being handled and behave in multiple scenarios. --- --- # 3) Cargo Handling Classes, the main engines for mission designers! --- --- For this reason, the MOOSE Cargo System is heavily used by 3 important **cargo handling class hierarchies** within MOOSE, --- that make cargo come "alive" within your mission in a full automatic manner! --- --- ## 3.1) AI Cargo handlers. --- --- - @{AI.AI_Cargo_APC} will create for you the capability to make an APC group handle cargo. --- - @{AI.AI_Cargo_Helicopter} will create for you the capability to make a Helicopter group handle cargo. --- --- --- ## 3.2) AI Cargo transportation dispatchers. --- --- There are also dispatchers that make AI work together to transport cargo automatically!!! --- --- - @{AI.AI_Cargo_Dispatcher_APC} derived classes will create for your dynamic cargo handlers controlled by AI ground vehicle groups (APCs) to transport cargo between sites. --- - @{AI.AI_Cargo_Dispatcher_Helicopter} derived classes will create for your dynamic cargo handlers controlled by AI helicopter groups to transport cargo between sites. --- --- ## 3.3) Cargo transportation tasking. --- --- And there is cargo transportation tasking for human players. --- --- - @{Tasking.Task_CARGO} derived classes will create for you cargo transportation tasks, that allow human players to interact with MOOSE cargo objects to complete tasks. --- --- Please refer to the documentation reflected within these modules to understand the detailed capabilities. --- --- # 4) Cargo SETs. --- --- To make life a bit more easy, MOOSE cargo objects can be grouped into a @{Core.Set#SET_CARGO}. --- This is a collection of MOOSE cargo objects. --- --- This would work as follows: --- --- -- Define the cargo set. --- local CargoSetWorkmaterials = SET_CARGO:New():FilterTypes( "Workmaterials" ):FilterStart() --- --- -- Now add cargo the cargo set. --- local EngineerCargoGroup = CARGO_GROUP:New( GROUP:FindByName( "Engineers" ), "Workmaterials", "Engineers", 250 ) --- local ConcreteCargo = CARGO_SLINGLOAD:New( STATIC:FindByName( "Concrete" ), "Workmaterials", "Concrete", 150, 50 ) --- local CrateCargo = CARGO_CRATE:New( STATIC:FindByName( "Crate" ), "Workmaterials", "Crate", 150, 50 ) --- local EnginesCargo = CARGO_CRATE:New( STATIC:FindByName( "Engines" ), "Workmaterials", "Engines", 150, 50 ) --- local MetalCargo = CARGO_CRATE:New( STATIC:FindByName( "Metal" ), "Workmaterials", "Metal", 150, 50 ) --- --- This is a very powerful concept! --- Instead of having to deal with multiple MOOSE cargo objects yourself, the cargo set capability will group cargo objects into one set. --- The key is the **cargo type** name given at each cargo declaration! --- In the above example, the cargo type name is `"Workmaterials"`. Each cargo object declared is given that type name. (the 2nd parameter). --- What happens now is that the cargo set `CargoSetWorkmaterials` will be added with each cargo object **dynamically** when the cargo object is created. --- In other words, the cargo set `CargoSetWorkmaterials` will incorporate any `"Workmaterials"` dynamically into its set. --- --- The cargo sets are extremely important for the AI cargo transportation dispatchers and the cargo transporation tasking. --- --- # 5) Declare cargo directly in the mission editor! --- --- But I am not finished! There is something more, that is even more great! --- Imagine the mission designers having to code all these lines every time it wants to embed cargo within a mission. --- --- -- Now add cargo the cargo set. --- local EngineerCargoGroup = CARGO_GROUP:New( GROUP:FindByName( "Engineers" ), "Workmaterials", "Engineers", 250 ) --- local ConcreteCargo = CARGO_SLINGLOAD:New( STATIC:FindByName( "Concrete" ), "Workmaterials", "Concrete", 150, 50 ) --- local CrateCargo = CARGO_CRATE:New( STATIC:FindByName( "Crate" ), "Workmaterials", "Crate", 150, 50 ) --- local EnginesCargo = CARGO_CRATE:New( STATIC:FindByName( "Engines" ), "Workmaterials", "Engines", 150, 50 ) --- local MetalCargo = CARGO_CRATE:New( STATIC:FindByName( "Metal" ), "Workmaterials", "Metal", 150, 50 ) --- --- This would be extremely tiring and a huge overload. --- However, the MOOSE framework allows to declare MOOSE cargo objects within the mission editor!!! --- --- So, at mission startup, MOOSE will search for objects following a special naming convention, and will **create** for you **dynamically --- cargo objects** at **mission start**!!! -- These cargo objects can then be automatically incorporated within cargo set(s)!!! --- In other words, your mission will be reduced to about a few lines of code, providing you with a full dynamic cargo handling mission! --- --- ## 5.1) Use \#CARGO tags in the mission editor: --- --- MOOSE can create automatically cargo objects, if the name of the cargo contains the **\#CARGO** tag. --- When a mission starts, MOOSE will scan all group and static objects it found for the presence of the \#CARGO tag. --- When found, MOOSE will declare the object as cargo (create in the background a CARGO_ object, like CARGO_GROUP, CARGO_CRATE or CARGO_SLINGLOAD. --- The creation of these CARGO_ objects will allow to be filtered and automatically added in SET_CARGO objects. --- In other words, with very minimal code as explained in the above code section, you are able to create vast amounts of cargo objects just from within the editor. --- --- What I talk about is this: --- --- -- BEFORE THIS SCRIPT STARTS, MOOSE WILL ALREADY HAVE SCANNED FOR OBJECTS WITH THE #CARGO TAG IN THE NAME. --- -- FOR EACH OF THESE OBJECT, MOOSE WILL HAVE CREATED CARGO_ OBJECTS LIKE CARGO_GROUP, CARGO_CRATE AND CARGO_SLINGLOAD. --- --- HQ = GROUP:FindByName( "HQ", "Bravo" ) --- --- CommandCenter = COMMANDCENTER --- :New( HQ, "Lima" ) --- --- Mission = MISSION --- :New( CommandCenter, "Operation Cargo Fun", "Tactical", "Transport Cargo", coalition.side.RED ) --- --- TransportGroups = SET_GROUP:New():FilterCoalitions( "blue" ):FilterPrefixes( "Transport" ):FilterStart() --- --- TaskDispatcher = TASK_CARGO_DISPATCHER:New( Mission, TransportGroups ) --- --- -- This is the most important now. You setup a new SET_CARGO filtering the relevant type. --- -- The actual cargo objects are now created by MOOSE in the background. --- -- Each cargo is setup in the Mission Editor using the #CARGO tag in the group name. --- -- This allows a truly dynamic setup. --- local CargoSetWorkmaterials = SET_CARGO:New():FilterTypes( "Workmaterials" ):FilterStart() --- --- local WorkplaceTask = TaskDispatcher:AddTransportTask( "Build a Workplace", CargoSetWorkmaterials, "Transport the workers, engineers and the equipment near the Workplace." ) --- TaskDispatcher:SetTransportDeployZone( WorkplaceTask, ZONE:New( "Workplace" ) ) --- --- The above code example has the `CargoSetWorkmaterials`, which is a SET_CARGO collection and will include the CARGO_ objects of the type "Workmaterials". --- And there is NO cargo object actually declared within the script! However, if you would open the mission, there would be hundreds of cargo objects... --- --- The \#CARGO tag even allows for several options to be specified, which are important to learn. --- --- ## 5.2) The \#CARGO tag to create CARGO_GROUP objects: --- --- You can also use the \#CARGO tag on **group** objects of the mission editor. --- --- For example, the following #CARGO naming in the **group name** of the object, will create a CARGO_GROUP object when the mission starts. --- --- `Infantry #CARGO(T=Workmaterials,RR=500,NR=25)` --- --- This will create a CARGO_GROUP object: --- --- * with the group name `Infantry #CARGO` --- * is of type `Workmaterials` --- * will report when a carrier is within 500 meters --- * will board to carriers when the carrier is within 500 meters from the cargo object --- * will disappear when the cargo is within 25 meters from the carrier during boarding --- --- So the overall syntax of the #CARGO naming tag and arguments are: --- --- `GroupName #CARGO(T=CargoTypeName,RR=Range,NR=Range)` --- --- * **T=** Provide a text that contains the type name of the cargo object. This type name can be used to filter cargo within a SET_CARGO object. --- * **RR=** Provide the minimal range in meters when the report to the carrier, and board to the carrier. --- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters. --- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding. --- Note that this option is optional, so can be omitted. The default value of the RR is 10 meters. --- --- ## 5.2) The \#CARGO tag to create CARGO_CRATE or CARGO_SLINGLOAD objects: --- --- You can also use the \#CARGO tag on **static** objects, including **static cargo** objects of the mission editor. --- --- For example, the following #CARGO naming in the **static name** of the object, will create a CARGO_CRATE object when the mission starts. --- --- `Static #CARGO(T=Workmaterials,C=CRATE,RR=500,NR=25)` --- --- This will create a CARGO_CRATE object: --- --- * with the group name `Static #CARGO` --- * is of type `Workmaterials` --- * is of category `CRATE` (as opposed to `SLING`) --- * will report when a carrier is within 500 meters --- * will board to carriers when the carrier is within 500 meters from the cargo object --- * will disappear when the cargo is within 25 meters from the carrier during boarding --- --- So the overall syntax of the #CARGO naming tag and arguments are: --- --- `StaticName #CARGO(T=CargoTypeName,C=Category,RR=Range,NR=Range)` --- --- * **T=** Provide a text that contains the type name of the cargo object. This type name can be used to filter cargo within a SET_CARGO object. --- * **C=** Provide either `CRATE` or `SLING` to have this static created as a CARGO_CRATE or CARGO_SLINGLOAD respectively. --- * **RR=** Provide the minimal range in meters when the report to the carrier, and board to the carrier. --- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters. --- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding. --- Note that this option is optional, so can be omitted. The default value of the RR is 10 meters. --- --- # Developer Note --- --- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE --- Therefore, this class is considered to be deprecated --- --- === --- --- ### Author: **FlightControl** --- ### Contributions: --- --- === --- --- @module Cargo.Cargo --- @image Cargo.JPG - --- Events - --- Board - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] Board --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. --- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - ---- Boards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo to the Carrier. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] __Board --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. --- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - - --- UnBoard - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] UnBoard --- @param #CARGO self --- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - ---- UnBoards the cargo to a Carrier. The event will create a movement (= running or driving) of the cargo from the Carrier. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] __UnBoard --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo should run after onboarding. If not provided, the cargo will run to 60 meters behind the Carrier location. - - --- Load - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] Load --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - ---- Loads the cargo to a Carrier. The event will load the cargo into the Carrier regardless of its position. There will be no movement simulated of the cargo loading. --- The cargo must be in the **UnLoaded** state. --- @function [parent=#CARGO] __Load --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Wrapper.Controllable#CONTROLLABLE ToCarrier The Carrier that will hold the cargo. - - --- UnLoad - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] UnLoad --- @param #CARGO self --- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - ---- UnLoads the cargo to a Carrier. The event will unload the cargo from the Carrier. There will be no movement simulated of the cargo loading. --- The cargo must be in the **Loaded** state. --- @function [parent=#CARGO] __UnLoad --- @param #CARGO self --- @param #number DelaySeconds The amount of seconds to delay the action. --- @param Core.Point#COORDINATE ToPointVec2 (optional) @{Core.Point#COORDINATE) to where the cargo will be placed after unloading. If not provided, the cargo will be placed 60 meters behind the Carrier location. - --- State Transition Functions - --- UnLoaded - ---- @function [parent=#CARGO] OnLeaveUnLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterUnLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Loaded - ---- @function [parent=#CARGO] OnLeaveLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterLoaded --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - --- Boarding - ---- @function [parent=#CARGO] OnLeaveBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). - --- UnBoarding - ---- @function [parent=#CARGO] OnLeaveUnBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable --- @return #boolean - ---- @function [parent=#CARGO] OnEnterUnBoarding --- @param #CARGO self --- @param Wrapper.Controllable#CONTROLLABLE Controllable - - --- TODO: Find all Carrier objects and make the type of the Carriers Wrapper.Unit#UNIT in the documentation. - -CARGOS = {} - -do -- CARGO - - -- @type CARGO - -- @extends Core.Fsm#FSM_PROCESS - -- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. - -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. - -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. - -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. - -- @field Wrapper.Unit#UNIT CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... - -- @field Wrapper.Client#CLIENT CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... - -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. - -- @field #boolean Moveable This flag defines if the cargo is moveable. - -- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit. - -- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit. - - --- Defines the core functions that defines a cargo object within MOOSE. - -- - -- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation. - -- - -- CARGO is not meant to be used directly by mission designers, but provides a base class for **concrete cargo implementation classes** to handle: - -- - -- * Cargo **group objects**, implemented by the @{Cargo.CargoGroup#CARGO_GROUP} class. - -- * Cargo **Unit objects**, implemented by the @{Cargo.CargoUnit#CARGO_UNIT} class. - -- * Cargo **Crate objects**, implemented by the @{Cargo.CargoCrate#CARGO_CRATE} class. - -- * Cargo **Sling Load objects**, implemented by the @{Cargo.CargoSlingload#CARGO_SLINGLOAD} class. - -- - -- The above cargo classes are used by the AI\_CARGO\_ classes to allow AI groups to transport cargo: - -- - -- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC#AI_CARGO_APC} class. - -- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter#AI_CARGO_HELICOPTER} class. - -- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane#AI_CARGO_AIRPLANE} class. - -- * AI Ships is planned. - -- - -- The above cargo classes are also used by the TASK\_CARGO\_ classes to allow human players to transport cargo as part of a tasking: - -- - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players. - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players. - -- - -- - -- The CARGO is a state machine: it manages the different events and states of the cargo. - -- All derived classes from CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states. - -- - -- ## CARGO Events: - -- - -- * @{#CARGO.Board}( ToCarrier ): Boards the cargo to a carrier. - -- * @{#CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position. - -- * @{#CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2. - -- * @{#CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier. - -- * @{#CARGO.Destroyed}( Controllable ): The cargo is dead. The cargo process will be ended. - -- - -- @field #CARGO - CARGO = { - ClassName = "CARGO", - Type = nil, - Name = nil, - Weight = nil, - CargoObject = nil, - CargoCarrier = nil, - Representable = false, - Slingloadable = false, - Moveable = false, - Containable = false, - Reported = {}, - } - - -- @type CARGO.CargoObjects - -- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo. - - --- CARGO Constructor. This class is an abstract class and should not be instantiated. - -- @param #CARGO self - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number LoadRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO - function CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) --R2.1 - - local self = BASE:Inherit( self, FSM:New() ) -- #CARGO - self:T( { Type, Name, Weight, LoadRadius, NearRadius } ) - - self:SetStartState( "UnLoaded" ) - self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" ) - self:AddTransition( "Boarding" , "Boarding", "Boarding" ) - self:AddTransition( "Boarding", "CancelBoarding", "UnLoaded" ) - self:AddTransition( "Boarding", "Load", "Loaded" ) - self:AddTransition( "UnLoaded", "Load", "Loaded" ) - self:AddTransition( "Loaded", "UnBoard", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnBoarding", "UnBoarding" ) - self:AddTransition( "UnBoarding", "UnLoad", "UnLoaded" ) - self:AddTransition( "Loaded", "UnLoad", "UnLoaded" ) - self:AddTransition( "*", "Damaged", "Damaged" ) - self:AddTransition( "*", "Destroyed", "Destroyed" ) - self:AddTransition( "*", "Respawn", "UnLoaded" ) - self:AddTransition( "*", "Reset", "UnLoaded" ) - - self.Type = Type - self.Name = Name - self.Weight = Weight or 0 - self.CargoObject = nil -- Wrapper.Group#GROUP - self.CargoCarrier = nil -- Wrapper.Client#CLIENT - self.Representable = false - self.Slingloadable = false - self.Moveable = false - self.Containable = false - - self.CargoLimit = 0 - - self.LoadRadius = LoadRadius or 500 - --self.NearRadius = NearRadius or 25 - - self:SetDeployed( false ) - - self.CargoScheduler = SCHEDULER:New() - - CARGOS[self.Name] = self - - return self - end - - --- Find a CARGO in the _DATABASE. - -- @param #CARGO self - -- @param #string CargoName The Cargo Name. - -- @return #CARGO self - function CARGO:FindByName( CargoName ) - - local CargoFound = _DATABASE:FindCargo( CargoName ) - return CargoFound - end - - --- Get the x position of the cargo. - -- @param #CARGO self - -- @return #number - function CARGO:GetX() - if self:IsLoaded() then - return self.CargoCarrier:GetCoordinate().x - else - return self.CargoObject:GetCoordinate().x - end - end - - --- Get the y position of the cargo. - -- @param #CARGO self - -- @return #number - function CARGO:GetY() - if self:IsLoaded() then - return self.CargoCarrier:GetCoordinate().z - else - return self.CargoObject:GetCoordinate().z - end - end - - --- Get the heading of the cargo. - -- @param #CARGO self - -- @return #number - function CARGO:GetHeading() - if self:IsLoaded() then - return self.CargoCarrier:GetHeading() - else - return self.CargoObject:GetHeading() - end - end - - --- Check if the cargo can be Slingloaded. - -- @param #CARGO self - function CARGO:CanSlingload() - return false - end - - --- Check if the cargo can be Boarded. - -- @param #CARGO self - function CARGO:CanBoard() - return true - end - - --- Check if the cargo can be Unboarded. - -- @param #CARGO self - function CARGO:CanUnboard() - return true - end - - --- Check if the cargo can be Loaded. - -- @param #CARGO self - function CARGO:CanLoad() - return true - end - - --- Check if the cargo can be Unloaded. - -- @param #CARGO self - function CARGO:CanUnload() - return true - end - - --- Destroy the cargo. - -- @param #CARGO self - function CARGO:Destroy() - if self.CargoObject then - self.CargoObject:Destroy() - end - self:Destroyed() - end - - --- Get the name of the Cargo. - -- @param #CARGO self - -- @return #string The name of the Cargo. - function CARGO:GetName() --R2.1 - return self.Name - end - - --- Get the current active object representing or being the Cargo. - -- @param #CARGO self - -- @return Wrapper.Positionable#POSITIONABLE The object representing or being the Cargo. - function CARGO:GetObject() - if self:IsLoaded() then - return self.CargoCarrier - else - return self.CargoObject - end - end - - --- Get the object name of the Cargo. - -- @param #CARGO self - -- @return #string The object name of the Cargo. - function CARGO:GetObjectName() --R2.1 - if self:IsLoaded() then - return self.CargoCarrier:GetName() - else - return self.CargoObject:GetName() - end - end - - --- Get the amount of Cargo. - -- @param #CARGO self - -- @return #number The amount of Cargo. - function CARGO:GetCount() - return 1 - end - - --- Get the type of the Cargo. - -- @param #CARGO self - -- @return #string The type of the Cargo. - function CARGO:GetType() - return self.Type - end - - --- Get the transportation method of the Cargo. - -- @param #CARGO self - -- @return #string The transportation method of the Cargo. - function CARGO:GetTransportationMethod() - return self.TransportationMethod - end - - --- Get the coalition of the Cargo. - -- @param #CARGO self - -- @return Coalition - function CARGO:GetCoalition() - if self:IsLoaded() then - return self.CargoCarrier:GetCoalition() - else - return self.CargoObject:GetCoalition() - end - end - - --- Get the current coordinates of the Cargo. - -- @param #CARGO self - -- @return Core.Point#COORDINATE The coordinates of the Cargo. - function CARGO:GetCoordinate() - return self.CargoObject:GetCoordinate() - end - - --- Check if cargo is destroyed. - -- @param #CARGO self - -- @return #boolean true if destroyed - function CARGO:IsDestroyed() - return self:Is( "Destroyed" ) - end - - --- Check if cargo is loaded. - -- @param #CARGO self - -- @return #boolean true if loaded - function CARGO:IsLoaded() - return self:Is( "Loaded" ) - end - - --- Check if cargo is loaded. - -- @param #CARGO self - -- @param Wrapper.Unit#UNIT Carrier - -- @return #boolean true if loaded - function CARGO:IsLoadedInCarrier( Carrier ) - return self.CargoCarrier and self.CargoCarrier:GetName() == Carrier:GetName() - end - - --- Check if cargo is unloaded. - -- @param #CARGO self - -- @return #boolean true if unloaded - function CARGO:IsUnLoaded() - return self:Is( "UnLoaded" ) - end - - --- Check if cargo is boarding. - -- @param #CARGO self - -- @return #boolean true if boarding - function CARGO:IsBoarding() - return self:Is( "Boarding" ) - end - - --- Check if cargo is unboarding. - -- @param #CARGO self - -- @return #boolean true if unboarding - function CARGO:IsUnboarding() - return self:Is( "UnBoarding" ) - end - - --- Check if cargo is alive. - -- @param #CARGO self - -- @return #boolean true if unloaded - function CARGO:IsAlive() - - if self:IsLoaded() then - return self.CargoCarrier:IsAlive() - else - return self.CargoObject:IsAlive() - end - end - - --- Set the cargo as deployed. - -- @param #CARGO self - -- @param #boolean Deployed true if the cargo is to be deployed. false or nil otherwise. - function CARGO:SetDeployed( Deployed ) - self.Deployed = Deployed - end - - --- Is the cargo deployed - -- @param #CARGO self - -- @return #boolean - function CARGO:IsDeployed() - return self.Deployed - end - - --- Template method to spawn a new representation of the CARGO in the simulator. - -- @param #CARGO self - -- @return #CARGO - function CARGO:Spawn( PointVec2 ) - self:T() - - end - - --- Signal a flare at the position of the CARGO. - -- @param #CARGO self - -- @param Utilities.Utils#FLARECOLOR FlareColor - function CARGO:Flare( FlareColor ) - if self:IsUnLoaded() then - trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 ) - end - end - - --- Signal a white flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareWhite() - self:Flare( trigger.flareColor.White ) - end - - --- Signal a yellow flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareYellow() - self:Flare( trigger.flareColor.Yellow ) - end - - --- Signal a green flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareGreen() - self:Flare( trigger.flareColor.Green ) - end - - --- Signal a red flare at the position of the CARGO. - -- @param #CARGO self - function CARGO:FlareRed() - self:Flare( trigger.flareColor.Red ) - end - - --- Smoke the CARGO. - -- @param #CARGO self - -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. - -- @param #number Radius The radius of randomization around the center of the Cargo. - function CARGO:Smoke( SmokeColor, Radius ) - if self:IsUnLoaded() then - if Radius then - trigger.action.smoke( self.CargoObject:GetRandomVec3( Radius ), SmokeColor ) - else - trigger.action.smoke( self.CargoObject:GetVec3(), SmokeColor ) - end - end - end - - --- Smoke the CARGO Green. - -- @param #CARGO self - function CARGO:SmokeGreen() - self:Smoke( trigger.smokeColor.Green, Range ) - end - - --- Smoke the CARGO Red. - -- @param #CARGO self - function CARGO:SmokeRed() - self:Smoke( trigger.smokeColor.Red, Range ) - end - - --- Smoke the CARGO White. - -- @param #CARGO self - function CARGO:SmokeWhite() - self:Smoke( trigger.smokeColor.White, Range ) - end - - --- Smoke the CARGO Orange. - -- @param #CARGO self - function CARGO:SmokeOrange() - self:Smoke( trigger.smokeColor.Orange, Range ) - end - - --- Smoke the CARGO Blue. - -- @param #CARGO self - function CARGO:SmokeBlue() - self:Smoke( trigger.smokeColor.Blue, Range ) - end - - --- Set the Load radius, which is the radius till when the Cargo can be loaded. - -- @param #CARGO self - -- @param #number LoadRadius The radius till Cargo can be loaded. - -- @return #CARGO - function CARGO:SetLoadRadius( LoadRadius ) - self.LoadRadius = LoadRadius or 150 - end - - --- Get the Load radius, which is the radius till when the Cargo can be loaded. - -- @param #CARGO self - -- @return #number The radius till Cargo can be loaded. - function CARGO:GetLoadRadius() - return self.LoadRadius - end - - --- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded. - -- @param #CARGO self - -- @param Core.Point#COORDINATE Coordinate - -- @return #boolean true if the CargoGroup is within the loading radius. - function CARGO:IsInLoadRadius( Coordinate ) - self:T( { Coordinate, LoadRadius = self.LoadRadius } ) - - local Distance = 0 - if self:IsUnLoaded() then - local CargoCoordinate = self.CargoObject:GetCoordinate() - Distance = Coordinate:Get2DDistance( CargoCoordinate ) - self:T( Distance ) - if Distance <= self.LoadRadius then - return true - end - end - - return false - end - - --- Check if the Cargo can report itself to be Boarded or Loaded. - -- @param #CARGO self - -- @param Core.Point#COORDINATE Coordinate - -- @return #boolean true if the Cargo can report itself. - function CARGO:IsInReportRadius( Coordinate ) - self:T( { Coordinate } ) - - local Distance = 0 - if self:IsUnLoaded() then - Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) - self:T( Distance ) - if Distance <= self.LoadRadius then - return true - end - end - - return false - end - - - --- 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). - -- @return #boolean - function CARGO:IsNear( Coordinate, NearRadius ) - --self:T( { PointVec2 = PointVec2, NearRadius = NearRadius } ) - - if self.CargoObject:IsAlive() then - --local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) - --self:T( { CargoObjectName = self.CargoObject:GetName() } ) - --self:T( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) - --self:T( { PointVec2 = PointVec2:GetVec2() } ) - local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) - --self:T( { Distance = Distance, NearRadius = NearRadius or "nil" } ) - - if Distance <= NearRadius then - --self:T( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } ) - return true - end - end - - --self:T( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } ) - return false - end - - --- Check if Cargo is the given @{Core.Zone}. - -- @param #CARGO self - -- @param Core.Zone#ZONE_BASE Zone - -- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone. - function CARGO:IsInZone( Zone ) - --self:T( { Zone } ) - - if self:IsLoaded() then - return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() ) - else - --self:T( { Size = self.CargoObject:GetSize(), Units = self.CargoObject:GetUnits() } ) - if self.CargoObject:GetSize() ~= 0 then - return Zone:IsPointVec2InZone( self.CargoObject:GetPointVec2() ) - else - return false - end - end - - return nil - - end - - --- Get the current PointVec2 of the cargo. - -- @param #CARGO self - -- @return Core.Point#COORDINATE - function CARGO:GetPointVec2() - return self.CargoObject:GetPointVec2() - end - - --- Get the current Coordinate of the cargo. - -- @param #CARGO self - -- @return Core.Point#COORDINATE - function CARGO:GetCoordinate() - 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. - -- @return #CARGO - function CARGO:SetWeight( Weight ) - self.Weight = Weight - 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 - -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group. - -- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. - function CARGO:MessageToGroup( Message, CarrierGroup, Name ) - - MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( CarrierGroup ) - - end - - --- Report to a Carrier Group. - -- @param #CARGO self - -- @param #string Action The string describing the action for the cargo. - -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to. - -- @return #CARGO - function CARGO:Report( ReportText, Action, CarrierGroup ) - - if not self.Reported[CarrierGroup] or not self.Reported[CarrierGroup][Action] then - self.Reported[CarrierGroup] = {} - self.Reported[CarrierGroup][Action] = true - self:MessageToGroup( ReportText, CarrierGroup ) - if self.ReportFlareColor then - if not self.Reported[CarrierGroup]["Flaring"] then - self:Flare( self.ReportFlareColor ) - self.Reported[CarrierGroup]["Flaring"] = true - end - end - if self.ReportSmokeColor then - if not self.Reported[CarrierGroup]["Smoking"] then - self:Smoke( self.ReportSmokeColor ) - self.Reported[CarrierGroup]["Smoking"] = true - end - end - end - end - - --- Report to a Carrier Group with a Flaring signal. - -- @param #CARGO self - -- @param Utilities.Utils#UTILS.FlareColor FlareColor the color of the flare. - -- @return #CARGO - function CARGO:ReportFlare( FlareColor ) - - self.ReportFlareColor = FlareColor - end - - --- Report to a Carrier Group with a Smoking signal. - -- @param #CARGO self - -- @param Utilities.Utils#UTILS.SmokeColor SmokeColor the color of the smoke. - -- @return #CARGO - function CARGO:ReportSmoke( SmokeColor ) - - self.ReportSmokeColor = SmokeColor - end - - --- Reset the reporting for a Carrier Group. - -- @param #CARGO self - -- @param #string Action The string describing the action for the cargo. - -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to. - -- @return #CARGO - function CARGO:ReportReset( Action, CarrierGroup ) - - self.Reported[CarrierGroup][Action] = nil - end - - --- Reset all the reporting for a Carrier Group. - -- @param #CARGO self - -- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to. - -- @return #CARGO - function CARGO:ReportResetAll( CarrierGroup ) - - self.Reported[CarrierGroup] = nil - end - - --- Respawn the cargo when destroyed - -- @param #CARGO self - -- @param #boolean RespawnDestroyed - function CARGO:RespawnOnDestroyed( RespawnDestroyed ) - - if RespawnDestroyed then - self.onenterDestroyed = function( self ) - self:Respawn() - end - else - self.onenterDestroyed = nil - end - - end - -end -- CARGO - -do -- CARGO_REPRESENTABLE - - -- @type CARGO_REPRESENTABLE - -- @extends #CARGO - -- @field test - - --- Models CARGO that is representable by a Unit. - -- @field #CARGO_REPRESENTABLE CARGO_REPRESENTABLE - CARGO_REPRESENTABLE = { - ClassName = "CARGO_REPRESENTABLE" - } - - --- CARGO_REPRESENTABLE Constructor. - -- @param #CARGO_REPRESENTABLE self - -- @param Wrapper.Positionable#POSITIONABLE CargoObject The cargo object. - -- @param #string Type Type name - -- @param #string Name Name. - -- @param #number LoadRadius (optional) Radius in meters. - -- @param #number NearRadius (optional) Radius in meters when the cargo is loaded into the carrier. - -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius ) - - -- Inherit CARGO. - local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE - self:T( { Type, Name, LoadRadius, NearRadius } ) - - -- Descriptors. - local Desc=CargoObject:GetDesc() - self:T({Desc=Desc}) - - -- Weight. - local Weight = math.random( 80, 120 ) - - -- Adjust weight.. - if Desc then - if Desc.typeName == "2B11 mortar" then - Weight = 210 - else - Weight = Desc.massEmpty - end - end - - -- Set weight. - self:SetWeight( Weight ) - - return self - end - - --- CARGO_REPRESENTABLE Destructor. - -- @param #CARGO_REPRESENTABLE self - -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:Destroy() - - -- Cargo objects are deleted from the _DATABASE and SET_CARGO objects. - self:T( { CargoName = self:GetName() } ) - --_EVENTDISPATCHER:CreateEventDeleteCargo( self ) - - return self - end - - --- Route a cargo unit to a PointVec2. - -- @param #CARGO_REPRESENTABLE self - -- @param Core.Point#COORDINATE ToPointVec2 - -- @param #number Speed - -- @return #CARGO_REPRESENTABLE - function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed ) - self:F2( ToPointVec2 ) - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = ToPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - return self - end - - --- Send a message to a @{Wrapper.Group} through a communication channel near the cargo. - -- @param #CARGO_REPRESENTABLE self - -- @param #string Message - -- @param Wrapper.Group#GROUP TaskGroup - -- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. - function CARGO_REPRESENTABLE:MessageToGroup( Message, TaskGroup, Name ) - - local CoordinateZone = ZONE_RADIUS:New( "Zone" , self:GetCoordinate():GetVec2(), 500 ) - CoordinateZone:Scan( { Object.Category.UNIT } ) - for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do - local NearUnit = UNIT:Find( DCSUnit ) - self:T({NearUnit=NearUnit}) - local NearUnitCoalition = NearUnit:GetCoalition() - local CargoCoalition = self:GetCoalition() - if NearUnitCoalition == CargoCoalition then - local Attributes = NearUnit:GetDesc() - self:T({Desc=Attributes}) - if NearUnit:HasAttribute( "Trucks" ) then - MESSAGE:New( Message, 20, NearUnit:GetCallsign() .. " reporting - Cargo " .. self:GetName() ):ToGroup( TaskGroup ) - break - end - end - end - - end - -end -- CARGO_REPRESENTABLE - -do -- CARGO_REPORTABLE - - -- @type CARGO_REPORTABLE - -- @extends #CARGO - CARGO_REPORTABLE = { - ClassName = "CARGO_REPORTABLE" - } - - --- CARGO_REPORTABLE Constructor. - -- @param #CARGO_REPORTABLE self - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number LoadRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_REPORTABLE - function CARGO_REPORTABLE:New( Type, Name, Weight, LoadRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPORTABLE - self:T( { Type, Name, Weight, LoadRadius, NearRadius } ) - - return self - end - - --- Send a CC message to a @{Wrapper.Group}. - -- @param #CARGO_REPORTABLE self - -- @param #string Message - -- @param Wrapper.Group#GROUP TaskGroup - -- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown. - function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name ) - - MESSAGE:New( Message, 20, "Cargo " .. self:GetName() .. " reporting" ):ToGroup( TaskGroup ) - - end - -end - -do -- CARGO_PACKAGE - - -- @type CARGO_PACKAGE - -- @extends #CARGO_REPRESENTABLE - CARGO_PACKAGE = { - ClassName = "CARGO_PACKAGE" - } - ---- CARGO_PACKAGE Constructor. --- @param #CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier The UNIT carrying the package. --- @param #string Type --- @param #string Name --- @param #number Weight --- @param #number LoadRadius (optional) --- @param #number NearRadius (optional) --- @return #CARGO_PACKAGE -function CARGO_PACKAGE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoCarrier, Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_PACKAGE - self:T( { Type, Name, Weight, LoadRadius, NearRadius } ) - - self:T( CargoCarrier ) - self.CargoCarrier = CargoCarrier - - return self -end - ---- Board Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number BoardDistance --- @param #number Angle -function CARGO_PACKAGE:onafterOnBoard( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - self:T() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only move the CargoCarrier to the New CargoCarrier when the New CargoCarrier is not in the air. - if not self.CargoInAir then - - local Points = {} - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = CargoCarrier:GetPointVec2():Translate( BoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:Boarded( CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - -end - ---- Check if CargoCarrier is near the Cargo to be Loaded. --- @param #CARGO_PACKAGE self --- @param Wrapper.Unit#UNIT CargoCarrier --- @return #boolean -function CARGO_PACKAGE:IsNear( CargoCarrier ) - self:T() - - local CargoCarrierPoint = CargoCarrier:GetCoordinate() - - local Distance = CargoCarrierPoint:Get2DDistance( self.CargoCarrier:GetCoordinate() ) - self:T( Distance ) - - if Distance <= self.NearRadius then - return true - else - return false - end -end - ---- Boarded Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @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:T() - - if self:IsNear( CargoCarrier ) then - self:__Load( 1, CargoCarrier, Speed, LoadDistance, Angle ) - else - self:__Boarded( 1, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle ) - end -end - ---- UnBoard Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number UnLoadDistance --- @param #number UnBoardDistance --- @param #number Radius --- @param #number Angle -function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnLoadDistance, UnBoardDistance, Radius, Angle ) - self:T() - - self.CargoInAir = self.CargoCarrier:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier 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 - - self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle ) - - local Points = {} - - local StartPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - self:T( { CargoCarrierHeading, CargoDeployHeading } ) - local CargoDeployPointVec2 = StartPointVec2:Translate( UnBoardDistance, CargoDeployHeading ) - - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = CargoCarrier:TaskRoute( Points ) - CargoCarrier:SetTask( TaskRoute, 1 ) - end - - self:__UnBoarded( 1 , CargoCarrier, Speed ) - -end - ---- UnBoarded Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed -function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed ) - self:T() - - if self:IsNear( CargoCarrier ) then - self:__UnLoad( 1, CargoCarrier, Speed ) - else - self:__UnBoarded( 1, CargoCarrier, Speed ) - end -end - ---- Load Event. --- @param #CARGO_PACKAGE self --- @param #string Event --- @param #string From --- @param #string To --- @param Wrapper.Unit#UNIT CargoCarrier --- @param #number Speed --- @param #number LoadDistance --- @param #number Angle -function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDistance, Angle ) - self:T() - - self.CargoCarrier = CargoCarrier - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading ) - - local Points = {} - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - ---- UnLoad Event. --- @param #CARGO_PACKAGE self --- @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 ) - self:T() - - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - self.CargoCarrier = CargoCarrier - - local Points = {} - Points[#Points+1] = StartPointVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoCarrier:TaskRoute( Points ) - self.CargoCarrier:SetTask( TaskRoute, 1 ) - -end - -end diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua deleted file mode 100644 index b9dcb2761..000000000 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ /dev/null @@ -1,340 +0,0 @@ ---- **Cargo** - Management of single cargo crates, which are based on a STATIC object. --- --- === --- --- ### [Demo Missions]() --- --- ### [YouTube Playlist]() --- --- === --- --- ### Author: **FlightControl** --- ### Contributions: --- --- === --- --- @module Cargo.CargoCrate --- @image Cargo_Crates.JPG - -do -- CARGO_CRATE - - --- Models the behaviour of cargo crates, which can be slingloaded and boarded on helicopters. - -- @type CARGO_CRATE - -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - - --- - -- ![Banner Image](..\Images\deprecated.png) - -- - --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. - -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO\_CRATE objects to and from carriers. - -- - -- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo: - -- - -- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC} module. - -- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter} module. - -- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane} module. - -- * AI Ships is planned. - -- - -- The above cargo classes are also used by the TASK_CARGO_ classes to allow human players to transport cargo as part of a tasking: - -- - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players. - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players. - -- - -- # Developer Note - -- - -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE - -- Therefore, this class is considered to be deprecated - -- - -- === - -- - -- @field #CARGO_CRATE - CARGO_CRATE = { - ClassName = "CARGO_CRATE" - } - - --- CARGO_CRATE Constructor. - -- @param #CARGO_CRATE self - -- @param Wrapper.Static#STATIC CargoStatic - -- @param #string Type - -- @param #string Name - -- @param #number LoadRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_CRATE - function CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_CRATE - self:T( { Type, Name, NearRadius } ) - - self.CargoObject = CargoStatic -- Wrapper.Static#STATIC - - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - - self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) - --self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) - - self:SetEventPriority( 4 ) - - self.NearRadius = NearRadius or 25 - - return self - end - - -- @param #CARGO_CRATE self - -- @param Core.Event#EVENTDATA EventData - function CARGO_CRATE:OnEventCargoDead( EventData ) - - local Destroyed = false - - if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then - if self.CargoObject:GetName() == EventData.IniUnitName then - if not self.NoDestroy then - Destroyed = true - end - end - else - if self:IsLoaded() then - local CarrierName = self.CargoCarrier:GetName() - if CarrierName == EventData.IniDCSUnitName then - MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll() - Destroyed = true - self.CargoCarrier:ClearCargo() - end - end - end - - if Destroyed then - self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } ) - self:Destroyed() - end - - end - - - --- Enter UnLoaded State. - -- @param #CARGO_CRATE self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE - function CARGO_CRATE:onenterUnLoaded( From, Event, To, ToPointVec2 ) - --self:T( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 10 - - if From == "Loaded" then - local StartCoordinate = self.CargoCarrier:GetCoordinate() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployCoord = StartCoordinate:Translate( Distance, CargoDeployHeading ) - - ToPointVec2 = ToPointVec2 or COORDINATE:NewFromVec2( { x= CargoDeployCoord.x, y = CargoDeployCoord.z } ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawnAt( ToPointVec2, 0 ) - self.CargoCarrier = nil - end - - end - - if self.OnUnLoadedCallBack then - self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) - self.OnUnLoadedCallBack = nil - end - - end - - - --- Loaded State. - -- @param #CARGO_CRATE self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier - function CARGO_CRATE:onenterLoaded( From, Event, To, CargoCarrier ) - --self:T( { From, Event, To, CargoCarrier } ) - - self.CargoCarrier = CargoCarrier - - -- Only destroy the CargoObject is if there is a CargoObject (packages don't have CargoObjects). - if self.CargoObject then - self:T("Destroying") - self.NoDestroy = true - self.CargoObject:Destroy( false ) -- Do not generate a remove unit event, because we want to keep the template for later respawn in the database. - --local Coordinate = self.CargoObject:GetCoordinate():GetRandomCoordinateInRadius( 50, 20 ) - --self.CargoObject:ReSpawnAt( Coordinate, 0 ) - end - end - - --- Check if the cargo can be Boarded. - -- @param #CARGO_CRATE self - function CARGO_CRATE:CanBoard() - return false - end - - --- Check if the cargo can be Unboarded. - -- @param #CARGO_CRATE self - function CARGO_CRATE:CanUnboard() - return false - end - - --- Check if the cargo can be sling loaded. - -- @param #CARGO_CRATE self - function CARGO_CRATE:CanSlingload() - return false - end - - --- Check if Cargo Crate is in the radius for the Cargo to be reported. - -- @param #CARGO_CRATE self - -- @param Core.Point#COORDINATE Coordinate - -- @return #boolean true if the Cargo Crate is within the report radius. - function CARGO_CRATE:IsInReportRadius( Coordinate ) - --self:T( { Coordinate, LoadRadius = self.LoadRadius } ) - - local Distance = 0 - if self:IsUnLoaded() then - Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) - --self:T( Distance ) - if Distance <= self.LoadRadius then - return true - end - end - - return false - end - - - --- Check if Cargo Crate is in the radius for the Cargo to be Boarded or Loaded. - -- @param #CARGO_CRATE self - -- @param Core.Point#Coordinate Coordinate - -- @return #boolean true if the Cargo Crate is within the loading radius. - function CARGO_CRATE:IsInLoadRadius( Coordinate ) - --self:T( { Coordinate, LoadRadius = self.NearRadius } ) - - local Distance = 0 - if self:IsUnLoaded() then - Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) - --self:T( Distance ) - if Distance <= self.NearRadius then - return true - end - end - - return false - end - - - - --- Get the current Coordinate of the CargoGroup. - -- @param #CARGO_CRATE self - -- @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_CRATE:GetCoordinate() - --self:T() - - return self.CargoObject:GetCoordinate() - end - - --- Check if the CargoGroup is alive. - -- @param #CARGO_CRATE self - -- @return #boolean true if the CargoGroup is alive. - -- @return #boolean false if the CargoGroup is dead. - function CARGO_CRATE:IsAlive() - - local Alive = true - - -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. - -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. - if self:IsLoaded() then - Alive = Alive == true and self.CargoCarrier:IsAlive() - else - Alive = Alive == true and self.CargoObject:IsAlive() - end - - return Alive - - end - - - --- Route Cargo to Coordinate and randomize locations. - -- @param #CARGO_CRATE self - -- @param Core.Point#COORDINATE Coordinate - function CARGO_CRATE:RouteTo( Coordinate ) - self:T( {Coordinate = Coordinate } ) - - end - - - --- Check if Cargo is near to the Carrier. - -- The Cargo is near to the Carrier within NearRadius. - -- @param #CARGO_CRATE 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. - function CARGO_CRATE:IsNear( CargoCarrier, NearRadius ) - self:T( {NearRadius = NearRadius } ) - - return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) - end - - --- Respawn the CargoGroup. - -- @param #CARGO_CRATE self - function CARGO_CRATE:Respawn() - - self:T( { "Respawning crate " .. self:GetName() } ) - - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event. - self:__Reset( -0.1 ) - end - - - end - - - --- Respawn the CargoGroup. - -- @param #CARGO_CRATE self - function CARGO_CRATE:onafterReset() - - self:T( { "Reset crate " .. self:GetName() } ) - - - -- Respawn the group... - if self.CargoObject then - self:SetDeployed( false ) - self:SetStartState( "UnLoaded" ) - self.CargoCarrier = nil - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - end - - - end - - --- Get the transportation method of the Cargo. - -- @param #CARGO_CRATE self - -- @return #string The transportation method of the Cargo. - function CARGO_CRATE:GetTransportationMethod() - if self:IsLoaded() then - return "for unloading" - else - if self:IsUnLoaded() then - return "for loading" - else - if self:IsDeployed() then - return "delivered" - end - end - end - return "" - end - -end - diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua deleted file mode 100644 index b756f456c..000000000 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ /dev/null @@ -1,777 +0,0 @@ ---- **Cargo** - Management of grouped cargo logistics, which are based on a GROUP object. --- --- === --- --- ### [Demo Missions]() --- --- ### [YouTube Playlist]() --- --- === --- --- ### Author: **FlightControl** --- ### Contributions: --- --- === --- --- @module Cargo.CargoGroup --- @image Cargo_Groups.JPG - - -do -- CARGO_GROUP - - --- @type CARGO_GROUP - -- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects. - -- @field #string GroupName The name of the CargoGroup. - -- @field Wrapper.Group#GROUÜ CargoCarrier The carrier group. - -- @extends Cargo.Cargo#CARGO_REPORTABLE - - --- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. - -- - -- ![Banner Image](..\Images\deprecated.png) - -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. - -- - -- The above cargo classes are used by the following AI_CARGO_ classes to allow AI groups to transport cargo: - -- - -- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC} module. - -- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter} module. - -- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Airplane} module. - -- * AI Ships is planned. - -- - -- The above cargo classes are also used by the TASK_CARGO_ classes to allow human players to transport cargo as part of a tasking: - -- - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players. - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players. - -- - -- # Developer Note - -- - -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE - -- Therefore, this class is considered to be deprecated - -- - -- @field #CARGO_GROUP CARGO_GROUP - -- - CARGO_GROUP = { - ClassName = "CARGO_GROUP", - } - - --- CARGO_GROUP constructor. - -- This make a new CARGO_GROUP from a @{Wrapper.Group} object. - -- It will "ungroup" the group object within the sim, and will create a @{Core.Set} of individual Unit objects. - -- @param #CARGO_GROUP self - -- @param Wrapper.Group#GROUP CargoGroup Group to be transported as cargo. - -- @param #string Type Cargo type, e.g. "Infantry". This is the type used in SET_CARGO:New():FilterTypes("Infantry") to define the valid cargo groups of the set. - -- @param #string Name A user defined name of the cargo group. This name CAN be the same as the group object but can also have a different name. This name MUST be unique! - -- @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, NearRadius ) - - -- Inherit CAROG_REPORTABLE - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP - self:T( { Type, Name, LoadRadius } ) - - self.CargoSet = SET_CARGO:New() - self.CargoGroup = CargoGroup - self.Grouped = true - self.CargoUnitTemplate = {} - - self.NearRadius = NearRadius - - self:SetDeployed( false ) - - local WeightGroup = 0 - local VolumeGroup = 0 - - self.CargoGroup:Destroy() -- destroy and generate a unit removal event, so that the database gets cleaned, and the linked sets get properly cleaned. - - local GroupName = CargoGroup:GetName() - self.CargoName = Name - self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) ) - - -- Deactivate late activation. - self.CargoTemplate.lateActivation=false - - self.GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - self.GroupTemplate.name = self.CargoName .. "#CARGO" - self.GroupTemplate.groupId = nil - - self.GroupTemplate.units = {} - - for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do - UnitTemplate.name = UnitTemplate.name .. "#CARGO" - local CargoUnitName = UnitTemplate.name - self.CargoUnitTemplate[CargoUnitName] = UnitTemplate - - self.GroupTemplate.units[#self.GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName] - self.GroupTemplate.units[#self.GroupTemplate.units].unitId = nil - - -- And we register the spawned unit as part of the CargoSet. - local Unit = UNIT:Register( CargoUnitName ) - - end - - -- Then we register the new group in the database - self.CargoGroup = GROUP:NewTemplate( self.GroupTemplate, self.GroupTemplate.CoalitionID, self.GroupTemplate.CategoryID, self.GroupTemplate.CountryID ) - - -- Now we spawn the new group based on the template created. - self.CargoObject = _DATABASE:Spawn( self.GroupTemplate ) - - for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do - - - local CargoUnitName = CargoUnit:GetName() - - local Cargo = CARGO_UNIT:New( CargoUnit, Type, CargoUnitName, LoadRadius, NearRadius ) - self.CargoSet:Add( CargoUnitName, Cargo ) - - WeightGroup = WeightGroup + Cargo:GetWeight() - - end - - self:SetWeight( WeightGroup ) - - self:T( { "Weight Cargo", WeightGroup } ) - - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - - self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) - --self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) - - self:SetEventPriority( 4 ) - - return self - end - - - --- Respawn the CargoGroup. - -- @param #CARGO_GROUP self - function CARGO_GROUP:Respawn() - - self:T( { "Respawning" } ) - - for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- Cargo.Cargo#CARGO - Cargo:Destroy() -- Destroy the cargo and generate a remove unit event to update the sets. - Cargo:SetStartState( "UnLoaded" ) - end - - -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( self.GroupTemplate ) - - for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do - - local CargoUnitName = CargoUnit:GetName() - - local Cargo = CARGO_UNIT:New( CargoUnit, self.Type, CargoUnitName, self.LoadRadius ) - self.CargoSet:Add( CargoUnitName, Cargo ) - - end - - self:SetDeployed( false ) - self:SetStartState( "UnLoaded" ) - - end - - --- Ungroup the cargo group into individual groups with one unit. - -- This is required because by default a group will move in formation and this is really an issue for group control. - -- Therefore this method is made to be able to ungroup a group. - -- This works for ground only groups. - -- @param #CARGO_GROUP self - function CARGO_GROUP:Ungroup() - - if self.Grouped == true then - - self.Grouped = false - - self.CargoGroup:Destroy() - - for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do - local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT - - if CargoUnit:IsUnLoaded() then - local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - --local GroupName = env.getValueDictByKey( GroupTemplate.name ) - - -- We create a new group object with one unit... - -- First we prepare the template... - GroupTemplate.name = self.CargoName .. "#CARGO#" .. CargoUnitName - GroupTemplate.groupId = nil - - if CargoUnit:IsUnLoaded() then - GroupTemplate.units = {} - GroupTemplate.units[1] = self.CargoUnitTemplate[CargoUnitName] - GroupTemplate.units[#GroupTemplate.units].unitId = nil - GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX() - GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY() - GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading() - end - - - -- Then we register the new group in the database - local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) - - -- Now we spawn the new group based on the template created. - _DATABASE:Spawn( GroupTemplate ) - end - end - - self.CargoObject = nil - end - - - end - - --- Regroup the cargo group into one group with multiple unit. - -- This is required because by default a group will move in formation and this is really an issue for group control. - -- Therefore this method is made to be able to regroup a group. - -- This works for ground only groups. - -- @param #CARGO_GROUP self - function CARGO_GROUP:Regroup() - - self:T("Regroup") - - if self.Grouped == false then - - self.Grouped = true - - local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - GroupTemplate.name = self.CargoName .. "#CARGO" - GroupTemplate.groupId = nil - GroupTemplate.units = {} - - for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do - local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT - - self:T( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } ) - - if CargoUnit:IsUnLoaded() then - - CargoUnit.CargoObject:Destroy() - - GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName] - GroupTemplate.units[#GroupTemplate.units].unitId = nil - GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX() - GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY() - GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading() - end - end - - -- Then we register the new group in the database - self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID ) - - self:T( { "Regroup", GroupTemplate } ) - - -- Now we spawn the new group based on the template created. - self.CargoObject = _DATABASE:Spawn( GroupTemplate ) - end - - end - - - --- @param #CARGO_GROUP self - -- @param Core.Event#EVENTDATA EventData - function CARGO_GROUP:OnEventCargoDead( EventData ) - - self:T(EventData) - - local Destroyed = false - - if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() or self:IsUnboarding() then - Destroyed = true - for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do - local Cargo = CargoData -- Cargo.Cargo#CARGO - if Cargo:IsAlive() then - Destroyed = false - else - Cargo:Destroyed() - end - end - else - local CarrierName = self.CargoCarrier:GetName() - if CarrierName == EventData.IniDCSUnitName then - MESSAGE:New( "Cargo is lost from carrier " .. CarrierName, 15 ):ToAll() - Destroyed = true - self.CargoCarrier:ClearCargo() - end - end - - if Destroyed then - self:Destroyed() - self:T( { "Cargo group destroyed" } ) - end - - end - - --- After Board Event. - -- @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:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) - self:T( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } ) - - NearRadius = NearRadius or self.NearRadius - - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo, ... ) - self:T( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } ) - local CargoGroup = Cargo.CargoObject --Wrapper.Group#GROUP - CargoGroup:OptionAlarmStateGreen() - Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) - end, ... - ) - - self:__Boarding( -1, CargoCarrier, NearRadius, ... ) - - end - - --- Enter Loaded State. - -- @param #CARGO_GROUP self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier - function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... ) - --self:T( { From, Event, To, CargoCarrier, ...} ) - - if From == "UnLoaded" then - -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - if not Cargo:IsDestroyed() then - Cargo:Load( CargoCarrier ) - end - end - end - - --self.CargoObject:Destroy() - self.CargoCarrier = CargoCarrier - self.CargoCarrier:AddCargo( self ) - - end - - --- Leave Boarding State. - -- @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:T( { CargoCarrier.UnitName, From, Event, To } ) - - local Boarded = true - local Cancelled = false - local Dead = true - - self.CargoSet:Flush() - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - --self:T( { Cargo:GetName(), Cargo.current } ) - - - if not Cargo:is( "Loaded" ) - and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. - Boarded = false - end - - if Cargo:is( "UnLoaded" ) then - Cancelled = true - end - - if not Cargo:is( "Destroyed" ) then - Dead = false - end - - end - - if not Dead then - - if not Cancelled then - if not Boarded then - self:__Boarding( -5, CargoCarrier, NearRadius, ... ) - else - self:T("Group Cargo is loaded") - self:__Load( 1, CargoCarrier, ... ) - end - else - self:__CancelBoarding( 1, CargoCarrier, NearRadius, ... ) - end - else - self:__Destroyed( 1, CargoCarrier, NearRadius, ... ) - end - - end - - --- Enter UnBoarding State. - -- @param #CARGO_GROUP self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE ToPointVec2 - -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. - function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... ) - self:T( {From, Event, To, ToPointVec2, NearRadius } ) - - NearRadius = NearRadius or 25 - - local Timer = 1 - - if From == "Loaded" then - - if self.CargoObject then - self.CargoObject:Destroy() - end - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - --- @param Cargo.Cargo#CARGO Cargo - function( Cargo, NearRadius ) - if not Cargo:IsDestroyed() then - local ToVec=nil - if ToPointVec2==nil then - ToVec=self.CargoCarrier:GetPointVec2():GetRandomPointVec2InRadius(2*NearRadius, NearRadius) - else - ToVec=ToPointVec2 - end - Cargo:__UnBoard( Timer, ToVec, NearRadius ) - Timer = Timer + 1 - end - end, { NearRadius } - ) - - - self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) - end - - end - - --- Leave UnBoarding State. - -- @param #CARGO_GROUP self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE 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:T( { From, Event, To, ToPointVec2, NearRadius } ) - - --local NearRadius = NearRadius or 25 - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - local UnBoarded = true - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do - self:T( { Cargo:GetName(), Cargo.current } ) - if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then - UnBoarded = false - end - end - - if UnBoarded then - self:__UnLoad( 1, ToPointVec2, ... ) - else - self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) - end - - return false - end - - end - - --- Enter UnLoaded State. - -- @param #CARGO_GROUP self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE ToPointVec2 - function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... ) - --self:T( { From, Event, To, ToPointVec2 } ) - - if From == "Loaded" then - - -- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2 - self.CargoSet:ForEach( - function( Cargo ) - --Cargo:UnLoad( ToPointVec2 ) - local RandomVec2=nil - if ToPointVec2 then - RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10) - end - Cargo:UnBoard( RandomVec2 ) - end - ) - - end - - self.CargoCarrier:RemoveCargo( self ) - self.CargoCarrier = nil - - end - - - --- Get the current Coordinate of the CargoGroup. - -- @param #CARGO_GROUP self - -- @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() - local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO - - if Cargo then - return Cargo.CargoObject:GetCoordinate() - end - - return nil - end - - --- Get the x position of the cargo. - -- @param #CARGO_GROUP self - -- @return #number - function CARGO:GetX() - - local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO - - if Cargo then - return Cargo:GetCoordinate().x - end - - return nil - end - - --- Get the y position of the cargo. - -- @param #CARGO_GROUP self - -- @return #number - function CARGO:GetY() - - local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO - - if Cargo then - return Cargo:GetCoordinate().z - end - - return nil - end - - - - --- Check if the CargoGroup is alive. - -- @param #CARGO_GROUP self - -- @return #boolean true if the CargoGroup is alive. - -- @return #boolean false if the CargoGroup is dead. - function CARGO_GROUP:IsAlive() - - local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO - return Cargo ~= nil - - end - - - --- Get the first alive Cargo Unit of the Cargo Group. - -- @param #CARGO_GROUP self - -- @return #CARGO_GROUP - function CARGO_GROUP:GetFirstAlive() - - local CargoFirstAlive = nil - - for _, Cargo in pairs( self.CargoSet:GetSet() ) do - if not Cargo:IsDestroyed() then - CargoFirstAlive = Cargo - break - end - end - return CargoFirstAlive - end - - - --- Get the amount of cargo units in the group. - -- @param #CARGO_GROUP self - -- @return #CARGO_GROUP - function CARGO_GROUP:GetCount() - return self.CargoSet:Count() - end - - - --- Get the underlying GROUP object from the CARGO_GROUP. - -- @param #CARGO_GROUP self - -- @return #CARGO_GROUP - function CARGO_GROUP:GetGroup( Cargo ) - local Cargo = Cargo or self:GetFirstAlive() -- Cargo.Cargo#CARGO - return Cargo.CargoObject:GetGroup() - end - - - --- Route Cargo to Coordinate and randomize locations. - -- @param #CARGO_GROUP self - -- @param Core.Point#COORDINATE Coordinate - function CARGO_GROUP:RouteTo( Coordinate ) - --self:T( {Coordinate = Coordinate } ) - - -- For each Cargo within the CargoSet, route each object to the Coordinate - self.CargoSet:ForEach( - function( Cargo ) - Cargo.CargoObject:RouteGroundTo( Coordinate, 10, "vee", 0 ) - end - ) - - end - - --- Check if Cargo is near to the Carrier. - -- The Cargo is near to the Carrier if the first unit of the Cargo Group is within NearRadius. - -- @param #CARGO_GROUP self - -- @param Wrapper.Group#GROUP CargoCarrier - -- @param #number NearRadius - -- @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:T( {NearRadius = NearRadius } ) - - for _, Cargo in pairs( self.CargoSet:GetSet() ) do - local Cargo = Cargo -- Cargo.Cargo#CARGO - if Cargo:IsAlive() then - if Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then - self:T( "Near" ) - return true - end - end - end - - return nil - end - - --- Check if Cargo Group is in the radius for the Cargo to be Boarded. - -- @param #CARGO_GROUP self - -- @param Core.Point#COORDINATE Coordinate - -- @return #boolean true if the Cargo Group is within the load radius. - function CARGO_GROUP:IsInLoadRadius( Coordinate ) - --self:T( { Coordinate } ) - - local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO - - if Cargo then - local Distance = 0 - local CargoCoordinate - if Cargo:IsLoaded() then - CargoCoordinate = Cargo.CargoCarrier:GetCoordinate() - else - CargoCoordinate = Cargo.CargoObject:GetCoordinate() - end - - -- FF check if coordinate could be obtained. This was commented out for some (unknown) reason. But the check seems valid! - if CargoCoordinate then - Distance = Coordinate:Get2DDistance( CargoCoordinate ) - else - return false - end - - self:T( { Distance = Distance, LoadRadius = self.LoadRadius } ) - if Distance <= self.LoadRadius then - return true - else - return false - end - end - - return nil - - end - - - --- Check if Cargo Group is in the report radius. - -- @param #CARGO_GROUP self - -- @param Core.Point#Coordinate Coordinate - -- @return #boolean true if the Cargo Group is within the report radius. - function CARGO_GROUP:IsInReportRadius( Coordinate ) - --self:T( { Coordinate } ) - - local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO - - if Cargo then - self:T( { Cargo } ) - local Distance = 0 - if Cargo:IsUnLoaded() then - Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() ) - --self:T( Distance ) - if Distance <= self.LoadRadius then - return true - end - end - end - - return nil - - end - - - --- Signal a flare at the position of the CargoGroup. - -- @param #CARGO_GROUP self - -- @param Utilities.Utils#FLARECOLOR FlareColor - function CARGO_GROUP:Flare( FlareColor ) - - local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO - if Cargo then - Cargo:Flare( FlareColor ) - end - end - - --- Smoke the CargoGroup. - -- @param #CARGO_GROUP self - -- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke. - -- @param #number Radius The radius of randomization around the center of the first element of the CargoGroup. - function CARGO_GROUP:Smoke( SmokeColor, Radius ) - - local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO - - if Cargo then - Cargo:Smoke( SmokeColor, Radius ) - end - end - - --- Check if the first element of the CargoGroup is the given @{Core.Zone}. - -- @param #CARGO_GROUP self - -- @param Core.Zone#ZONE_BASE Zone - -- @return #boolean **true** if the first element of the CargoGroup is in the Zone - -- @return #boolean **false** if there is no element of the CargoGroup in the Zone. - function CARGO_GROUP:IsInZone( Zone ) - --self:T( { Zone } ) - - local Cargo = self.CargoSet:GetFirst() -- Cargo.Cargo#CARGO - - if Cargo then - return Cargo:IsInZone( Zone ) - end - - return nil - - end - - --- Get the transportation method of the Cargo. - -- @param #CARGO_GROUP self - -- @return #string The transportation method of the Cargo. - function CARGO_GROUP:GetTransportationMethod() - if self:IsLoaded() then - return "for unboarding" - else - if self:IsUnLoaded() then - return "for boarding" - else - if self:IsDeployed() then - return "delivered" - end - end - end - return "" - end - - - -end -- CARGO_GROUP - diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua deleted file mode 100644 index 90209e8c0..000000000 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ /dev/null @@ -1,277 +0,0 @@ ---- **Cargo** - Management of single cargo crates, which are based on a STATIC object. The cargo can only be slingloaded. --- --- === --- --- ### [Demo Missions]() --- --- ### [YouTube Playlist]() --- --- === --- --- ### Author: **FlightControl** --- ### Contributions: --- --- === --- --- @module Cargo.CargoSlingload --- @image Cargo_Slingload.JPG - - -do -- CARGO_SLINGLOAD - - --- Models the behaviour of cargo crates, which can only be slingloaded. - -- @type CARGO_SLINGLOAD - -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - - --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. - -- - -- The above cargo classes are also used by the TASK_CARGO_ classes to allow human players to transport cargo as part of a tasking: - -- - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players. - -- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players. - -- - -- # Developer Note - -- - -- ![Banner Image](..\Images\deprecated.png) - -- - -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE - -- Therefore, this class is considered to be deprecated - -- - -- === - -- - -- @field #CARGO_SLINGLOAD - CARGO_SLINGLOAD = { - ClassName = "CARGO_SLINGLOAD" - } - - --- CARGO_SLINGLOAD Constructor. - -- @param #CARGO_SLINGLOAD self - -- @param Wrapper.Static#STATIC CargoStatic - -- @param #string Type - -- @param #string Name - -- @param #number LoadRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_SLINGLOAD - function CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoStatic, Type, Name, nil, LoadRadius, NearRadius ) ) -- #CARGO_SLINGLOAD - self:T( { Type, Name, NearRadius } ) - - self.CargoObject = CargoStatic - - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - - self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) - --self:HandleEvent( EVENTS.RemoveUnit, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) - - self:SetEventPriority( 4 ) - - self.NearRadius = NearRadius or 25 - - return self - end - - - -- @param #CARGO_SLINGLOAD self - -- @param Core.Event#EVENTDATA EventData - function CARGO_SLINGLOAD:OnEventCargoDead( EventData ) - - local Destroyed = false - - if self:IsDestroyed() or self:IsUnLoaded() then - if self.CargoObject:GetName() == EventData.IniUnitName then - if not self.NoDestroy then - Destroyed = true - end - end - end - - if Destroyed then - self:I( { "Cargo crate destroyed: " .. self.CargoObject:GetName() } ) - self:Destroyed() - end - - end - - - --- Check if the cargo can be Slingloaded. - -- @param #CARGO_SLINGLOAD self - function CARGO_SLINGLOAD:CanSlingload() - return true - end - - --- Check if the cargo can be Boarded. - -- @param #CARGO_SLINGLOAD self - function CARGO_SLINGLOAD:CanBoard() - return false - end - - --- Check if the cargo can be Unboarded. - -- @param #CARGO_SLINGLOAD self - function CARGO_SLINGLOAD:CanUnboard() - return false - end - - --- Check if the cargo can be Loaded. - -- @param #CARGO_SLINGLOAD self - function CARGO_SLINGLOAD:CanLoad() - return false - end - - --- Check if the cargo can be Unloaded. - -- @param #CARGO_SLINGLOAD self - function CARGO_SLINGLOAD:CanUnload() - return false - end - - - --- Check if Cargo Crate is in the radius for the Cargo to be reported. - -- @param #CARGO_SLINGLOAD self - -- @param Core.Point#COORDINATE Coordinate - -- @return #boolean true if the Cargo Crate is within the report radius. - function CARGO_SLINGLOAD:IsInReportRadius( Coordinate ) - --self:T( { Coordinate, LoadRadius = self.LoadRadius } ) - - local Distance = 0 - if self:IsUnLoaded() then - Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) - if Distance <= self.LoadRadius then - return true - end - end - - return false - end - - - --- Check if Cargo Slingload is in the radius for the Cargo to be Boarded or Loaded. - -- @param #CARGO_SLINGLOAD self - -- @param Core.Point#COORDINATE Coordinate - -- @return #boolean true if the Cargo Slingload is within the loading radius. - function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate ) - --self:T( { Coordinate } ) - - local Distance = 0 - if self:IsUnLoaded() then - Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) - if Distance <= self.NearRadius then - return true - end - end - - return false - end - - - - --- Get the current Coordinate of the CargoGroup. - -- @param #CARGO_SLINGLOAD self - -- @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_SLINGLOAD:GetCoordinate() - --self:T() - - return self.CargoObject:GetCoordinate() - end - - --- Check if the CargoGroup is alive. - -- @param #CARGO_SLINGLOAD self - -- @return #boolean true if the CargoGroup is alive. - -- @return #boolean false if the CargoGroup is dead. - function CARGO_SLINGLOAD:IsAlive() - - local Alive = true - - -- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive. - -- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive. - if self:IsLoaded() then - Alive = Alive == true and self.CargoCarrier:IsAlive() - else - Alive = Alive == true and self.CargoObject:IsAlive() - end - - return Alive - - end - - - --- Route Cargo to Coordinate and randomize locations. - -- @param #CARGO_SLINGLOAD self - -- @param Core.Point#COORDINATE Coordinate - function CARGO_SLINGLOAD:RouteTo( Coordinate ) - --self:T( {Coordinate = Coordinate } ) - - end - - - --- Check if Cargo is near to the Carrier. - -- The Cargo is near to the Carrier within NearRadius. - -- @param #CARGO_SLINGLOAD 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. - function CARGO_SLINGLOAD:IsNear( CargoCarrier, NearRadius ) - --self:T( {NearRadius = NearRadius } ) - - return self:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) - end - - - --- Respawn the CargoGroup. - -- @param #CARGO_SLINGLOAD self - function CARGO_SLINGLOAD:Respawn() - - --self:T( { "Respawning slingload " .. self:GetName() } ) - - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn() -- A cargo destroy crates a DEAD event. - self:__Reset( -0.1 ) - end - - - end - - - --- Respawn the CargoGroup. - -- @param #CARGO_SLINGLOAD self - function CARGO_SLINGLOAD:onafterReset() - - --self:T( { "Reset slingload " .. self:GetName() } ) - - - -- Respawn the group... - if self.CargoObject then - self:SetDeployed( false ) - self:SetStartState( "UnLoaded" ) - self.CargoCarrier = nil - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) - end - - - end - - --- Get the transportation method of the Cargo. - -- @param #CARGO_SLINGLOAD self - -- @return #string The transportation method of the Cargo. - function CARGO_SLINGLOAD:GetTransportationMethod() - if self:IsLoaded() then - return "for sling loading" - else - if self:IsUnLoaded() then - return "for sling loading" - else - if self:IsDeployed() then - return "delivered" - end - end - end - return "" - end - -end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua deleted file mode 100644 index bc504d003..000000000 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ /dev/null @@ -1,397 +0,0 @@ ---- **Cargo** - Management of single cargo logistics, which are based on a UNIT object. --- --- === --- --- ### [Demo Missions]() --- --- ### [YouTube Playlist]() --- --- === --- --- ### Author: **FlightControl** --- ### Contributions: --- --- === --- --- @module Cargo.CargoUnit --- @image Cargo_Units.JPG - -do -- CARGO_UNIT - - --- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded. - -- @type CARGO_UNIT - -- @extends Cargo.Cargo#CARGO_REPRESENTABLE - - --- Defines a cargo that is represented by a UNIT object within the simulator, and can be transported by a carrier. - -- Use the event functions as described above to Load, UnLoad, Board, UnBoard the CARGO_UNIT objects to and from carriers. - -- Note that ground forces behave in a group, and thus, act in formation, regardless if one unit is commanded to move. - -- - -- This class is used in CARGO_GROUP, and is not meant to be used by mission designers individually. - -- - -- # Developer Note - -- - -- ![Banner Image](..\Images\deprecated.png) - -- - -- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE - -- Therefore, this class is considered to be deprecated - -- - -- === - -- - -- @field #CARGO_UNIT CARGO_UNIT - -- - CARGO_UNIT = { - ClassName = "CARGO_UNIT" - } - - --- CARGO_UNIT Constructor. - -- @param #CARGO_UNIT self - -- @param Wrapper.Unit#UNIT CargoUnit - -- @param #string Type - -- @param #string Name - -- @param #number Weight - -- @param #number LoadRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_UNIT - function CARGO_UNIT:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) - - -- Inherit CARGO_REPRESENTABLE. - local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) ) -- #CARGO_UNIT - - -- Debug info. - self:T({Type=Type, Name=Name, LoadRadius=LoadRadius, NearRadius=NearRadius}) - - -- Set cargo object. - self.CargoObject = CargoUnit - - -- Set event prio. - self:SetEventPriority( 5 ) - - return self - end - - --- Enter UnBoarding State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE ToPointVec2 - -- @param #number NearRadius (optional) Defaut 25 m. - function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:T( { From, Event, To, ToPointVec2, NearRadius } ) - - local Angle = 180 - local Speed = 60 - local DeployDistance = 9 - local RouteDistance = 60 - - if From == "Loaded" then - - if not self:IsDestroyed() then - - local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE - - if CargoCarrier:IsAlive() then - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - - - local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - - - -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) - local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) - local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) - --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) - - ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) - - -- Respawn the group... - if self.CargoObject then - if CargoCarrier:IsShip() then - -- If CargoCarrier is a ship, we don't want to spawn the units in the water next to the boat. Use destination coord instead. - self.CargoObject:ReSpawnAt( ToPointVec2, CargoDeployHeading ) - else - self.CargoObject:ReSpawnAt( FromPointVec2, CargoDeployHeading ) - end - self:T( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) - self.CargoCarrier = nil - - local Points = {} - - -- From - Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) - - -- To - Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 1 ) - - - self:__UnBoarding( 1, ToPointVec2, NearRadius ) - end - else - -- the Carrier is dead. This cargo is dead too! - self:Destroyed() - end - end - end - - end - - --- Leave UnBoarding State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE ToPointVec2 - -- @param #number NearRadius (optional) Defaut 100 m. - function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:T( { From, Event, To, ToPointVec2, NearRadius } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "UnBoarding" then - --if self:IsNear( ToPointVec2, NearRadius ) then - return true - --else - - --self:__UnBoarding( 1, ToPointVec2, NearRadius ) - --end - --return false - end - - end - - --- UnBoard Event. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE ToPointVec2 - -- @param #number NearRadius (optional) Defaut 100 m. - function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius ) - self:T( { From, Event, To, ToPointVec2, NearRadius } ) - - self.CargoInAir = self.CargoObject:InAir() - - self:T( self.CargoInAir ) - - -- Only unboard the cargo when the carrier 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 - - end - - self:__UnLoad( 1, ToPointVec2, NearRadius ) - - end - - - - --- Enter UnLoaded State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Core.Point#COORDINATE - function CARGO_UNIT:onenterUnLoaded( From, Event, To, ToPointVec2 ) - self:T( { ToPointVec2, From, Event, To } ) - - local Angle = 180 - local Speed = 10 - local Distance = 5 - - if From == "Loaded" then - local StartPointVec2 = self.CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployCoord = StartPointVec2:Translate( Distance, CargoDeployHeading ) - - ToPointVec2 = ToPointVec2 or COORDINATE:New( CargoDeployCoord.x, CargoDeployCoord.z ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawnAt( ToPointVec2, 0 ) - self.CargoCarrier = nil - end - - end - - if self.OnUnLoadedCallBack then - self.OnUnLoadedCallBack( self, unpack( self.OnUnLoadedParameters ) ) - self.OnUnLoadedCallBack = nil - end - - end - - --- Board Event. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Group#GROUP CargoCarrier - -- @param #number NearRadius - function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... ) - self:T( { From, Event, To, CargoCarrier, NearRadius = NearRadius } ) - - self.CargoInAir = self.CargoObject:InAir() - - local Desc = self.CargoObject:GetDesc() - local MaxSpeed = Desc.speedMaxOffRoad - local TypeName = Desc.typeName - - --self:T({Unit=self.CargoObject:GetName()}) - - -- A cargo unit can only be boarded if it is not dead - - -- Only move the group to the carrier when the cargo is not in the air - -- (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 = NearRadius or CargoCarrier:GetBoundingRadius() + 5 - if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then - self:Load( CargoCarrier, NearRadius, ... ) - else - if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then - self:Load( CargoCarrier, NearRadius, ... ) - else - - local Speed = 90 - local Angle = 180 - local Distance = 0 - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - -- Set the CargoObject to state Green to ensure it is boarding! - self.CargoObject:OptionAlarmStateGreen() - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 2 ) - self:__Boarding( -5, CargoCarrier, NearRadius, ... ) - self.RunCount = 0 - end - end - end - end - - - --- Boarding Event. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Client#CLIENT CargoCarrier - -- @param #number NearRadius Default 25 m. - function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) - self:T( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } ) - - self:T( { IsAlive=self.CargoObject:IsAlive() } ) - - if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then - if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then - local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5 - if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then - self:__Load( -1, CargoCarrier, ... ) - else - if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then - self:__Boarding( -1, CargoCarrier, NearRadius, ... ) - self.RunCount = self.RunCount + 1 - else - self:__Boarding( -2, CargoCarrier, NearRadius, ... ) - self.RunCount = self.RunCount + 2 - end - if self.RunCount >= 40 then - self.RunCount = 0 - local Speed = 90 - local Angle = 180 - local Distance = 0 - - --self:T({Unit=self.CargoObject:GetName()}) - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) - - -- Set the CargoObject to state Green to ensure it is boarding! - self.CargoObject:OptionAlarmStateGreen() - - local Points = {} - - local PointStartVec2 = self.CargoObject:GetPointVec2() - - Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" ) - Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" ) - - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 0.2 ) - end - end - else - self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() ) - self:CancelBoarding( CargoCarrier, NearRadius, ... ) - self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) ) - end - else - self:T("Something is wrong") - end - - end - - - --- Loaded State. - -- @param #CARGO_UNIT self - -- @param #string Event - -- @param #string From - -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier - function CARGO_UNIT:onenterLoaded( From, Event, To, CargoCarrier ) - self:T( { From, Event, To, CargoCarrier } ) - - self.CargoCarrier = CargoCarrier - - --self:T({Unit=self.CargoObject:GetName()}) - - -- Only destroy the CargoObject if there is a CargoObject (packages don't have CargoObjects). - if self.CargoObject then - self.CargoObject:Destroy( false ) - --self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 ) - end - end - - --- Get the transportation method of the Cargo. - -- @param #CARGO_UNIT self - -- @return #string The transportation method of the Cargo. - function CARGO_UNIT:GetTransportationMethod() - if self:IsLoaded() then - return "for unboarding" - else - if self:IsUnLoaded() then - return "for boarding" - else - if self:IsDeployed() then - return "delivered" - end - end - end - return "" - end - -end -- CARGO_UNIT diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 040969abb..7ee178f08 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -54,7 +54,6 @@ -- * AIRBASES -- * PLAYERSJOINED -- * PLAYERS --- * CARGOS -- * STORAGES (DCS warehouses) -- * DYNAMICCARGO -- @@ -81,7 +80,6 @@ DATABASE = { PLAYERSJOINED = {}, PLAYERUNITS = {}, CLIENTS = {}, - CARGOS = {}, AIRBASES = {}, COUNTRY_ID = {}, COUNTRY_NAME = {}, @@ -746,102 +744,6 @@ do -- OpsZone end -- OpsZone -do -- cargo - - --- Adds a Cargo based on the Cargo Name in the DATABASE. - -- @param #DATABASE self - -- @param #string CargoName The name of the airbase - function DATABASE:AddCargo( Cargo ) - - if not self.CARGOS[Cargo.Name] then - self.CARGOS[Cargo.Name] = Cargo - end - end - - - --- Deletes a Cargo from the DATABASE based on the Cargo Name. - -- @param #DATABASE self - -- @param #string CargoName The name of the airbase - function DATABASE:DeleteCargo( CargoName ) - - self.CARGOS[CargoName] = nil - end - - --- Finds an CARGO based on the CargoName. - -- @param #DATABASE self - -- @param #string CargoName - -- @return Cargo.Cargo#CARGO The found CARGO. - function DATABASE:FindCargo( CargoName ) - - local CargoFound = self.CARGOS[CargoName] - return CargoFound - end - - --- Checks if the Template name has a #CARGO tag. - -- If yes, the group is a cargo. - -- @param #DATABASE self - -- @param #string TemplateName - -- @return #boolean - function DATABASE:IsCargo( TemplateName ) - - TemplateName = env.getValueDictByKey( TemplateName ) - - local Cargo = TemplateName:match( "#(CARGO)" ) - - return Cargo and Cargo == "CARGO" - end - - --- Private method that registers new Static Templates within the DATABASE Object. - -- @param #DATABASE self - -- @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( Groups ) do - 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%(.*%)(.*)") - 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 - local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) - local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) - - self:I({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) - CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius ) - end - end - - for CargoStaticName, CargoStatic in pairs( self.STATICS ) do - if self:IsCargo( CargoStaticName ) then - local CargoInfo = CargoStaticName:match("#CARGO(.*)") - local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)") - local CargoName = CargoStaticName:match("(.*)#CARGO") - local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") - local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?") - local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName - local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) - local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) - - if Category == "SLING" then - self:I({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) - CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) - else - if Category == "CRATE" then - self:I({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) - CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) - end - end - end - end - - end - -end -- cargo - --- Finds a CLIENT based on the ClientName. -- @param #DATABASE self -- @param #string ClientName - Note this is the UNIT name of the client! @@ -2050,19 +1952,6 @@ function DATABASE:ForEachClient( IteratorFunction, FinalizeFunction, ... ) return self end ---- Iterate the DATABASE and call an iterator function for each CARGO, providing the CARGO object to the function and optional parameters. --- @param #DATABASE self --- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a CLIENT parameter. --- @return #DATABASE self -function DATABASE:ForEachCargo( IteratorFunction, FinalizeFunction, ... ) - self:F2( arg ) - - self:ForEach( IteratorFunction, FinalizeFunction, arg, self.CARGOS ) - - return self -end - - --- Handles the OnEventNewCargo event. -- @param #DATABASE self -- @param Core.Event#EVENTDATA EventData diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 7a9e22e46..e97b78d37 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -187,19 +187,17 @@ EVENT = { CreateMarkCoordinateOnEvent = false, } -world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000 -world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001 -world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002 -world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003 -world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004 -world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005 -world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006 -world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007 +world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1000 +world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1001 +world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1002 +world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1003 +world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1004 +world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1005 -- dynamic cargo -world.event.S_EVENT_NEW_DYNAMIC_CARGO = world.event.S_EVENT_MAX + 1008 -world.event.S_EVENT_DYNAMIC_CARGO_LOADED = world.event.S_EVENT_MAX + 1009 -world.event.S_EVENT_DYNAMIC_CARGO_UNLOADED = world.event.S_EVENT_MAX + 1010 -world.event.S_EVENT_DYNAMIC_CARGO_REMOVED = world.event.S_EVENT_MAX + 1011 +world.event.S_EVENT_NEW_DYNAMIC_CARGO = world.event.S_EVENT_MAX + 1006 +world.event.S_EVENT_DYNAMIC_CARGO_LOADED = world.event.S_EVENT_MAX + 1007 +world.event.S_EVENT_DYNAMIC_CARGO_UNLOADED = world.event.S_EVENT_MAX + 1008 +world.event.S_EVENT_DYNAMIC_CARGO_REMOVED = world.event.S_EVENT_MAX + 1009 --- The different types of events supported by MOOSE. @@ -234,8 +232,6 @@ EVENTS = { MarkChange = world.event.S_EVENT_MARK_CHANGE, MarkRemoved = world.event.S_EVENT_MARK_REMOVED, -- Moose Events - NewCargo = world.event.S_EVENT_NEW_CARGO, - DeleteCargo = world.event.S_EVENT_DELETE_CARGO, NewZone = world.event.S_EVENT_NEW_ZONE, DeleteZone = world.event.S_EVENT_DELETE_ZONE, NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL, @@ -512,16 +508,6 @@ local _EVENTMETA = { Event = "OnEventMarkRemoved", Text = "S_EVENT_MARK_REMOVED" }, - [EVENTS.NewCargo] = { - Order = 1, - Event = "OnEventNewCargo", - Text = "S_EVENT_NEW_CARGO" - }, - [EVENTS.DeleteCargo] = { - Order = 1, - Event = "OnEventDeleteCargo", - Text = "S_EVENT_DELETE_CARGO" - }, [EVENTS.NewZone] = { Order = 1, Event = "OnEventNewZone", @@ -1068,38 +1054,6 @@ end do -- Event Creation - -- TODO Remove old Cargo event - --- Creation of a New Cargo Event. - -- @param #EVENT self - -- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created. - function EVENT:CreateEventNewCargo( Cargo ) - self:F( { Cargo } ) - - local Event = { - id = EVENTS.NewCargo, - time = timer.getTime(), - cargo = Cargo, - } - - world.onEvent( Event ) - end - - -- TODO Remove old Cargo event - --- Creation of a Cargo Deletion Event. - -- @param #EVENT self - -- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created. - function EVENT:CreateEventDeleteCargo( Cargo ) - self:F( { Cargo } ) - - local Event = { - id = EVENTS.DeleteCargo, - time = timer.getTime(), - cargo = Cargo, - } - - world.onEvent( Event ) - end - --- Creation of a New Zone Event. -- @param #EVENT self -- @param Core.Zone#ZONE_BASE Zone The Zone created. @@ -1368,7 +1322,6 @@ function EVENT:onEvent( Event ) Event.IniDynamicCargoName = Event.IniUnitName Event.IniPlayerName = string.match(Event.IniUnitName,"^(.+)|%d%d:%d%d|PKG%d+") else - --Event.IniUnit = CARGO:FindByName( Event.IniDCSUnitName ) Event.IniUnit = STATIC:FindByName( Event.IniDCSUnitName, false ) end Event.IniCoalition = Event.IniDCSUnit:getCoalition() @@ -1540,12 +1493,6 @@ function EVENT:onEvent( Event ) Event.MarkGroupID = Event.groupID end - -- Cargo object. - if Event.cargo then - Event.Cargo = Event.cargo - Event.CargoName = Event.cargo.Name - end - -- Dynamic cargo Object if Event.dynamiccargo then Event.IniDynamicCargo = Event.dynamiccargo @@ -1707,15 +1654,6 @@ function EVENT:onEvent( Event ) end end - -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. - -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. - -- And this is a problem because it will remove all entries from the SET_CARGOs. - -- To prevent this from happening, the Cargo object has a flag NoDestroy. - -- When true, the SET_CARGO won't Remove the Cargo object from the set. - -- But we need to switch that flag off after the event handlers have been called. - if Event.id == EVENTS.DeleteCargo then - Event.Cargo.NoDestroy = nil - end else self:T( { EventMeta.Text, Event } ) end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index ee2b0c6ce..8d4a3189c 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -3725,25 +3725,6 @@ do -- COORDINATE local ModeA2A = nil - --[[ - if Task then - if Task:IsInstanceOf( TASK_A2A ) then - ModeA2A = true - else - if Task:IsInstanceOf( TASK_A2G ) then - ModeA2A = false - else - if Task:IsInstanceOf( TASK_CARGO ) then - ModeA2A = false - end - if Task:IsInstanceOf( TASK_CAPTURE_ZONE ) then - ModeA2A = false - end - end - end - end - --]] - if ModeA2A == nil then local IsAir = Controllable and ( Controllable:IsAirPlane() or Controllable:IsHelicopter() ) or false if IsAir then diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 27ec6c0e0..0d567c472 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -24,7 +24,6 @@ -- * @{#SET_STATIC}: Defines a collection of @{Wrapper.Static}s filtered by filter criteria. -- * @{#SET_CLIENT}: Defines a collection of @{Wrapper.Client}s filtered by filter criteria. -- * @{#SET_AIRBASE}: Defines a collection of @{Wrapper.Airbase}s filtered by filter criteria. --- * @{#SET_CARGO}: Defines a collection of @{Cargo.Cargo}s filtered by filter criteria. -- * @{#SET_ZONE}: Defines a collection of @{Core.Zone}s filtered by filter criteria. -- * @{#SET_SCENERY}: Defines a collection of @{Wrapper.Scenery}s added via a filtered @{#SET_ZONE}. -- * @{#SET_DYNAMICCARGO}: Defines a collection of @{Wrapper.DynamicCargo}s filtered by filter criteria. @@ -5781,431 +5780,6 @@ do -- SET_AIRBASE end -do -- SET_CARGO - - --- - -- @type SET_CARGO - -- @extends Core.Set#SET_BASE - - --- Mission designers can use the @{Core.Set#SET_CARGO} class to build sets of cargos optionally belonging to certain: - -- - -- * Coalitions - -- * Types - -- * Name or Prefix - -- - -- ## SET_CARGO constructor - -- - -- Create a new SET_CARGO object with the @{#SET_CARGO.New} method: - -- - -- * @{#SET_CARGO.New}: Creates a new SET_CARGO object. - -- - -- ## Add or Remove CARGOs from SET_CARGO - -- - -- CARGOs can be added and removed using the @{Core.Set#SET_CARGO.AddCargosByName} and @{Core.Set#SET_CARGO.RemoveCargosByName} respectively. - -- These methods take a single CARGO name or an array of CARGO names to be added or removed from SET_CARGO. - -- - -- ## SET_CARGO filter criteria - -- - -- You can set filter criteria to automatically maintain the SET_CARGO contents. - -- Filter criteria are defined by: - -- - -- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s). - -- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the same string(s). **Attention!** LUA regular expression apply here, so special characters in names like minus, dot, hash (#) etc might lead to unexpected results. - -- Have a read through here to understand the application of regular expressions: [LUA regular expressions](https://riptutorial.com/lua/example/20315/lua-pattern-matching) - -- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s). - -- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies). - -- - -- Once the filter criteria have been set for the SET_CARGO, you can start filtering using: - -- - -- * @{#SET_CARGO.FilterStart}: Starts the filtering of the cargos within the SET_CARGO. - -- - -- ## SET_CARGO iterators - -- - -- Once the filters have been defined and the SET_CARGO has been built, you can iterate the SET_CARGO with the available iterator methods. - -- The iterator methods will walk the SET_CARGO set, and call for each cargo within the set a function that you provide. - -- The following iterator methods are currently available within the SET_CARGO: - -- - -- * @{#SET_CARGO.ForEachCargo}: Calls a function for each cargo it finds within the SET_CARGO. - -- - -- @field #SET_CARGO SET_CARGO - SET_CARGO = { - ClassName = "SET_CARGO", - Cargos = {}, - Filter = { - Coalitions = nil, - Types = nil, - Countries = nil, - ClientPrefixes = nil, - }, - FilterMeta = { - Coalitions = { - red = coalition.side.RED, - blue = coalition.side.BLUE, - neutral = coalition.side.NEUTRAL, - }, - }, - } - - --- Creates a new SET_CARGO object, building a set of cargos belonging to a coalitions and categories. - -- @param #SET_CARGO self - -- @return #SET_CARGO - -- @usage - -- -- Define a new SET_CARGO Object. The DatabaseSet will contain a reference to all Cargos. - -- DatabaseSet = SET_CARGO:New() - function SET_CARGO:New() -- R2.1 - -- Inherits from BASE - local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.CARGOS)) -- #SET_CARGO - - return self - end - - --- Add CARGO to SET_CARGO. - -- @param Core.Set#SET_CARGO self - -- @param Cargo.Cargo#CARGO Cargo A single cargo. - -- @return Core.Set#SET_CARGO self - function SET_CARGO:AddCargo(Cargo) -- R2.4 - - self:Add(Cargo:GetName(), Cargo) - - return self - end - - --- Add CARGOs to SET_CARGO. - -- @param Core.Set#SET_CARGO self - -- @param #string AddCargoNames A single name or an array of CARGO names. - -- @return Core.Set#SET_CARGO self - function SET_CARGO:AddCargosByName(AddCargoNames) -- R2.1 - - local AddCargoNamesArray = (type(AddCargoNames) == "table") and AddCargoNames or { AddCargoNames } - - for AddCargoID, AddCargoName in pairs(AddCargoNamesArray) do - self:Add(AddCargoName, CARGO:FindByName(AddCargoName)) - end - - return self - end - - --- Remove CARGOs from SET_CARGO. - -- @param Core.Set#SET_CARGO self - -- @param Cargo.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names. - -- @return Core.Set#SET_CARGO self - function SET_CARGO:RemoveCargosByName(RemoveCargoNames) -- R2.1 - - local RemoveCargoNamesArray = (type(RemoveCargoNames) == "table") and RemoveCargoNames or { RemoveCargoNames } - - for RemoveCargoID, RemoveCargoName in pairs(RemoveCargoNamesArray) do - self:Remove(RemoveCargoName.CargoName) - end - - return self - end - - --- Finds a Cargo based on the Cargo Name. - -- @param #SET_CARGO self - -- @param #string CargoName - -- @return Cargo.Cargo#CARGO The found Cargo. - function SET_CARGO:FindCargo(CargoName) -- R2.1 - - local CargoFound = self.Set[CargoName] - return CargoFound - end - - --- Builds a set of cargos of coalitions. - -- Possible current coalitions are red, blue and neutral. - -- @param #SET_CARGO self - -- @param #string Coalitions Can take the following values: "red", "blue", "neutral". - -- @return #SET_CARGO self - - --- Builds a set of cargos of defined cargo types. - -- Possible current types are those types known within DCS world. - -- @param #SET_CARGO self - -- @param #string Types Can take those type strings known within DCS world. - -- @return #SET_CARGO self - function SET_CARGO:FilterTypes(Types) -- R2.1 - if not self.Filter.Types then - self.Filter.Types = {} - end - if type(Types) ~= "table" then - Types = { Types } - end - for TypeID, Type in pairs(Types) do - self.Filter.Types[Type] = Type - end - return self - end - - --- Builds a set of cargos of defined countries. - -- Possible current countries are those known within DCS world. - -- @param #SET_CARGO self - -- @param #string Countries Can take those country strings known within DCS world. - -- @return #SET_CARGO self - function SET_CARGO:FilterCountries(Countries) -- R2.1 - if not self.Filter.Countries then - self.Filter.Countries = {} - end - if type(Countries) ~= "table" then - Countries = { Countries } - end - for CountryID, Country in pairs(Countries) do - self.Filter.Countries[Country] = Country - end - return self - end - - --- Builds a set of CARGOs that contain a given string in their name. - -- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all cargos that **contain** the string. - -- @param #SET_CARGO self - -- @param #string Prefixes The string pattern(s) that need to be in the cargo name. Can also be passed as a `#table` of strings. - -- @return #SET_CARGO self - function SET_CARGO:FilterPrefixes(Prefixes) -- R2.1 - if not self.Filter.CargoPrefixes then - self.Filter.CargoPrefixes = {} - end - if type(Prefixes) ~= "table" then - Prefixes = { Prefixes } - end - for PrefixID, Prefix in pairs(Prefixes) do - self.Filter.CargoPrefixes[Prefix] = Prefix - end - return self - end - - --- Starts the filtering. - -- @param #SET_CARGO self - -- @return #SET_CARGO self - function SET_CARGO:FilterStart() -- R2.1 - - if _DATABASE then - self:_FilterStart() - self:HandleEvent(EVENTS.NewCargo) - self:HandleEvent(EVENTS.DeleteCargo) - end - - return self - end - - --- Stops the filtering for the defined collection. - -- @param #SET_CARGO self - -- @return #SET_CARGO self - function SET_CARGO:FilterStop() - - self:UnHandleEvent(EVENTS.NewCargo) - self:UnHandleEvent(EVENTS.DeleteCargo) - - return self - end - - --- Handles the Database to check on an event (birth) that the Object was added in the Database. - -- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event! - -- @param #SET_CARGO self - -- @param Core.Event#EVENTDATA Event - -- @return #string The name of the CARGO - -- @return #table The CARGO - function SET_CARGO:AddInDatabase(Event) -- R2.1 - --self:F3({ Event }) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] - end - - --- Handles the Database to check on any event that Object exists in the Database. - -- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa! - -- @param #SET_CARGO self - -- @param Core.Event#EVENTDATA Event - -- @return #string The name of the CARGO - -- @return #table The CARGO - function SET_CARGO:FindInDatabase(Event) -- R2.1 - --self:F3({ Event }) - - return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName] - end - - --- Iterate the SET_CARGO and call an iterator function for each CARGO, providing the CARGO and optional parameters. - -- @param #SET_CARGO self - -- @param #function IteratorFunction The function that will be called when there is an alive CARGO in the SET_CARGO. The function needs to accept a CARGO parameter. - -- @return #SET_CARGO self - function SET_CARGO:ForEachCargo(IteratorFunction, ...) -- R2.1 - --self:F2(arg) - - self:ForEach(IteratorFunction, arg, self:GetSet()) - - return self - end - - --- Iterate the SET_CARGO while identifying the nearest @{Cargo.Cargo#CARGO} from a @{Core.Point#COORDINATE}. - -- @param #SET_CARGO self - -- @param Core.Point#COORDINATE Coordinate A @{Core.Point#COORDINATE} object from where to evaluate the closest @{Cargo.Cargo#CARGO}. - -- @return Cargo.Cargo#CARGO The closest @{Cargo.Cargo#CARGO}. - function SET_CARGO:FindNearestCargoFromPointVec2(Coordinate) -- R2.1 - --self:F2(Coordinate) - - local NearestCargo = self:FindNearestObjectFromPointVec2(Coordinate) - return NearestCargo - end - - --- - -- @param #SET_CARGO self - function SET_CARGO:FirstCargoWithState(State) - - local FirstCargo = nil - - for CargoName, Cargo in pairs(self.Set) do - if Cargo:Is(State) then - FirstCargo = Cargo - break - end - end - - return FirstCargo - end - - --- - -- @param #SET_CARGO self - function SET_CARGO:FirstCargoWithStateAndNotDeployed(State) - - local FirstCargo = nil - - for CargoName, Cargo in pairs(self.Set) do - if Cargo:Is(State) and not Cargo:IsDeployed() then - FirstCargo = Cargo - break - end - end - - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoUnLoaded() - local FirstCargo = self:FirstCargoWithState("UnLoaded") - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is UnLoaded and not Deployed. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoUnLoadedAndNotDeployed() - local FirstCargo = self:FirstCargoWithStateAndNotDeployed("UnLoaded") - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Loaded. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoLoaded() - local FirstCargo = self:FirstCargoWithState("Loaded") - return FirstCargo - end - - --- Iterate the SET_CARGO while identifying the first @{Cargo.Cargo#CARGO} that is Deployed. - -- @param #SET_CARGO self - -- @return Cargo.Cargo#CARGO The first @{Cargo.Cargo#CARGO}. - function SET_CARGO:FirstCargoDeployed() - local FirstCargo = self:FirstCargoWithState("Deployed") - return FirstCargo - end - - --- - -- @param #SET_CARGO self - -- @param AI.AI_Cargo#AI_CARGO MCargo - -- @return #SET_CARGO self - function SET_CARGO:IsIncludeObject(MCargo) -- R2.1 - --self:F2(MCargo) - - local MCargoInclude = true - - if MCargo then - local MCargoName = MCargo:GetName() - - if self.Filter.Coalitions then - local MCargoCoalition = false - for CoalitionID, CoalitionName in pairs(self.Filter.Coalitions) do - local CargoCoalitionID = MCargo:GetCoalition() - --self:T(3({ "Coalition:", CargoCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName }) - if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == CargoCoalitionID then - MCargoCoalition = true - end - end - --self:F({ "Evaluated Coalition", MCargoCoalition }) - MCargoInclude = MCargoInclude and MCargoCoalition - end - - if self.Filter.Types then - local MCargoType = false - for TypeID, TypeName in pairs(self.Filter.Types) do - --self:T(3({ "Type:", MCargo:GetType(), TypeName }) - if TypeName == MCargo:GetType() then - MCargoType = true - end - end - --self:F({ "Evaluated Type", MCargoType }) - MCargoInclude = MCargoInclude and MCargoType - end - - if self.Filter.CargoPrefixes then - local MCargoPrefix = false - for CargoPrefixId, CargoPrefix in pairs(self.Filter.CargoPrefixes) do - --self:T(3({ "Prefix:", string.find(MCargo.Name, CargoPrefix, 1), CargoPrefix }) - if string.find(MCargo.Name, CargoPrefix, 1) then - MCargoPrefix = true - end - end - --self:F({ "Evaluated Prefix", MCargoPrefix }) - MCargoInclude = MCargoInclude and MCargoPrefix - end - end - - if self.Filter.Functions and MCargoInclude then - local MClientFunc = self:_EvalFilterFunctions(MCargo) - MCargoInclude = MCargoInclude and MClientFunc - end - - --self:T(2(MCargoInclude) - return MCargoInclude - end - - --- Handles the OnEventNewCargo event for the Set. - -- @param #SET_CARGO self - -- @param Core.Event#EVENTDATA EventData - function SET_CARGO:OnEventNewCargo(EventData) -- R2.1 - - --self:F({ "New Cargo", EventData }) - - if EventData.Cargo then - if EventData.Cargo and self:IsIncludeObject(EventData.Cargo) then - self:Add(EventData.Cargo.Name, EventData.Cargo) - end - end - end - - --- Handles the OnDead or OnCrash event for alive units set. - -- @param #SET_CARGO self - -- @param Core.Event#EVENTDATA EventData - function SET_CARGO:OnEventDeleteCargo(EventData) -- R2.1 - --self:F3({ EventData }) - - if EventData.Cargo then - local Cargo = _DATABASE:FindCargo(EventData.Cargo.Name) - if Cargo and Cargo.Name then - - -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. - -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. - -- And this is a problem because it will remove all entries from the SET_CARGOs. - -- To prevent this from happening, the Cargo object has a flag NoDestroy. - -- When true, the SET_CARGO won't Remove the Cargo object from the set. - -- This flag is switched off after the event handlers have been called in the EVENT class. - --self:F({ CargoNoDestroy = Cargo.NoDestroy }) - if Cargo.NoDestroy then - else - self:Remove(Cargo.Name) - end - end - end - end - -end - do -- SET_ZONE --- @@ -6547,14 +6121,6 @@ do -- SET_ZONE if EventData.Zone then local Zone = _DATABASE:FindZone(EventData.Zone.ZoneName) if Zone and Zone.ZoneName then - - -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. - -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. - -- And this is a problem because it will remove all entries from the SET_ZONEs. - -- To prevent this from happening, the Zone object has a flag NoDestroy. - -- When true, the SET_ZONE won't Remove the Zone object from the set. - -- This flag is switched off after the event handlers have been called in the EVENT class. - --self:F({ ZoneNoDestroy = Zone.NoDestroy }) if Zone.NoDestroy then else self:Remove(Zone.ZoneName) @@ -7069,14 +6635,6 @@ do -- SET_ZONE_GOAL if EventData.ZoneGoal then local Zone = _DATABASE:FindZone(EventData.ZoneGoal.ZoneName) if Zone and Zone.ZoneName then - - -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. - -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. - -- And this is a problem because it will remove all entries from the SET_ZONE_GOALs. - -- To prevent this from happening, the Zone object has a flag NoDestroy. - -- When true, the SET_ZONE_GOAL won't Remove the Zone object from the set. - -- This flag is switched off after the event handlers have been called in the EVENT class. - --self:F({ ZoneNoDestroy = Zone.NoDestroy }) if Zone.NoDestroy then else self:Remove(Zone.ZoneName) @@ -7465,14 +7023,6 @@ do -- SET_OPSZONE if EventData.ZoneGoal then local Zone = _DATABASE:FindZone(EventData.ZoneGoal.ZoneName) if Zone and Zone.ZoneName then - - -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. - -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. - -- And this is a problem because it will remove all entries from the SET_OPSZONEs. - -- To prevent this from happening, the Zone object has a flag NoDestroy. - -- When true, the SET_OPSZONE won't Remove the Zone object from the set. - -- This flag is switched off after the event handlers have been called in the EVENT class. - --self:F({ ZoneNoDestroy = Zone.NoDestroy }) if Zone.NoDestroy then else self:Remove(Zone.ZoneName) diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 669fde4e0..9e68aafa6 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -511,24 +511,6 @@ -- -- Start ARTY process. -- normandy:Start() -- --- ### Transportation as Cargo --- This example demonstates how an ARTY group can be transported to another location as cargo. --- -- Define a group as CARGO_GROUP --- CargoGroupMortars=CARGO_GROUP:New(GROUP:FindByName("Mortars"), "Mortars", "Mortar Platoon Alpha", 100 , 10) --- --- -- Define the mortar CARGO GROUP as ARTY object --- mortars=ARTY:NewFromCargoGroup(CargoGroupMortars, "Mortar Platoon Alpha") --- --- -- Start ARTY process --- mortars:Start() --- --- -- Setup AI cargo dispatcher for e.g. helos --- SetHeloCarriers = SET_GROUP:New():FilterPrefixes("CH-47D"):FilterStart() --- SetCargoMortars = SET_CARGO:New():FilterTypes("Mortars"):FilterStart() --- SetZoneDepoly = SET_ZONE:New():FilterPrefixes("Deploy"):FilterStart() --- CargoHelo=AI_CARGO_DISPATCHER_HELICOPTER:New(SetHeloCarriers, SetCargoMortars, SetZoneDepoly) --- CargoHelo:Start() --- The ARTY group will be transported and resume its normal operation after it has been deployed. New targets can be assigned at any time also during the transportation process. -- -- @field #ARTY ARTY={ @@ -1230,37 +1212,6 @@ function ARTY:New(group, alias) return self end ---- Creates a new ARTY object from a MOOSE CARGO_GROUP object. --- @param #ARTY self --- @param Cargo.CargoGroup#CARGO_GROUP cargogroup The CARGO GROUP object for which artillery tasks should be assigned. --- @param alias (Optional) Alias name the group will be calling itself when sending messages. Default is the group name. --- @return #ARTY ARTY object or nil if group does not exist or is not a ground or naval group. -function ARTY:NewFromCargoGroup(cargogroup, alias) - - if cargogroup then - BASE:T(string.format("ARTY script version %s. Added CARGO group %s.", ARTY.version, cargogroup:GetName())) - else - BASE:E("ERROR: Requested ARTY CARGO GROUP does not exist! (Has to be a MOOSE CARGO(!) group.)") - return nil - end - - -- Get group belonging to the cargo group. - local group=cargogroup:GetObject() - - -- Create ARTY object. - local arty=ARTY:New(group,alias) - - -- Set iscargo flag. - arty.iscargo=true - - -- Set cargo group object. - arty.cargogroup=cargogroup - - return arty -end - - - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- User Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Functional/ZoneGoalCargo.lua b/Moose Development/Moose/Functional/ZoneGoalCargo.lua deleted file mode 100644 index 10b91e12f..000000000 --- a/Moose Development/Moose/Functional/ZoneGoalCargo.lua +++ /dev/null @@ -1,458 +0,0 @@ ---- **Functional** - Base class that models processes to achieve goals involving a Zone and Cargo. --- --- === --- --- ZONE_GOAL_CARGO models processes that have a Goal with a defined achievement involving a Zone and Cargo. --- Derived classes implement the ways how the achievements can be realized. --- --- # Developer Note --- --- ![Banner Image](..\Images\deprecated.png) --- --- Note while this class still works, it is no longer supported as the original author stopped active development of MOOSE --- Therefore, this class is considered to be deprecated --- --- === --- --- ### Author: **FlightControl** --- --- === --- --- @module Functional.ZoneGoalCargo --- @image MOOSE.JPG - -do -- ZoneGoal - - -- @type ZONE_GOAL_CARGO - -- @extends Functional.ZoneGoal#ZONE_GOAL - - - --- Models processes that have a Goal with a defined achievement involving a Zone and Cargo. - -- Derived classes implement the ways how the achievements can be realized. - -- - -- ## 1. ZONE_GOAL_CARGO constructor - -- - -- * @{#ZONE_GOAL_CARGO.New}(): Creates a new ZONE_GOAL_CARGO object. - -- - -- ## 2. ZONE_GOAL_CARGO is a finite state machine (FSM). - -- - -- ### 2.1 ZONE_GOAL_CARGO States - -- - -- * **Deployed**: The Zone has been captured by an other coalition. - -- * **Airborne**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone. - -- * **Loaded**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone. - -- * **Empty**: The Zone is empty. There is not valid unit in the Zone. - -- - -- ### 2.2 ZONE_GOAL_CARGO Events - -- - -- * **Capture**: The Zone has been captured by an other coalition. - -- * **Attack**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone. - -- * **Guard**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone. - -- * **Empty**: The Zone is empty. There is not valid unit in the Zone. - -- - -- ### 2.3 ZONE_GOAL_CARGO State Machine - -- - -- @field #ZONE_GOAL_CARGO - ZONE_GOAL_CARGO = { - ClassName = "ZONE_GOAL_CARGO", - } - - -- @field #table ZONE_GOAL_CARGO.States - ZONE_GOAL_CARGO.States = {} - - --- ZONE_GOAL_CARGO Constructor. - -- @param #ZONE_GOAL_CARGO self - -- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved. - -- @param #number Coalition The initial coalition owning the zone. - -- @return #ZONE_GOAL_CARGO - function ZONE_GOAL_CARGO:New( Zone, Coalition ) - - local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_CARGO - self:F( { Zone = Zone, Coalition = Coalition } ) - - self:SetCoalition( Coalition ) - - do - - --- Captured State Handler OnLeave for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnLeaveCaptured - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Captured State Handler OnEnter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnEnterCaptured - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - end - - - do - - --- Attacked State Handler OnLeave for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnLeaveAttacked - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Attacked State Handler OnEnter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnEnterAttacked - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - end - - do - - --- Guarded State Handler OnLeave for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnLeaveGuarded - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Guarded State Handler OnEnter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnEnterGuarded - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - end - - - do - - --- Empty State Handler OnLeave for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnLeaveEmpty - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Empty State Handler OnEnter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnEnterEmpty - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - end - - self:AddTransition( "*", "Guard", "Guarded" ) - - --- Guard Handler OnBefore for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnBeforeGuard - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Guard Handler OnAfter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnAfterGuard - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - --- Guard Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] Guard - -- @param #ZONE_GOAL_CARGO self - - --- Guard Asynchronous Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] __Guard - -- @param #ZONE_GOAL_CARGO self - -- @param #number Delay - - self:AddTransition( "*", "Empty", "Empty" ) - - --- Empty Handler OnBefore for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnBeforeEmpty - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Empty Handler OnAfter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnAfterEmpty - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - --- Empty Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] Empty - -- @param #ZONE_GOAL_CARGO self - - --- Empty Asynchronous Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] __Empty - -- @param #ZONE_GOAL_CARGO self - -- @param #number Delay - - - self:AddTransition( { "Guarded", "Empty" }, "Attack", "Attacked" ) - - --- Attack Handler OnBefore for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnBeforeAttack - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Attack Handler OnAfter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnAfterAttack - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - --- Attack Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] Attack - -- @param #ZONE_GOAL_CARGO self - - --- Attack Asynchronous Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] __Attack - -- @param #ZONE_GOAL_CARGO self - -- @param #number Delay - - self:AddTransition( { "Guarded", "Attacked", "Empty" }, "Capture", "Captured" ) - - --- Capture Handler OnBefore for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnBeforeCapture - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - -- @return #boolean - - --- Capture Handler OnAfter for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] OnAfterCapture - -- @param #ZONE_GOAL_CARGO self - -- @param #string From - -- @param #string Event - -- @param #string To - - --- Capture Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] Capture - -- @param #ZONE_GOAL_CARGO self - - --- Capture Asynchronous Trigger for ZONE_GOAL_CARGO - -- @function [parent=#ZONE_GOAL_CARGO] __Capture - -- @param #ZONE_GOAL_CARGO self - -- @param #number Delay - - return self - end - - - --- Set the owning coalition of the zone. - -- @param #ZONE_GOAL_CARGO self - -- @param #number Coalition - function ZONE_GOAL_CARGO:SetCoalition( Coalition ) - self.Coalition = Coalition - end - - - --- Get the owning coalition of the zone. - -- @param #ZONE_GOAL_CARGO self - -- @return #number Coalition. - function ZONE_GOAL_CARGO:GetCoalition() - return self.Coalition - end - - - --- Get the owning coalition name of the zone. - -- @param #ZONE_GOAL_CARGO self - -- @return #string Coalition name. - function ZONE_GOAL_CARGO:GetCoalitionName() - - if self.Coalition == coalition.side.BLUE then - return "Blue" - end - - if self.Coalition == coalition.side.RED then - return "Red" - end - - if self.Coalition == coalition.side.NEUTRAL then - return "Neutral" - end - - return "" - end - - - function ZONE_GOAL_CARGO:IsGuarded() - - local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition ) - self:F( { IsGuarded = IsGuarded } ) - return IsGuarded - end - - - function ZONE_GOAL_CARGO:IsEmpty() - - local IsEmpty = self.Zone:IsNoneInZone() - self:F( { IsEmpty = IsEmpty } ) - return IsEmpty - end - - - function ZONE_GOAL_CARGO:IsCaptured() - - local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition ) - self:F( { IsCaptured = IsCaptured } ) - return IsCaptured - end - - - function ZONE_GOAL_CARGO:IsAttacked() - - local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition ) - self:F( { IsAttacked = IsAttacked } ) - return IsAttacked - end - - - - --- Mark. - -- @param #ZONE_GOAL_CARGO self - function ZONE_GOAL_CARGO:Mark() - - local Coord = self.Zone:GetCoordinate() - local ZoneName = self:GetZoneName() - local State = self:GetState() - - if self.MarkRed and self.MarkBlue then - self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } ) - Coord:RemoveMark( self.MarkRed ) - Coord:RemoveMark( self.MarkBlue ) - end - - if self.Coalition == coalition.side.BLUE then - self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State ) - self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State ) - else - self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State ) - self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State ) - end - end - - --- Bound. - -- @param #ZONE_GOAL_CARGO self - function ZONE_GOAL_CARGO:onenterGuarded() - - --self:GetParent( self ):onenterGuarded() - - if self.Coalition == coalition.side.BLUE then - --elf.ProtectZone:BoundZone( 12, country.id.USA ) - else - --self.ProtectZone:BoundZone( 12, country.id.RUSSIA ) - end - - self:Mark() - - end - - function ZONE_GOAL_CARGO:onenterCaptured() - - --self:GetParent( self ):onenterCaptured() - - local NewCoalition = self.Zone:GetCoalition() - self:F( { NewCoalition = NewCoalition } ) - self:SetCoalition( NewCoalition ) - - self:Mark() - end - - - function ZONE_GOAL_CARGO:onenterEmpty() - - --self:GetParent( self ):onenterEmpty() - - self:Mark() - end - - - function ZONE_GOAL_CARGO:onenterAttacked() - - --self:GetParent( self ):onenterAttacked() - - self:Mark() - end - - - --- When started, check the Coalition status. - -- @param #ZONE_GOAL_CARGO self - function ZONE_GOAL_CARGO:onafterGuard() - - --self:F({BASE:GetParent( self )}) - --BASE:GetParent( self ).onafterGuard( self ) - - if not self.SmokeScheduler then - self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self ) - end - if not self.ScheduleStatusZone then - self.ScheduleStatusZone = self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self ) - end - end - - - function ZONE_GOAL_CARGO:IsCaptured() - - local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition ) - self:F( { IsCaptured = IsCaptured } ) - return IsCaptured - end - - - function ZONE_GOAL_CARGO:IsAttacked() - - local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition ) - self:F( { IsAttacked = IsAttacked } ) - return IsAttacked - end - - --- Check status Coalition ownership. - -- @param #ZONE_GOAL_CARGO self - function ZONE_GOAL_CARGO:StatusZone() - - local State = self:GetState() - self:F( { State = self:GetState() } ) - - self.Zone:Scan() - - if State ~= "Guarded" and self:IsGuarded() then - self:Guard() - end - - if State ~= "Empty" and self:IsEmpty() then - self:Empty() - end - - if State ~= "Attacked" and self:IsAttacked() then - self:Attack() - end - - if State ~= "Captured" and self:IsCaptured() then - self:Capture() - end - - end - -end - diff --git a/Moose Development/Moose/Globals.lua b/Moose Development/Moose/Globals.lua index 5108254d1..d5f7ef941 100644 --- a/Moose Development/Moose/Globals.lua +++ b/Moose Development/Moose/Globals.lua @@ -13,9 +13,6 @@ _DATABASE = DATABASE:New() -- Core.Database#DATABASE _SETTINGS = SETTINGS:Set() -- Core.Settings#SETTINGS _SETTINGS:SetPlayerMenuOn() ---- Register cargos. -_DATABASE:_RegisterCargos() - --- Register zones. _DATABASE:_RegisterZones() _DATABASE:_RegisterAirbases() diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index b6ff32ab9..489d0421a 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -50,11 +50,6 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Net.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/Storage.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Wrapper/DynamicCargo.lua' ) -__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Cargo/Cargo.lua' ) -__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Cargo/CargoUnit.lua' ) -__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Cargo/CargoSlingload.lua' ) -__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Cargo/CargoCrate.lua' ) -__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Cargo/CargoGroup.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Scoring.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/CleanUp.lua' ) @@ -80,7 +75,6 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Shorad.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/AICSAR.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/AmmoTruck.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Autolase.lua' ) -__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/ZoneGoalCargo.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Tiresias.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/Stratego.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Functional/ClientWatch.lua') diff --git a/Moose Development/Moose/Wrapper/Client.lua b/Moose Development/Moose/Wrapper/Client.lua index d39f0bb30..cb1a18225 100644 --- a/Moose Development/Moose/Wrapper/Client.lua +++ b/Moose Development/Moose/Wrapper/Client.lua @@ -148,7 +148,7 @@ function CLIENT:FindByName( ClientName, ClientBriefing, Error ) end end ---- Transport defines that the Client is a Transport. Transports show cargo. +--- Register a client. -- @param #CLIENT self -- @param #string ClientName Name of the client unit. -- @return #CLIENT self @@ -507,37 +507,6 @@ function CLIENT:GetClientGroupDCSUnit() end end - ---- Evaluates if the CLIENT is a transport. --- @param #CLIENT self --- @return #boolean true is a transport. -function CLIENT:IsTransport() - self:F() - return self.ClientTransport -end - ---- Shows the @{AI.AI_Cargo#CARGO} contained within the CLIENT to the player as a message. --- The @{AI.AI_Cargo#CARGO} is shown using the @{Core.Message#MESSAGE} distribution system. --- @param #CLIENT self -function CLIENT:ShowCargo() - self:F() - - local CargoMsg = "" - - for CargoName, Cargo in pairs( CARGOS ) do - if self == Cargo:IsLoadedInClient() then - CargoMsg = CargoMsg .. Cargo.CargoName .. " Type:" .. Cargo.CargoType .. " Weight: " .. Cargo.CargoWeight .. "\n" - end - end - - if CargoMsg == "" then - CargoMsg = "empty" - end - - self:Message( CargoMsg, 15, "Co-Pilot: Cargo Status", 30 ) - -end - --- The main message driver for the CLIENT. -- This function displays various messages to the Player logged into the CLIENT through the DCS World Messaging system. -- @param #CLIENT self