From 6955d4584073fb93369fd20cb652ce6d88b3c4e1 Mon Sep 17 00:00:00 2001 From: svenvandevelde Date: Thu, 25 Feb 2016 14:52:16 +0100 Subject: [PATCH] Lots of fixes for cargo + optimization of Stage Messages --- Moose/Base.lua | 15 +- Moose/Cargo.lua | 258 +++++++++++++------------- Moose/Client.lua | 70 ++++--- Moose/DeployTask.lua | 33 ++-- Moose/Group.lua | 68 +++++++ Moose/Mission.lua | 7 +- Moose/PickupTask.lua | 48 ++--- Moose/Routines.lua | 90 +++++---- Moose/Spawn.lua | 69 ++++++- Moose/Stage.lua | 271 +++++++++------------------- Test Missions/MOOSE_Pickup_Test.lua | 126 +++++++++++++ Test Missions/MOOSE_Pickup_Test.miz | Bin 0 -> 27262 bytes Test Missions/MOOSE_Spawn_Test.lua | 15 ++ Test Missions/MOOSE_Spawn_Test.miz | Bin 0 -> 19439 bytes 14 files changed, 640 insertions(+), 430 deletions(-) create mode 100644 Test Missions/MOOSE_Pickup_Test.lua create mode 100644 Test Missions/MOOSE_Pickup_Test.miz create mode 100644 Test Missions/MOOSE_Spawn_Test.lua create mode 100644 Test Missions/MOOSE_Spawn_Test.miz diff --git a/Moose/Base.lua b/Moose/Base.lua index dc4029ff0..77724a7a1 100644 --- a/Moose/Base.lua +++ b/Moose/Base.lua @@ -156,9 +156,20 @@ trace.f( self.ClassName, { EventTime, Initiator, IniUnitName, place, subplace } subplace = subplace } - world.onEvent( Event ) + world.onEvent( Event ) end +function BASE:CreateEventCrash( EventTime, Initiator ) +trace.f( self.ClassName, { EventTime, Initiator } ) + + local Event = { + id = world.event.S_EVENT_CRASH, + time = EventTime, + initiator = Initiator, + } + + world.onEvent( Event ) +end function BASE:onEvent(event) --trace.f(self.ClassName, event ) @@ -204,6 +215,6 @@ function BASE:T( Arguments ) local Line = DebugInfo.currentline - env.info( string.format( "%6d/%1s:%20s.%s\(%s\)" , Line, "T", self.ClassName, Function .. routines.utils.oneLineSerialize( Arguments ) ) ) + env.info( string.format( "%6d/%1s:%20s.%s\(%s\)" , Line, "T", self.ClassName, Function, routines.utils.oneLineSerialize( Arguments ) ) ) end end diff --git a/Moose/Cargo.lua b/Moose/Cargo.lua index d302f8f98..d113e70b1 100644 --- a/Moose/Cargo.lua +++ b/Moose/Cargo.lua @@ -31,24 +31,25 @@ CARGO_ZONE = { } } -function CARGO_ZONE:New( CargoZoneName, CargoHostName ) -trace.f( self.ClassName, { CargoZoneName, CargoHostName } ) - - local self = BASE:Inherit( self, BASE:New() ) +function CARGO_ZONE:New( CargoZoneName, CargoHostName ) local self = BASE:Inherit( self, BASE:New() ) +self:T( { CargoZoneName, CargoHostName } ) self.CargoZoneName = CargoZoneName self.CargoZone = trigger.misc.getZone( CargoZoneName ) + if CargoHostName then self.CargoHostName = CargoHostName self.CargoHostSpawn = SPAWN:New( CargoHostName ) end + + self:T( self.CargoZone ) return self end function CARGO_ZONE:Spawn() -trace.f( self.ClassName, CargoHostSpawn ) +self:T( CargoHostSpawn ) if self.CargoHostSpawn then local CargoHostGroup = Group.getByName( self.CargoHostSpawn:SpawnGroupName() ) @@ -84,7 +85,7 @@ function CARGO_ZONE:GetHostUnit() end function CARGO_ZONE:ReportCargosToClient( Client, CargoType ) -trace.f( self.ClassName ) +self:T() local SignalUnit = self:GetHostUnit() @@ -95,23 +96,25 @@ trace.f( self.ClassName ) local HostMessage = "" local IsCargo = false - for CargoID, Cargo in pairs( Cargos ) do + for CargoID, Cargo in pairs( CARGOS ) do if Cargo.CargoType == Task.CargoType then - HostMessage = HostMessage .. "\n - " .. Cargo.CargoName - IsCargo = true + if Cargo:IsStatusNone() then + HostMessage = HostMessage .. " - " .. Cargo.CargoName .. " - " .. Cargo.CargoType .. " (" .. Cargo.Weight .. "kg)" .. "\n" + IsCargo = true + end end end if not IsCargo then - HostMessage = HostMessage .. "No Cargo Available." + HostMessage = "No Cargo Available." end - Client:Message( RouteMessage, self.MSG.TIME, Mission.Name .. "/StageHosts." .. SignalUnitTypeName, SignalUnitTypeName .. ": Reporting Cargo", 10 ) + Client:Message( HostMessage, 20, Mission.Name .. "/StageHosts." .. SignalUnitTypeName, SignalUnitTypeName .. ": Reporting Cargo", 10 ) end end function CARGO_ZONE:Signal() -trace.f( self.ClassName ) +self:T() local Signalled = false @@ -125,7 +128,7 @@ trace.f( self.ClassName ) if SignalUnit then - trace.i( self.ClassName, 'Signalling Unit' ) + self:T( 'Signalling Unit' ) local SignalVehiclePos = SignalUnit:getPosition().p SignalVehiclePos.y = SignalVehiclePos.y + 2 @@ -165,7 +168,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:WhiteSmoke() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.WHITE @@ -174,7 +177,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:BlueSmoke() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.BLUE @@ -183,7 +186,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:RedSmoke() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.RED @@ -192,7 +195,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:OrangeSmoke() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.ORANGE @@ -201,7 +204,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:GreenSmoke() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.SMOKE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.GREEN @@ -211,7 +214,7 @@ end function CARGO_ZONE:WhiteFlare() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.WHITE @@ -220,7 +223,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:RedFlare() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.RED @@ -229,7 +232,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:GreenFlare() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.GREEN @@ -238,7 +241,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:YellowFlare() -trace.f( self.ClassName ) +self:T() self.SignalType = CARGO_ZONE.SIGNAL.TYPE.FLARE self.SignalColor = CARGO_ZONE.SIGNAL.COLOR.YELLOW @@ -248,7 +251,7 @@ end function CARGO_ZONE:GetCargoHostUnit() -trace.f( self.ClassName ) +self:T() local CargoHostUnit = Group.getByName( self.CargoHostSpawn:SpawnGroupName() ):getUnit(1) if CargoHostUnit and CargoHostUnit:isExist() then @@ -259,7 +262,7 @@ trace.f( self.ClassName ) end function CARGO_ZONE:GetCargoZoneName() -trace.f( self.ClassName ) +self:T() return self.CargoZoneName end @@ -276,10 +279,9 @@ CARGO = { } --- Add Cargo to the mission... Cargo functionality needs to be reworked a bit, so this is still under construction. I need to make a CARGO Class... -function CARGO:New( CargoType, CargoName, CargoWeight ) -trace.f( self.ClassName, { CargoType, CargoName, CargoWeight } ) +function CARGO:New( CargoType, CargoName, CargoWeight ) local self = BASE:Inherit( self, BASE:New() ) +self:T( { CargoType, CargoName, CargoWeight } ) - local self = BASE:Inherit( self, BASE:New() ) self.CargoType = CargoType self.CargoName = CargoName @@ -291,14 +293,14 @@ trace.f( self.ClassName, { CargoType, CargoName, CargoWeight } ) end function CARGO:Spawn() -trace.f( self.ClassName ) +self:T() return self end function CARGO:IsNear( Client, LandingZone ) -trace.f( self.ClassName ) +self:T() local Near = true @@ -307,7 +309,7 @@ trace.f( self.ClassName ) end function CARGO:IsLoadedInClient() -trace.f( self.ClassName ) +self:T() if self:IsStatusLoaded() or self:IsStatusLoading() then return self.CargoClient @@ -319,7 +321,7 @@ end function CARGO:UnLoad( Client, TargetZoneName ) -trace.f( self.ClassName ) +self:T() self:StatusUnLoaded() @@ -327,7 +329,7 @@ trace.f( self.ClassName ) end function CARGO:OnBoard( Client, LandingZone ) -trace.f(self.ClassName ) +self:T() local Valid = true @@ -338,7 +340,7 @@ trace.f(self.ClassName ) end function CARGO:OnBoarded( Client, LandingZone ) -trace.f(self.ClassName ) +self:T() local OnBoarded = true @@ -346,7 +348,7 @@ trace.f(self.ClassName ) end function CARGO:Load( Client ) -trace.f( self.ClassName ) +self:T() self:StatusLoaded( Client ) @@ -354,18 +356,18 @@ trace.f( self.ClassName ) end function CARGO:IsLandingRequired() -trace.f( self.ClassName ) +self:T() return true end function CARGO:IsSlingLoad() -trace.f( self.ClassName ) +self:T() return false end function CARGO:StatusNone() -trace.f(self.ClassName ) +self:T() self.CargoClient = nil self.CargoStatus = CARGO.STATUS.NONE @@ -374,16 +376,17 @@ trace.f(self.ClassName ) end function CARGO:StatusLoading( Client ) -trace.f(self.ClassName ) +self:T() self.CargoClient = Client self.CargoStatus = CARGO.STATUS.LOADING + self:T( "Cargo loaded in Client: " .. CargoClient:GetClientGroupName() ) return self end function CARGO:StatusLoaded( Client ) -trace.f(self.ClassName ) +self:T() self.CargoClient = Client self.CargoStatus = CARGO.STATUS.LOADED @@ -392,7 +395,7 @@ trace.f(self.ClassName ) end function CARGO:StatusUnLoaded() -trace.f(self.ClassName ) +self:T() self.CargoClient = nil self.CargoStatus = CARGO.STATUS.UNLOADED @@ -402,25 +405,25 @@ end function CARGO:IsStatusNone() -trace.f(self.ClassName ) +self:T() return self.CargoStatus == CARGO.STATUS.NONE end function CARGO:IsStatusLoading() -trace.f(self.ClassName ) +self:T() return self.CargoStatus == CARGO.STATUS.LOADING end function CARGO:IsStatusLoaded() -trace.f(self.ClassName ) +self:T() return self.CargoStatus == CARGO.STATUS.LOADED end function CARGO:IsStatusUnLoaded() -trace.f(self.ClassName ) +self:T() return self.CargoStatus == CARGO.STATUS.UNLOADED end @@ -431,12 +434,9 @@ CARGO_GROUP = { } -function CARGO_GROUP:New( CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone ) -trace.f( self.ClassName, { CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone } ) +function CARGO_GROUP:New( CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) +self:T( { CargoType, CargoName, CargoWeight, CargoGroupTemplate, CargoZone } ) - -- Arrange meta tables - local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - self.CargoSpawn = SPAWN:New( CargoGroupTemplate ) self.CargoZone = CargoZone @@ -447,7 +447,7 @@ trace.f( self.ClassName, { CargoType, CargoName, CargoWeight, CargoGroupTemplate end function CARGO_GROUP:Spawn() -trace.f( self.ClassName ) +self:T() local SpawnCargo = true @@ -477,13 +477,13 @@ trace.f( self.ClassName ) self:StatusNone() end - trace.i( self.ClassName, { self.CargoGroupName, CARGOS[self.CargoName].CargoGroupName } ) + self:T( { self.CargoGroupName, CARGOS[self.CargoName].CargoGroupName } ) return self end function CARGO_GROUP:IsNear( Client, LandingZone ) -trace.f( self.ClassName ) +self:T() local Near = false @@ -498,8 +498,9 @@ trace.f( self.ClassName ) end + function CARGO_GROUP:OnBoard( Client, LandingZone, OnBoardSide ) -trace.f(self.ClassName ) +self:T() local Valid = true @@ -517,12 +518,12 @@ trace.f(self.ClassName ) local Points = {} - trace.i( self.ClassName, 'CargoPos x = ' .. CargoPos.x .. " z = " .. CargoPos.z ) - trace.i( self.ClassName, 'CarrierPosMove x = ' .. CarrierPosMove.x .. " z = " .. CarrierPosMove.z ) + self:T( 'CargoPos x = ' .. CargoPos.x .. " z = " .. CargoPos.z ) + self:T( 'CarrierPosMove x = ' .. CarrierPosMove.x .. " z = " .. CarrierPosMove.z ) Points[#Points+1] = routines.ground.buildWP( CargoPos, "Cone", 10 ) - trace.i( self.ClassName, 'Points[1] x = ' .. Points[1].x .. " y = " .. Points[1].y ) + self:T( 'Points[1] x = ' .. Points[1].x .. " y = " .. Points[1].y ) if OnBoardSide == nil then OnBoardSide = CLIENT.ONBOARDSIDE.NONE @@ -530,7 +531,7 @@ trace.f(self.ClassName ) if OnBoardSide == CLIENT.ONBOARDSIDE.LEFT then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding LEFT" ) + self:T( "TransportCargoOnBoard: Onboarding LEFT" ) CarrierPosMove.z = CarrierPosMove.z - 25 CarrierPosOnBoard.z = CarrierPosOnBoard.z - 5 Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "Cone", 10 ) @@ -538,7 +539,7 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.RIGHT then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding RIGHT" ) + self:T( "TransportCargoOnBoard: Onboarding RIGHT" ) CarrierPosMove.z = CarrierPosMove.z + 25 CarrierPosOnBoard.z = CarrierPosOnBoard.z + 5 Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "Cone", 10 ) @@ -546,7 +547,7 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.BACK then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding BACK" ) + self:T( "TransportCargoOnBoard: Onboarding BACK" ) CarrierPosMove.x = CarrierPosMove.x - 25 CarrierPosOnBoard.x = CarrierPosOnBoard.x - 5 Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "Cone", 10 ) @@ -554,7 +555,7 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.FRONT then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding FRONT" ) + self:T( "TransportCargoOnBoard: Onboarding FRONT" ) CarrierPosMove.x = CarrierPosMove.x + 25 CarrierPosOnBoard.x = CarrierPosOnBoard.x + 5 Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "Cone", 10 ) @@ -562,11 +563,11 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.NONE then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding CENTRAL" ) + self:T( "TransportCargoOnBoard: Onboarding CENTRAL" ) Points[#Points+1] = routines.ground.buildWP( CarrierPos, "Cone", 10 ) end - trace.i( self.ClassName, "TransportCargoOnBoard: Routing " .. self.CargoGroupName ) + self:T( "TransportCargoOnBoard: Routing " .. self.CargoGroupName ) routines.scheduleFunction( routines.goRoute, { self.CargoGroupName, Points}, timer.getTime() + 4 ) @@ -578,7 +579,7 @@ end function CARGO_GROUP:OnBoarded( Client, LandingZone ) -trace.f(self.ClassName ) +self:T() local OnBoarded = false @@ -592,11 +593,12 @@ trace.f(self.ClassName ) return OnBoarded end -function CARGO_GROUP:UnLoad( Client, TargetZoneName ) -trace.f( self.ClassName ) - trace.i( self.ClassName, 'self.CargoName = ' .. self.CargoName ) - trace.i( self.ClassName, 'self.CargoGroupName = ' .. self.CargoGroupName ) +function CARGO_GROUP:UnLoad( Client, TargetZoneName ) +self:T() + + self:T( 'self.CargoName = ' .. self.CargoName ) + self:T( 'self.CargoGroupName = ' .. self.CargoGroupName ) self.CargoSpawn:FromCarrier( Client:GetClientGroupUnit(), TargetZoneName, self.CargoGroupName ) @@ -611,18 +613,11 @@ CARGO_PACKAGE = { } -function CARGO_PACKAGE:New( CargoType, CargoName, CargoWeight, CargoClientInitGroupName ) -trace.f( self.ClassName, { CargoType, CargoName, CargoWeight, CargoClientInitGroupName } ) +function CARGO_PACKAGE:New( CargoType, CargoName, CargoWeight, CargoClient ) local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - -- Arrange meta tables - local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) - - self.CargoClientInitGroupName = CargoClientInitGroupName - - self.CargoClient = CLIENT:New( self.CargoClientInitGroupName ) - self:StatusLoaded( self.CargoClient ) - - self.CargoClientInitGroupSpawn = SPAWN:New( self.CargoClientInitGroupName ) + self:T( { CargoType, CargoName, CargoWeight, CargoClient.ClientName } ) + + self.CargoClient = CargoClient CARGOS[self.CargoName] = self @@ -630,21 +625,28 @@ trace.f( self.ClassName, { CargoType, CargoName, CargoWeight, CargoClientInitGro end + function CARGO_PACKAGE:Spawn() -trace.f( self.ClassName ) +self:T() -- this needs to be checked thoroughly + local CargoClientInitGroup = self.CargoClient:ClientGroup() + if not CargoClientInitGroup then + if not self.CargoClientInitGroupSpawn then + self.CargoClientInitGroupSpawn = SPAWN:New( self.CargoClient:GetClientGroupName() ) + end + self.CargoClientInitGroupSpawn:Spawn( self.CargoClient:GetClientGroupName() ) + end + local SpawnCargo = true - trace.i( self.ClassName, self.CargoClientInitGroupName ) - if self:IsStatusNone() then elseif self:IsStatusLoading() or self:IsStatusLoaded() then - local Client = self:IsLoadedInClient() - if Client and Client:ClientGroup() then + local CargoClientLoaded = self:IsLoadedInClient() + if CargoClientLoaded and CargoClientLoaded:ClientGroup() then SpawnCargo = false end @@ -657,26 +659,21 @@ trace.f( self.ClassName ) end if SpawnCargo then - self.CargoClient = CLIENT:New( self.CargoClientInitGroupName ) self:StatusLoaded( self.CargoClient ) end - - local CargoClientInitGroup = Group.getByName( self.CargoClientInitGroupName ) - if CargoClientInitGroup then - self.CargoClientInitGroupSpawn:Spawn( self.CargoClientInitGroupName ) - end - + return self end + function CARGO_PACKAGE:IsNear( Client, LandingZone ) -trace.f( self.ClassName ) +self:T() local Near = false if self.CargoClient and self.CargoClient:ClientGroup() then - trace.i( self.ClassName, self.CargoClient.ClientName ) - trace.i( self.ClassName, 'Client Exists.' ) + self:T( self.CargoClient.ClientName ) + self:T( 'Client Exists.' ) if routines.IsUnitInRadius( self.CargoClient:GetClientGroupUnit(), Client:ClientPosition(), 150 ) then Near = true @@ -687,8 +684,9 @@ trace.f( self.ClassName ) end + function CARGO_PACKAGE:OnBoard( Client, LandingZone, OnBoardSide ) -trace.f(self.ClassName ) +self:T() local Valid = true @@ -707,12 +705,12 @@ trace.f(self.ClassName ) local Points = {} - trace.i( self.ClassName, 'CargoPos x = ' .. CargoPos.x .. " z = " .. CargoPos.z ) - trace.i( self.ClassName, 'CarrierPosMove x = ' .. CarrierPosMove.x .. " z = " .. CarrierPosMove.z ) + self:T( 'CargoPos x = ' .. CargoPos.x .. " z = " .. CargoPos.z ) + self:T( 'CarrierPosMove x = ' .. CarrierPosMove.x .. " z = " .. CarrierPosMove.z ) Points[#Points+1] = routines.ground.buildWP( CargoPos, "Cone", 10 ) - trace.i( self.ClassName, 'Points[1] x = ' .. Points[1].x .. " y = " .. Points[1].y ) + self:T( 'Points[1] x = ' .. Points[1].x .. " y = " .. Points[1].y ) if OnBoardSide == nil then OnBoardSide = CLIENT.ONBOARDSIDE.NONE @@ -720,7 +718,7 @@ trace.f(self.ClassName ) if OnBoardSide == CLIENT.ONBOARDSIDE.LEFT then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding LEFT" ) + self:T( "TransportCargoOnBoard: Onboarding LEFT" ) CarrierPosMove.z = CarrierPosMove.z - 25 CarrierPosOnBoard.z = CarrierPosOnBoard.z - 5 CarrierPosMoveAway.z = CarrierPosMoveAway.z - 20 @@ -730,7 +728,7 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.RIGHT then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding RIGHT" ) + self:T( "TransportCargoOnBoard: Onboarding RIGHT" ) CarrierPosMove.z = CarrierPosMove.z + 25 CarrierPosOnBoard.z = CarrierPosOnBoard.z + 5 CarrierPosMoveAway.z = CarrierPosMoveAway.z + 20 @@ -740,7 +738,7 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.BACK then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding BACK" ) + self:T( "TransportCargoOnBoard: Onboarding BACK" ) CarrierPosMove.x = CarrierPosMove.x - 25 CarrierPosOnBoard.x = CarrierPosOnBoard.x - 5 CarrierPosMoveAway.x = CarrierPosMoveAway.x - 20 @@ -750,7 +748,7 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.FRONT then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding FRONT" ) + self:T( "TransportCargoOnBoard: Onboarding FRONT" ) CarrierPosMove.x = CarrierPosMove.x + 25 CarrierPosOnBoard.x = CarrierPosOnBoard.x + 5 CarrierPosMoveAway.x = CarrierPosMoveAway.x + 20 @@ -760,7 +758,7 @@ trace.f(self.ClassName ) elseif OnBoardSide == CLIENT.ONBOARDSIDE.NONE then - trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding FRONT" ) + self:T( "TransportCargoOnBoard: Onboarding FRONT" ) CarrierPosMove.x = CarrierPosMove.x + 25 CarrierPosOnBoard.x = CarrierPosOnBoard.x + 5 CarrierPosMoveAway.x = CarrierPosMoveAway.x + 20 @@ -769,7 +767,7 @@ trace.f(self.ClassName ) Points[#Points+1] = routines.ground.buildWP( CarrierPosMoveAway, "Cone", 10 ) end - trace.i( self.ClassName, "Routing " .. CargoHostName ) + self:T( "Routing " .. CargoHostName ) routines.scheduleFunction( routines.goRoute, { CargoHostName, Points}, timer.getTime() + 4 ) @@ -779,7 +777,7 @@ end function CARGO_PACKAGE:OnBoarded( Client, LandingZone ) -trace.f(self.ClassName ) +self:T() local OnBoarded = false @@ -797,11 +795,12 @@ trace.f(self.ClassName ) return OnBoarded end -function CARGO_PACKAGE:UnLoad( Client, TargetZoneName ) -trace.f( self.ClassName ) - trace.i( self.ClassName, 'self.CargoName = ' .. self.CargoName ) - --trace.i( self.ClassName, 'self.CargoHostName = ' .. self.CargoHostName ) +function CARGO_PACKAGE:UnLoad( Client, TargetZoneName ) +self:T() + + self:T( 'self.CargoName = ' .. self.CargoName ) + --self:T( 'self.CargoHostName = ' .. self.CargoHostName ) --self.CargoSpawn:FromCarrier( Client:ClientGroup(), TargetZoneName, self.CargoHostName ) self:StatusUnLoaded() @@ -816,11 +815,10 @@ CARGO_SLINGLOAD = { function CARGO_SLINGLOAD:New( CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID ) -trace.f( self.ClassName, { CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID } ) - - -- Arrange meta tables local self = BASE:Inherit( self, CARGO:New( CargoType, CargoName, CargoWeight ) ) + self:T( { CargoType, CargoName, CargoWeight, CargoZone, CargoHostName, CargoCountryID } ) + self.CargoHostName = CargoHostName -- Cargo will be initialized around the CargoZone position. @@ -838,19 +836,21 @@ trace.f( self.ClassName, { CargoType, CargoName, CargoWeight, CargoZone, CargoHo end + function CARGO_SLINGLOAD:IsLandingRequired() -trace.f( self.ClassName ) +self:T() return false end + function CARGO_SLINGLOAD:IsSlingLoad() -trace.f( self.ClassName ) +self:T() return true end function CARGO_SLINGLOAD:Spawn() -trace.f( self.ClassName ) +self:T() local Zone = trigger.misc.getZone( self.CargoZone ) @@ -858,7 +858,7 @@ trace.f( self.ClassName ) ZonePos.x = Zone.point.x + math.random( Zone.radius / 2 * -1, Zone.radius / 2 ) ZonePos.y = Zone.point.z + math.random( Zone.radius / 2 * -1, Zone.radius / 2 ) - trace.i( self.ClassName, "Cargo Location = " .. ZonePos.x .. ", " .. ZonePos.y ) + self:T( "Cargo Location = " .. ZonePos.x .. ", " .. ZonePos.y ) --[[ -- This does not work in 1.5.2. @@ -898,8 +898,9 @@ trace.f( self.ClassName ) return self end + function CARGO_SLINGLOAD:IsNear( Client, LandingZone ) -trace.f( self.ClassName ) +self:T() local Near = false @@ -908,7 +909,7 @@ end function CARGO_SLINGLOAD:IsInLandingZone( Client, LandingZone ) -trace.f( self.ClassName ) +self:T() local Near = false @@ -923,9 +924,8 @@ trace.f( self.ClassName ) end - function CARGO_SLINGLOAD:OnBoard( Client, LandingZone, OnBoardSide ) -trace.f(self.ClassName ) +self:T() local Valid = true @@ -935,34 +935,28 @@ end function CARGO_SLINGLOAD:OnBoarded( Client, LandingZone ) -trace.f(self.ClassName ) +self:T() local OnBoarded = false local CargoStaticUnit = StaticObject.getByName( self.CargoName ) if CargoStaticUnit then if not routines.IsStaticInZones( CargoStaticUnit, LandingZone ) then - Onboarded = true + OnBoarded = true end end return OnBoarded end -function CARGO_SLINGLOAD:UnLoad( Client, TargetZoneName ) -trace.f( self.ClassName ) - trace.i( self.ClassName, 'self.CargoName = ' .. self.CargoName ) - trace.i( self.ClassName, 'self.CargoGroupName = ' .. self.CargoGroupName ) +function CARGO_SLINGLOAD:UnLoad( Client, TargetZoneName ) +self:T() + + self:T( 'self.CargoName = ' .. self.CargoName ) + self:T( 'self.CargoGroupName = ' .. self.CargoGroupName ) self:StatusUnLoaded() return Cargo end - ---[[-- - Internal Table to understand the form of the CARGO. - @table CARGO_TRANSPORT ---]] -CARGO_TRANSPORT = { UNIT = 1, SLING = 2, STATIC = 3, INVISIBLE = 4 } - diff --git a/Moose/Client.lua b/Moose/Client.lua index ed8994a53..8b152620f 100644 --- a/Moose/Client.lua +++ b/Moose/Client.lua @@ -44,10 +44,9 @@ CLIENT = { -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) function CLIENT:New( ClientName, ClientBriefing ) -trace.f( self.ClassName, { ClientName, ClientBriefing } ) - - -- Arrange meta tables local self = BASE:Inherit( self, BASE:New() ) + self:T() + self.ClientName = ClientName self:AddBriefing( ClientBriefing ) self.MessageSwitch = true @@ -58,7 +57,7 @@ end --- Resets a CLIENT. -- @tparam string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client. function CLIENT:Reset( ClientName ) -trace.f(self.ClassName) +self:T() self._Menus = {} end @@ -66,11 +65,11 @@ end -- This function is modified to deal with a couple of bugs in DCS 1.5.3 -- @treturn Group function CLIENT:ClientGroup() -trace.f(self.ClassName) +self:T() -- local ClientData = Group.getByName( self.ClientName ) -- if ClientData and ClientData:isExist() then --- trace.i( self.ClassName, self.ClientName .. " : group found!" ) +-- self:T( self.ClientName .. " : group found!" ) -- return ClientData -- else -- return nil @@ -78,33 +77,33 @@ trace.f(self.ClassName) local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) } for CoalitionId, CoalitionData in pairs( CoalitionsData ) do - trace.i( self.ClassName, CoalitionData ) + self:T( { "CoalitionData:", CoalitionData } ) for UnitId, UnitData in pairs( CoalitionData ) do - trace.i( self.ClassName, UnitData ) + self:T( { "UnitData:", UnitData } ) if UnitData and UnitData:isExist() then local ClientGroup = Group.getByName( self.ClientName ) if ClientGroup then - trace.i( self.ClassName, "ClientGroup = " .. self.ClientName ) + self:T( "ClientGroup = " .. self.ClientName ) if ClientGroup:isExist() then if ClientGroup:getID() == UnitData:getGroup():getID() then - trace.i( self.ClassName, "Normal logic" ) - trace.i( self.ClassName, self.ClientName .. " : group found!" ) + self:T( "Normal logic" ) + self:T( self.ClientName .. " : group found!" ) return ClientGroup end else -- Now we need to resolve the bugs in DCS 1.5 ... -- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil) - trace.i( self.ClassName, "Bug 1.5 logic" ) + self:T( "Bug 1.5 logic" ) local ClientUnits = _Database.Groups[self.ClientName].Units - trace.i( self.ClassName, { ClientUnits[1].name, env.getValueDictByKey(ClientUnits[1].name) } ) + self:T( { ClientUnits[1].name, env.getValueDictByKey(ClientUnits[1].name) } ) for ClientUnitID, ClientUnitData in pairs( ClientUnits ) do - trace.i( self.ClassName, { tonumber(UnitData:getID()), ClientUnitData.unitId } ) + self:T( { tonumber(UnitData:getID()), ClientUnitData.unitId } ) if tonumber(UnitData:getID()) == ClientUnitData.unitId then local ClientGroupTemplate = _Database.Groups[self.ClientName].Template self.ClientGroupID = ClientGroupTemplate.groupId self.ClientGroupUnit = UnitData - trace.i( self.ClassName, self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) + self:T( self.ClientName .. " : group found in bug 1.5 resolvement logic!" ) return ClientGroup end end @@ -119,10 +118,10 @@ trace.f(self.ClassName) -- For non player clients local ClientGroup = Group.getByName( self.ClientName ) if ClientGroup then - trace.i( self.ClassName, "ClientGroup = " .. self.ClientName ) + self:T( "ClientGroup = " .. self.ClientName ) if ClientGroup:isExist() then - trace.i( self.ClassName, "Normal logic" ) - trace.i( self.ClassName, self.ClientName .. " : group found!" ) + self:T( "Normal logic" ) + self:T( self.ClientName .. " : group found!" ) return ClientGroup end end @@ -135,7 +134,7 @@ end function CLIENT:GetClientGroupID() -trace.f(self.ClassName) +self:T() ClientGroup = self:ClientGroup() @@ -150,10 +149,29 @@ trace.f(self.ClassName) return nil end + +function CLIENT:GetClientGroupName() +self:T() + + ClientGroup = self:ClientGroup() + + if ClientGroup then + if ClientGroup:isExist() then + self:T( ClientGroup:getName() ) + return ClientGroup:getName() + else + self:T( self.ClientName ) + return self.ClientName + end + end + + return nil +end + --- Returns the Unit of the @{CLIENT}. -- @treturn Unit function CLIENT:GetClientGroupUnit() -trace.f(self.ClassName) +self:T() ClientGroup = self:ClientGroup() @@ -172,7 +190,7 @@ end --- Returns the Position of the @{CLIENT}. -- @treturn Position function CLIENT:ClientPosition() ---trace.f(self.ClassName) +--self:T() ClientGroupUnit = self:GetClientGroupUnit() @@ -188,7 +206,7 @@ end --- Transport defines that the Client is a Transport. -- @treturn CLIENT function CLIENT:Transport() -trace.f(self.ClassName) +self:T() self.ClientTransport = true return self @@ -198,7 +216,7 @@ end -- @tparam string ClientBriefing is the text defining the Mission briefing. -- @treturn CLIENT function CLIENT:AddBriefing( ClientBriefing ) -trace.f(self.ClassName) +self:T() self.ClientBriefing = ClientBriefing return self end @@ -206,14 +224,14 @@ end --- IsTransport returns if a Client is a transport. -- @treturn bool function CLIENT:IsTransport() -trace.f(self.ClassName) +self:T() return self.ClientTransport end --- ShowCargo shows the @{CARGO} within the CLIENT to the Player. -- The @{CARGO} is shown throught the MESSAGE system of DCS World. function CLIENT:ShowCargo() -trace.f( self.ClassName ) +self:T() local CargoMsg = "" @@ -244,7 +262,7 @@ end -- @tparam string MessageCategory is the category of the message (the title). -- @tparam number MessageInterval is the interval in seconds between the display of the Message when the CLIENT is in the air. function CLIENT:Message( Message, MessageDuration, MessageId, MessageCategory, MessageInterval ) -trace.f( self.ClassName, { Message, MessageDuration, MessageId, MessageCategory, MessageInterval } ) +self:T() if not self.MenuMessages then if self:GetClientGroupID() then diff --git a/Moose/DeployTask.lua b/Moose/DeployTask.lua index e27e29898..612f1f6ad 100644 --- a/Moose/DeployTask.lua +++ b/Moose/DeployTask.lua @@ -14,27 +14,25 @@ DEPLOYTASK = { -- @tparam table{string,...}|string LandingZones Table or name of the zone(s) where Cargo is to be unloaded. -- @tparam CARGO_TYPE CargoType Type of the Cargo. function DEPLOYTASK:New( CargoType ) -trace.f(self.ClassName) + local self = BASE:Inherit( self, TASK:New() ) + self:T() - -- Child holds the inherited instance of the DEPLOYTASK Class to the BASE class. - local Child = BASE:Inherit( self, TASK:New() ) - local Valid = true if Valid then - Child.Name = 'Deploy Cargo' - Child.TaskBriefing = "Fly to one of the indicated landing zones and deploy " .. CargoType .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the deployment zone." - Child.CargoType = CargoType - Child.GoalVerb = CargoType .. " " .. self.GoalVerb - Child.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGEUNLOAD:New(), STAGEDONE:New() } - Child.SetStage( Child, 1 ) + self.Name = 'Deploy Cargo' + self.TaskBriefing = "Fly to one of the indicated landing zones and deploy " .. CargoType .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the deployment zone." + self.CargoType = CargoType + self.GoalVerb = CargoType .. " " .. self.GoalVerb + self.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGEUNLOAD:New(), STAGEDONE:New() } + self.SetStage( self, 1 ) end - return Child + return self end function DEPLOYTASK:ToZone( LandingZone ) -trace.f(self.ClassName) +self:T() self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone @@ -44,7 +42,7 @@ end function DEPLOYTASK:InitCargo( InitCargos ) -trace.f( self.ClassName, { InitCargos } ) +self:T( { InitCargos } ) if type( InitCargos ) == "table" then self.Cargos.InitCargos = InitCargos @@ -52,13 +50,12 @@ trace.f( self.ClassName, { InitCargos } ) self.Cargos.InitCargos = { InitCargos } end - return self end function DEPLOYTASK:LoadCargo( LoadCargos ) -trace.f( self.ClassName, { LoadCargos } ) +self:T( { LoadCargos } ) if type( LoadCargos ) == "table" then self.Cargos.LoadCargos = LoadCargos @@ -73,7 +70,7 @@ end --- When the cargo is unloaded, it will move to the target zone name. -- @tparam string TargetZoneName Name of the Zone to where the Cargo should move after unloading. function DEPLOYTASK:SetCargoTargetZoneName( TargetZoneName ) -trace.f(self.ClassName) +self:T() local Valid = true @@ -88,7 +85,7 @@ trace.f(self.ClassName) end function DEPLOYTASK:AddCargoMenus( Client, Cargos, TransportRadius ) -trace.f( self.ClassName ) +self:T() local ClientGroupID = Client:GetClientGroupID() @@ -135,7 +132,7 @@ trace.f( self.ClassName ) end function DEPLOYTASK:RemoveCargoMenus( Client ) -trace.f(self.ClassName ) +self:T() local ClientGroupID = Client:GetClientGroupID() trace.i( self.ClassName, ClientGroupID ) diff --git a/Moose/Group.lua b/Moose/Group.lua index 9fa5977af..3506b79e0 100644 --- a/Moose/Group.lua +++ b/Moose/Group.lua @@ -24,6 +24,74 @@ trace.f( self.ClassName, _Group:getName() ) return self end + +function GROUP:GetName() + self:T( self.GroupName ) + + return self.GroupName +end + +function GROUP:Destroy() + self:T( self.GroupName ) + + for Index, UnitData in pairs( self._Group:getUnits() ) do + self:CreateEventCrash( timer.getTime(), UnitData ) + end + + self._Group:destroy() +end + +function GROUP:IsAir() +self:T() + + local IsAirResult = self._Group:getCategory() == Group.Category.AIRPLANE or self._Group:getCategory() == Group.Category.HELICOPTER + + self:T( IsAirResult ) + return IsAirResult +end + +function GROUP:AllOnGround() +self:T() + + local AllOnGroundResult = true + + for Index, UnitData in pairs( self._Group:getUnits() ) do + if UnitData:inAir() then + AllOnGroundResult = false + end + end + + self:T( AllOnGroundResult ) + return AllOnGroundResult +end + + +function GROUP:GetMaxVelocity() +self:T() + + local MaxVelocity = 0 + + for Index, UnitData in pairs( self._Group:getUnits() ) do + + local Velocity = UnitData:getVelocity() + local VelocityTotal = math.abs( Velocity.x ) + math.abs( Velocity.y ) + math.abs( Velocity.z ) + + if VelocityTotal < MaxVelocity then + MaxVelocity = VelocityTotal + end + end + + return MaxVelocity +end + + +function GROUP:GetHeight() +self:T() + + +end + + function GROUP:Land( Point, Duration ) trace.f( self.ClassName, { self.GroupName, Point, Duration } ) diff --git a/Moose/Mission.lua b/Moose/Mission.lua index 13d0ca400..3d699212f 100644 --- a/Moose/Mission.lua +++ b/Moose/Mission.lua @@ -243,11 +243,12 @@ function MISSION:ShowBriefing( Client ) if not Client.ClientBriefingShown then Client.ClientBriefingShown = true - Client:Message( '(Press the keys [LEFT ALT]+[B] to view the briefing pages. Browse through the graphical briefing.)\n' .. - self.MissionBriefing, 40, self.Name .. '/MissionBriefing', "Mission Command: Mission Briefing" ) + local Briefing = self.MissionBriefing if Client.ClientBriefing then - Client:Message( Client.ClientBriefing, 40, self.Name .. '/ClientBriefing', "Mission Command: Mission Briefing" ) + Briefing = Briefing .. "\n" .. Client.ClientBriefing end + Briefing = Briefing .. "\n (Press [LEFT ALT]+[B] to view the graphical documentation.)" + Client:Message( Briefing, 30, self.Name .. '/MissionBriefing', "Command: Mission Briefing" ) end return Client diff --git a/Moose/PickupTask.lua b/Moose/PickupTask.lua index 52479fa42..92100df64 100644 --- a/Moose/PickupTask.lua +++ b/Moose/PickupTask.lua @@ -16,30 +16,30 @@ PICKUPTASK = { -- @tparam CARGO_TYPE CargoType Type of the Cargo. The type must be of the following Enumeration:.. -- @tparam number OnBoardSide Reflects from which side the cargo Group will be on-boarded on the Carrier. function PICKUPTASK:New( CargoType, OnBoardSide ) -trace.f(self.ClassName) + local self = BASE:Inherit( self, TASK:New() ) + self:T() - -- Child holds the inherited instance of the PICKUPTASK Class to the BASE class. - local Child = BASE:Inherit( self, TASK:New() ) + -- self holds the inherited instance of the PICKUPTASK Class to the BASE class. local Valid = true if Valid then - Child.Name = 'Pickup Cargo' - Child.TaskBriefing = "Task: Fly to the indicated landing zones and pickup " .. CargoType .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the pickup zone." - Child.CargoType = CargoType - Child.GoalVerb = CargoType .. " " .. Child.GoalVerb - Child.OnBoardSide = OnBoardSide - Child.IsLandingRequired = false -- required to decide whether the client needs to land or not - Child.IsSlingLoad = false -- Indicates whether the cargo is a sling load cargo - Child.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGELOAD:New(), STAGEDONE:New() } - Child.SetStage( Child, 1 ) + self.Name = 'Pickup Cargo' + self.TaskBriefing = "Task: Fly to the indicated landing zones and pickup " .. CargoType .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the pickup zone." + self.CargoType = CargoType + self.GoalVerb = CargoType .. " " .. self.GoalVerb + self.OnBoardSide = OnBoardSide + self.IsLandingRequired = false -- required to decide whether the client needs to land or not + self.IsSlingLoad = false -- Indicates whether the cargo is a sling load cargo + self.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGELOAD:New(), STAGEDONE:New() } + self.SetStage( self, 1 ) end - return Child + return self end function PICKUPTASK:FromZone( LandingZone ) -trace.f(self.ClassName) +self:T() self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone @@ -48,7 +48,7 @@ trace.f(self.ClassName) end function PICKUPTASK:InitCargo( InitCargos ) -trace.f( self.ClassName, { InitCargos } ) +self:T( { InitCargos } ) if type( InitCargos ) == "table" then self.Cargos.InitCargos = InitCargos @@ -60,7 +60,7 @@ trace.f( self.ClassName, { InitCargos } ) end function PICKUPTASK:LoadCargo( LoadCargos ) -trace.f( self.ClassName, { LoadCargos } ) +self:T( { LoadCargos } ) if type( LoadCargos ) == "table" then self.Cargos.LoadCargos = LoadCargos @@ -72,11 +72,11 @@ trace.f( self.ClassName, { LoadCargos } ) end function PICKUPTASK:AddCargoMenus( Client, Cargos, TransportRadius ) -trace.f( self.ClassName ) +self:T() for CargoID, Cargo in pairs( Cargos ) do - trace.i( self.ClassName, { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo:IsStatusNone(), Cargo:IsStatusLoaded(), Cargo:IsStatusLoading(), Cargo:IsStatusUnLoaded() } ) + self:T( { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo:IsStatusNone(), Cargo:IsStatusLoaded(), Cargo:IsStatusLoading(), Cargo:IsStatusUnLoaded() } ) if Cargo:IsStatusNone() or ( Cargo:IsStatusLoaded() and Client ~= Cargo:IsLoadedInClient() ) then @@ -96,7 +96,7 @@ trace.f( self.ClassName ) self.TEXT[1] .. " " .. Cargo.CargoType, nil ) - trace.i( self.ClassName, 'Added PickupMenu: ' .. self.TEXT[1] .. " " .. Cargo.CargoType ) + self:T( 'Added PickupMenu: ' .. self.TEXT[1] .. " " .. Cargo.CargoType ) end if Client._Menus[Cargo.CargoType].PickupSubMenus == nil then @@ -110,7 +110,7 @@ trace.f( self.ClassName ) self.MenuAction, { ReferenceTask = self, CargoTask = Cargo } ) - trace.i( self.ClassName, 'Added PickupSubMenu' .. Cargo.CargoType .. ":" .. Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )" ) + self:T( 'Added PickupSubMenu' .. Cargo.CargoType .. ":" .. Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )" ) end end end @@ -118,17 +118,17 @@ trace.f( self.ClassName ) end function PICKUPTASK:RemoveCargoMenus( Client ) -trace.f( self.ClassName ) +self:T() for MenuID, MenuData in pairs( Client._Menus ) do for SubMenuID, SubMenuData in pairs( MenuData.PickupSubMenus ) do missionCommands.removeItemForGroup( Client:GetClientGroupID(), SubMenuData ) - trace.i( self.ClassName, "Removed PickupSubMenu " ) + self:T( "Removed PickupSubMenu " ) SubMenuData = nil end if MenuData.PickupMenu then missionCommands.removeItemForGroup( Client:GetClientGroupID(), MenuData.PickupMenu ) - trace.i( self.ClassName, "Removed PickupMenu " ) + self:T( "Removed PickupMenu " ) MenuData.PickupMenu = nil end end @@ -138,7 +138,7 @@ end function PICKUPTASK:HasFailed( ClientDead ) -trace.f(self.ClassName) +self:T() local TaskHasFailed = self.TaskFailed return TaskHasFailed diff --git a/Moose/Routines.lua b/Moose/Routines.lua index a40a8c9df..bdcc7924f 100644 --- a/Moose/Routines.lua +++ b/Moose/Routines.lua @@ -48,53 +48,69 @@ end -- porting in Slmod's serialize_slmod2 routines.utils.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function - if type(tbl) == 'table' then --function only works for tables! - local tbl_str = {} + lookup_table = {} + + local function _Serialize( tbl ) - tbl_str[#tbl_str + 1] = '{' - - for ind,val in pairs(tbl) do -- serialize its fields - if type(ind) == "number" then - tbl_str[#tbl_str + 1] = '[' - tbl_str[#tbl_str + 1] = tostring(ind) - tbl_str[#tbl_str + 1] = ']=' - else --must be a string - tbl_str[#tbl_str + 1] = '[' - tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(ind) - tbl_str[#tbl_str + 1] = ']=' + if type(tbl) == 'table' then --function only works for tables! + + if lookup_table[tbl] then + return lookup_table[object] end - if ((type(val) == 'number') or (type(val) == 'boolean')) then - tbl_str[#tbl_str + 1] = tostring(val) - tbl_str[#tbl_str + 1] = ',' - elseif type(val) == 'string' then - tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(val) - tbl_str[#tbl_str + 1] = ',' - elseif type(val) == 'nil' then -- won't ever happen, right? - tbl_str[#tbl_str + 1] = 'nil,' - elseif type(val) == 'table' then - if ind == "__index" then - tbl_str[#tbl_str + 1] = "__index" + local tbl_str = {} + + lookup_table[tbl] = tbl_str + + tbl_str[#tbl_str + 1] = '{' + + for ind,val in pairs(tbl) do -- serialize its fields + if type(ind) == "number" then + tbl_str[#tbl_str + 1] = '[' + tbl_str[#tbl_str + 1] = tostring(ind) + tbl_str[#tbl_str + 1] = ']=' + else --must be a string + tbl_str[#tbl_str + 1] = '[' + tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(ind) + tbl_str[#tbl_str + 1] = ']=' + end + + if ((type(val) == 'number') or (type(val) == 'boolean')) then + tbl_str[#tbl_str + 1] = tostring(val) + tbl_str[#tbl_str + 1] = ',' + elseif type(val) == 'string' then + tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(val) + tbl_str[#tbl_str + 1] = ',' + elseif type(val) == 'nil' then -- won't ever happen, right? + tbl_str[#tbl_str + 1] = 'nil,' + elseif type(val) == 'table' then + if ind == "__index" then + tbl_str[#tbl_str + 1] = "__index" + tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + else + + tbl_str[#tbl_str + 1] = _Serialize(val) + tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + end + elseif type(val) == 'function' then + tbl_str[#tbl_str + 1] = "function " .. tostring(ind) tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it else - tbl_str[#tbl_str + 1] = routines.utils.oneLineSerialize(val) - tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it + env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) + env.info( debug.traceback() ) end - elseif type(val) == 'function' then - tbl_str[#tbl_str + 1] = "function " .. tostring(ind) - tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it - else - env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind)) - env.info( debug.traceback() ) - end + end + tbl_str[#tbl_str + 1] = '}' + return table.concat(tbl_str) + else + return tostring(tbl) end - tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) - else - return tostring(tbl) end + + local objectreturn = _Serialize(tbl) + return objectreturn end --porting in Slmod's "safestring" basic serialize diff --git a/Moose/Spawn.lua b/Moose/Spawn.lua index 0fdd5d521..343d6614b 100644 --- a/Moose/Spawn.lua +++ b/Moose/Spawn.lua @@ -236,6 +236,37 @@ trace.f( self.ClassName ) return self end +function SPAWN:CleanUp( SpawnCleanUpInterval ) +self:T() + + self.SpawnCleanUpInterval = SpawnCleanUpInterval + self.SpawnCleanUpTimeStamps = {} + self.CleanUpFunction = routines.scheduleFunction( self._SpawnCleanUpScheduler, { self }, timer.getTime() + 1, 60 ) +end + +function SPAWN:_SpawnCleanUpScheduler() +self:T() + + local SpawnGroup = self:GetFirstAliveGroup() + + while SpawnGroup do + + if SpawnGroup:AllOnGround() and SpawnGroup:GetMaxVelocity() < 1 then + if not self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] then + self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] = timer.getTime() + else + if self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] + self.SpawnCleanUpInterval < timer.getTime() then + SpawnGroup:Destroy() + end + end + else + self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] = nil + end + + SpawnGroup = self:GetNextAliveGroup() + end + +end --- Will SPAWN a Group whenever you want to do this. -- Note that the configuration with the above functions will apply when calling this method: Maxima, Randomization of routes, Scheduler, ... @@ -441,7 +472,42 @@ function SPAWN:GetLastIndex() end -function SPAWN:GetLastGroup() + +function SPAWN:GetFirstAliveGroup() +self:T() + + self.SpawnIndex = 1 + for SpawnIndex = 1, self.SpawnCount do + SpawnGroupName = self:SpawnGroupName( SpawnIndex ) + SpawnGroup = Group.getByName( SpawnGroupName ) + if SpawnGroup and SpawnGroup:isExist() then + self.SpawnIndex = SpawnIndex + return GROUP:New( SpawnGroup ) + end + end + + self.SpawnIndex = nil + return nil +end + +function SPAWN:GetNextAliveGroup() +self:T() + + self.SpawnIndex = self.SpawnIndex + 1 + for SpawnIndex = self.SpawnIndex, self.SpawnCount do + SpawnGroupName = self:SpawnGroupName( SpawnIndex ) + SpawnGroup = Group.getByName( SpawnGroupName ) + if SpawnGroup and SpawnGroup:isExist() then + self.SpawnIndex = SpawnIndex + return GROUP:New( SpawnGroup ) + end + end + + self.SpawnIndex = nil + return nil +end + +function SPAWN:GetLastAliveGroup() trace.f( self.ClassName ) local LastGroupName = self:SpawnGroupName( self:GetLastIndex() ) @@ -449,7 +515,6 @@ trace.f( self.ClassName ) return GROUP:New( Group.getByName( LastGroupName ) ) end - --- Will SPAWN a Group within a given ZoneName. -- @tparam string ZonePrefix is the name of the zone where the Group is to be SPAWNed. -- @treturn SpawnTemplate diff --git a/Moose/Stage.lua b/Moose/Stage.lua index a9e8377aa..5b79bfd8a 100644 --- a/Moose/Stage.lua +++ b/Moose/Stage.lua @@ -27,13 +27,12 @@ STAGE = { function STAGE:New() -trace.f(self.ClassName) local self = BASE:Inherit( self, BASE:New() ) + self:T() return self end function STAGE:Execute( Mission, Client, Task ) -trace.f(self.ClassName) local Valid = true @@ -41,13 +40,10 @@ trace.f(self.ClassName) end function STAGE:Executing( Mission, Client, Task ) -trace.f(self.ClassName) end function STAGE:Validate( Mission, Client, Task ) -trace.f(self.ClassName) - local Valid = true return Valid @@ -63,24 +59,23 @@ STAGEBRIEF = { } function STAGEBRIEF:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'CLIENT' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'CLIENT' + return self end function STAGEBRIEF:Execute( Mission, Client, Task ) -trace.f(self.ClassName) local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) + self:T() Mission:ShowBriefing( Client ) self.StageBriefingTime = timer.getTime() return Valid end function STAGEBRIEF:Validate( Mission, Client, Task ) -trace.f(self.ClassName) local Valid = STAGE:Validate( Mission, Client, Task ) + self:T() if timer.getTime() - self.StageBriefingTime <= self.StageBriefingDuration then return 0 @@ -101,27 +96,26 @@ STAGESTART = { } function STAGESTART:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'CLIENT' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'CLIENT' + return self end function STAGESTART:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) if Task.TaskBriefing then - Client:Message( Task.TaskBriefing, 15, Mission.Name .. "/Stage", "Mission Command: Tasking" ) + Client:Message( Task.TaskBriefing, 30, Mission.Name .. "/Stage", "Mission Command: Tasking" ) else - Client:Message( 'Task ' .. Task.TaskNumber .. '.', 15, Mission.Name .. "/Stage", "Mission Command: Tasking" ) + Client:Message( 'Task ' .. Task.TaskNumber .. '.', 30, Mission.Name .. "/Stage", "Mission Command: Tasking" ) end self.StageStartTime = timer.getTime() return Valid end function STAGESTART:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = STAGE:Validate( Mission, Client, Task ) if timer.getTime() - self.StageStartTime <= self.StageStartDuration then @@ -140,15 +134,14 @@ STAGE_CARGO_LOAD = { } function STAGE_CARGO_LOAD:New() -trace.f(self.ClassName) - -- Arrange meta tables local self = BASE:Inherit( self, STAGE:New() ) + self:T() self.StageType = 'CLIENT' return self end function STAGE_CARGO_LOAD:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) for LoadCargoID, LoadCargo in pairs( Task.Cargos.LoadCargos ) do @@ -163,7 +156,7 @@ trace.f(self.ClassName) end function STAGE_CARGO_LOAD:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = STAGE:Validate( Mission, Client, Task ) return 1 @@ -175,26 +168,26 @@ STAGE_CARGO_INIT = { } function STAGE_CARGO_INIT:New() -trace.f(self.ClassName) - -- Arrange meta tables local self = BASE:Inherit( self, STAGE:New() ) + self:T() self.StageType = 'CLIENT' return self end function STAGE_CARGO_INIT:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) for InitLandingZoneID, InitLandingZone in pairs( Task.LandingZones.LandingZones ) do - trace.i( self.ClassName, InitLandingZone ) + self:T( InitLandingZone ) InitLandingZone:Spawn() end - - for InitCargoID, InitCargo in pairs( Task.Cargos.InitCargos ) do - trace.i( self.ClassName ) - InitCargo:Spawn() + + self:T( Task.Cargos.InitCargos ) + for InitCargoID, InitCargoData in pairs( Task.Cargos.InitCargos ) do + self:T( { InitCargoData } ) + InitCargoData:Spawn() end return Valid @@ -202,7 +195,7 @@ end function STAGE_CARGO_INIT:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = STAGE:Validate( Mission, Client, Task ) return 1 @@ -218,9 +211,8 @@ STAGEROUTE = { } function STAGEROUTE:New() -trace.f(self.ClassName) - -- Arrange meta tables local self = BASE:Inherit( self, STAGE:New() ) + self:T() self.StageType = 'CLIENT' self.MessageSwitch = true return self @@ -228,10 +220,11 @@ end function STAGEROUTE:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) local RouteMessage = "Fly to " + self:T( Task.LandingZones ) for LandingZoneID, LandingZoneName in pairs( Task.LandingZones.LandingZoneNames ) do RouteMessage = RouteMessage .. LandingZoneName .. ' at ' .. routines.getBRStringZone( { zone = LandingZoneName, ref = Client:GetClientGroupUnit():getPoint(), true, true } ) .. ' km. ' end @@ -245,11 +238,11 @@ trace.f(self.ClassName) end function STAGEROUTE:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() local Valid = STAGE:Validate( Mission, Client, Task ) -- check if the Client is in the landing zone - trace.i( self.ClassName, Task.LandingZones.LandingZoneNames ) + self:T( Task.LandingZones.LandingZoneNames ) Task.CurrentLandingZoneName = routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.LandingZones.LandingZoneNames ) if Task.CurrentLandingZoneName then @@ -279,15 +272,14 @@ STAGELANDING = { } function STAGELANDING:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'CLIENT' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'CLIENT' + return self end function STAGELANDING:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() Client:Message( "We have arrived at the landing zone.", self.MSG.TIME, Mission.Name .. "/StageArrived", "Co-Pilot: Arrived", 10 ) @@ -307,12 +299,12 @@ trace.f(self.ClassName) if Cargo.CargoType == Task.CargoType then if Cargo:IsLandingRequired() then - trace.i( self.ClassName, "Task for cargo " .. Cargo.CargoType .. " requires landing.") + self:T( "Task for cargo " .. Cargo.CargoType .. " requires landing.") Task.IsLandingRequired = true end if Cargo:IsSlingLoad() then - trace.i( self.ClassName, "Task for cargo " .. Cargo.CargoType .. " is a slingload.") + self:T( "Task for cargo " .. Cargo.CargoType .. " is a slingload.") Task.IsSlingLoad = true end @@ -337,13 +329,13 @@ trace.f(self.ClassName) end function STAGELANDING:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() Task.CurrentLandingZoneName = routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.LandingZones.LandingZoneNames ) if Task.CurrentLandingZoneName then -- Client is in de landing zone. - trace.i( self.ClassName, Task.CurrentLandingZoneName ) + self:T( Task.CurrentLandingZoneName ) Task.CurrentLandingZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName].CargoZone Task.CurrentCargoZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName] @@ -380,15 +372,14 @@ STAGELANDED = { } function STAGELANDED:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'CLIENT' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'CLIENT' + return self end function STAGELANDED:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() if Task.IsLandingRequired then Client:Message( 'We have landed within the landing zone. Use the radio menu (F10) to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType .. '.', @@ -404,17 +395,17 @@ end function STAGELANDED:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() if not routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then - trace.i( self.ClassName, "Client is not anymore in the landing zone, go back to stage Route, and remove cargo menus." ) + self:T( "Client is not anymore in the landing zone, go back to stage Route, and remove cargo menus." ) Task.Signalled = false Task:RemoveCargoMenus( Client ) return -2 end if Task.IsLandingRequired and Client:GetClientGroupUnit():inAir() then - trace.i( self.ClassName, "Client went back in the air. Go back to stage Landing." ) + self:T( "Client went back in the air. Go back to stage Landing." ) Task.Signalled = false return -1 end @@ -436,22 +427,21 @@ STAGEUNLOAD = { } function STAGEUNLOAD:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'CLIENT' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'CLIENT' + return self end function STAGEUNLOAD:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.', self.MSG.TIME, Mission.Name .. "/StageUnLoad", "Co-Pilot: Unload" ) Task:RemoveCargoMenus( Client ) end function STAGEUNLOAD:Executing( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() env.info( 'STAGEUNLOAD:Executing() Task.Cargo.CargoName = ' .. Task.Cargo.CargoName ) local TargetZoneName @@ -471,7 +461,7 @@ trace.f(self.ClassName) end function STAGEUNLOAD:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() env.info( 'STAGEUNLOAD:Validate()' ) if routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then @@ -509,15 +499,14 @@ STAGELOAD = { } function STAGELOAD:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'CLIENT' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'CLIENT' + return self end function STAGELOAD:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() if not Task.IsSlingLoad then Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.', @@ -532,7 +521,7 @@ trace.f(self.ClassName) end function STAGELOAD:Executing( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() -- If the Cargo is ready to be loaded, load it into the Client. @@ -556,7 +545,7 @@ trace.f(self.ClassName) Client:Message( "Hook the " .. Task.CargoNames .. " onto the helicopter " .. Task.TEXT[3] .. " within the landing zone.", _TransportStageMsgTime.EXECUTING, Mission.Name .. "/STAGELOAD.LOADING.1." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":", 10 ) for CargoID, Cargo in pairs( CARGOS ) do - trace.i( self.ClassName, "Cargo.CargoName = " .. Cargo.CargoName ) + self:T( "Cargo.CargoName = " .. Cargo.CargoName ) if Cargo:IsSlingLoad() then local CargoStatic = StaticObject.getByName( Cargo.CargoStaticName ) @@ -575,7 +564,7 @@ trace.f(self.ClassName) break end else - trace.i( self.ClassName, "Cargo not found in the DCS simulator." ) + self:T( "Cargo not found in the DCS simulator." ) end end end @@ -584,9 +573,9 @@ trace.f(self.ClassName) end function STAGELOAD:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() - trace.i( self.ClassName, "Task.CurrentLandingZoneName = " .. Task.CurrentLandingZoneName ) + self:T( "Task.CurrentLandingZoneName = " .. Task.CurrentLandingZoneName ) if not Task.IsSlingLoad then if not routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then @@ -634,93 +623,6 @@ trace.f(self.ClassName) return 0 end -STAGE_SLINGLOAD_HOOK = { - ClassName = "STAGE_SLINGLOAD_HOOK", - MSG = { ID = "SlingLoadHook", TIME = 10 }, - Name = "SlingLoadHook" -} - -function STAGE_SLINGLOAD_HOOK:New() -trace.f(self.ClassName) - -- Arrange meta tables - local self = BASE:Inherit( self, STAGE:New() ) - self.StageType = 'CLIENT' - return self -end - -function STAGE_SLINGLOAD_HOOK:Execute( Mission, Client, Task ) -trace.f(self.ClassName) - Client:Message( 'Hook the Cargo onto the helicopter, and fly out the pick-up zone. Due to a bug in DCS world it cannot be chacked (for the moment) ' .. - 'if the cargo is in our out of the zone and attached to your helicopter...', self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Hook" ) -end - -function STAGE_SLINGLOAD_HOOK:Validate( Mission, Client, Task ) -trace.f(self.ClassName) - - - for CargoID, CargoName in pairs( Task.CargoPrefixes ) do - env.info( CargoName ) - if StaticObject.getByName( CargoName ):inAir() then - Task.CargoName = CargoName - Task.CargoID = CargoID - Client:Message( 'Co-Pilot: The Cargo has been successfully hooked onto the helicopter within the landing zone.', self.MSG.TIME, Mission.Name .. "/StageSuccess" ) - break - end - end - - if Task.CargoName then - if routines.IsStaticInZones( StaticObject.getByName( Task.CargoName ), Task.CurrentLandingZoneName ) then - else - return 1 - end - end - - return 1 -end - -STAGE_SLINGLOAD_UNHOOK = { - ClassName = "STAGE_SLINGLOAD_UNHOOK", - MSG = { ID = "SlingLoadUnHook", TIME = 10 }, - Name = "SlingLoadUnHook" -} - -function STAGE_SLINGLOAD_UNHOOK:New() -trace.f(self.ClassName) - -- Arrange meta tables - local self = BASE:Inherit( self, STAGE:New() ) - self.StageType = 'CLIENT' - return self -end - -function STAGE_SLINGLOAD_UNHOOK:Execute( Mission, Client, Task ) -trace.f(self.ClassName) - Client:Message( 'Deploy the Cargo in the Landing Zone and unhook the cargo, and fly out of the drop zone.', self.MSG.TIME, Mission.Name .. "/StageUnhook", "Co-Pilot: Unhook" ) -end - -function STAGE_SLINGLOAD_UNHOOK:Validate( Mission, Client, Task ) -trace.f(self.ClassName) - - for CargoID, CargoName in pairs( Task.CargoPrefixes ) do - if StaticObject.getByName( CargoName ):inAir() then - Task.CargoName = CargoName - Task.CargoID = CargoID - Client:Message( 'Co-Pilot: Drop the cargo within the landing zone and unhook.', self.MSG.TIME, Mission.Name .. "/Stage" ) - break - end - end - - if Task.CargoName then - if not StaticObject.getByName( Task.CargoName ):inAir() then - if routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then - else - Client:Message( 'Co-Pilot: The Cargo is Dropped in the Landing Zone, and You have flown outside of the landing zone.', self.MSG.TIME, Mission.Name .. "/Stage" ) - return 1 - end - end - end - - return 1 -end STAGEDONE = { ClassName = "STAGEDONE", @@ -729,20 +631,19 @@ STAGEDONE = { } function STAGEDONE:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'AI' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'AI' + return self end function STAGEDONE:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() end function STAGEDONE:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() Task:Done() @@ -756,22 +657,21 @@ STAGEARRIVE = { } function STAGEARRIVE:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'CLIENT' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'CLIENT' + return self end function STAGEARRIVE:Execute( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() Client:Message( 'We have arrived at ' .. Task.CurrentLandingZoneName .. ".", self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Arrived" ) end function STAGEARRIVE:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.LandingZones ) if ( Task.CurrentLandingZoneID ) then @@ -791,11 +691,10 @@ STAGEGROUPSDESTROYED = { } function STAGEGROUPSDESTROYED:New() -trace.f(self.ClassName) - -- Arrange meta tables - local Child = BASE:Inherit( self, STAGE:New() ) - Child.StageType = 'AI' - return Child + local self = BASE:Inherit( self, STAGE:New() ) + self:T() + self.StageType = 'AI' + return self end --function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task ) @@ -805,7 +704,7 @@ end --end function STAGEGROUPSDESTROYED:Validate( Mission, Client, Task ) -trace.f(self.ClassName) +self:T() if Task.MissionTask:IsGoalReached() then return 1 @@ -815,8 +714,8 @@ trace.f(self.ClassName) end function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task ) -trace.f(self.ClassName) - trace.i( self.ClassName, { Task.ClassName, Task.Destroyed } ) +self:T() + self:T( { Task.ClassName, Task.Destroyed } ) --env.info( 'Event Table Task = ' .. tostring(Task) ) end diff --git a/Test Missions/MOOSE_Pickup_Test.lua b/Test Missions/MOOSE_Pickup_Test.lua new file mode 100644 index 000000000..dfe4ff840 --- /dev/null +++ b/Test Missions/MOOSE_Pickup_Test.lua @@ -0,0 +1,126 @@ +Include.File( "Mission" ) +Include.File( "Client" ) +Include.File( "DeployTask" ) +Include.File( "PickupTask" ) +Include.File( "DestroyGroupsTask" ) +Include.File( "DestroyRadarsTask" ) +Include.File( "DestroyUnitTypesTask" ) +Include.File( "GoHomeTask" ) +Include.File( "Spawn" ) +Include.File( "Movement" ) +Include.File( "Sead" ) +Include.File( "CleanUp" ) + +do + local Mission = MISSION:New( 'Pickup', 'Operational', 'Pickup Troops', 'NATO' ) + + Mission:AddClient( CLIENT:New( 'DE Pickup Test 1' ):Transport() ) + Mission:AddClient( CLIENT:New( 'DE Pickup Test 2' ):Transport() ) + + local CargoTable = {} + + local EngineerNames = { "Alpha", "Beta", "Gamma", "Delta", "Theta" } + + Cargo_Pickup_Zone_1 = CARGO_ZONE:New( 'Pickup Zone 1', 'DE Communication Center 1' ):BlueSmoke() + Cargo_Pickup_Zone_2 = CARGO_ZONE:New( 'Pickup Zone 2', 'DE Communication Center 2' ):RedSmoke() + + for CargoItem = 1, 2 do + CargoTable[CargoItem] = CARGO_GROUP:New( 'Engineers', 'Team ' .. EngineerNames[CargoItem], math.random( 70, 100 ) * 3, 'DE Infantry', Cargo_Pickup_Zone_1 ) + end + + for CargoItem = 3, 5 do + CargoTable[CargoItem] = CARGO_GROUP:New( 'Engineers', 'Team ' .. EngineerNames[CargoItem], math.random( 70, 100 ) * 3, 'DE Infantry', Cargo_Pickup_Zone_2 ) + end + + --Cargo_Package = CARGO_INVISIBLE:New( 'Letter', 0.1, 'DE Secret Agent', 'Pickup Zone Package' ) + --Cargo_Goods = CARGO_STATIC:New( 'Goods', 20, 'Goods', 'Pickup Zone Goods', 'DE Collection Point' ) + --Cargo_SlingLoad = CARGO_SLING:New( 'Basket', 40, 'Basket', 'Pickup Zone Sling Load', 'DE Cargo Guard' ) + + + -- Assign the Pickup Task + local PickupTask = PICKUPTASK:New( 'Engineers', CLIENT.ONBOARDSIDE.LEFT ) + PickupTask:FromZone( Cargo_Pickup_Zone_1 ) + PickupTask:FromZone( Cargo_Pickup_Zone_2 ) + PickupTask:InitCargo( CargoTable ) + PickupTask:SetGoalTotal( 3 ) + Mission:AddTask( PickupTask, 1 ) + + + Cargo_Deploy_Zone_1 = CARGO_ZONE:New( 'Deploy Zone 1', 'DE Communication Center 3' ):RedFlare() + Cargo_Deploy_Zone_2 = CARGO_ZONE:New( 'Deploy Zone 2', 'DE Communication Center 4' ):WhiteFlare() + + -- Assign the Pickup Task + local DeployTask = DEPLOYTASK:New( 'Engineers' ) + DeployTask:ToZone( Cargo_Deploy_Zone_1 ) + DeployTask:ToZone( Cargo_Deploy_Zone_2 ) + DeployTask:SetGoalTotal( 3 ) + Mission:AddTask( DeployTask, 2 ) + + MISSIONSCHEDULER.AddMission( Mission ) +end + +do + local Mission = MISSION:New( 'Deliver secret letter', 'Operational', 'Pickup letter to the commander.', 'NATO' ) + + Mission:AddClient( CLIENT:New( 'BE Package Test 1' ):Transport() ) + Mission:AddClient( CLIENT:New( 'BE Package Test 2' ):Transport() ) + Mission:AddClient( CLIENT:New( 'DE Pickup Test 1' ):Transport() ) + Mission:AddClient( CLIENT:New( 'DE Pickup Test 2' ):Transport() ) + + Package_Pickup_Zone = CARGO_ZONE:New( 'Package Pickup Zone', 'DE Guard' ):GreenSmoke() + + Cargo_Package = CARGO_PACKAGE:New( 'Letter', 'Letter to Command', 0.1, 'DE Guard' ) + --Cargo_Goods = CARGO_STATIC:New( 'Goods', 20, 'Goods', 'Pickup Zone Goods', 'DE Collection Point' ) + --Cargo_SlingLoad = CARGO_SLING:New( 'Basket', 40, 'Basket', 'Pickup Zone Sling Load', 'DE Cargo Guard' ) + + + -- Assign the Pickup Task + local PickupTask = PICKUPTASK:New( 'Letter', CLIENT.ONBOARDSIDE.FRONT ) + PickupTask:FromZone( Package_Pickup_Zone ) + PickupTask:InitCargo( { Cargo_Package } ) + PickupTask:SetGoalTotal( 1 ) + Mission:AddTask( PickupTask, 1 ) + + + Package_Deploy_Zone = CARGO_ZONE:New( 'Package Deploy Zone', 'DE Secret Car' ):GreenFlare() + + -- Assign the Pickup Task + local DeployTask = DEPLOYTASK:New( 'Letter' ) + DeployTask:ToZone( Package_Deploy_Zone ) + DeployTask:SetGoalTotal( 1 ) + Mission:AddTask( DeployTask, 2 ) + + MISSIONSCHEDULER.AddMission( Mission ) +end + +do + local Mission = MISSION:New( 'Sling load Cargo', 'Operational', 'Sling Load Cargo to Deploy Zone.', 'NATO' ) + + Mission:AddClient( CLIENT:New( 'Sling Load Test Client 1' ):Transport() ) + Mission:AddClient( CLIENT:New( 'Sling Load Test Client 2' ):Transport() ) + + Sling_Load_Pickup_Zone = CARGO_ZONE:New( 'Sling Load Pickup Zone', 'Sling Load Guard' ):RedSmoke() + + Cargo_Sling_Load = CARGO_SLINGLOAD:New( 'Sling', 'Food Boxes', 200, 'Sling Load Pickup Zone', 'Sling Load Guard', country.id.USA ) + --Cargo_Goods = CARGO_STATIC:New( 'Goods', 20, 'Goods', 'Pickup Zone Goods', 'DE Collection Point' ) + --Cargo_SlingLoad = CARGO_SLING:New( 'Basket', 40, 'Basket', 'Pickup Zone Sling Load', 'DE Cargo Guard' ) + + + -- Assign the Pickup Task + local PickupTask = PICKUPTASK:New( 'Sling', CLIENT.ONBOARDSIDE.FRONT ) + PickupTask:FromZone( Sling_Load_Pickup_Zone ) + PickupTask:InitCargo( { Cargo_Sling_Load } ) + PickupTask:SetGoalTotal( 1 ) + Mission:AddTask( PickupTask, 1 ) + + MISSIONSCHEDULER.AddMission( Mission ) +end + + + +-- MISSION SCHEDULER STARTUP +MISSIONSCHEDULER.Start() +MISSIONSCHEDULER.ReportMenu() +MISSIONSCHEDULER.ReportMissionsHide() + +env.info( "Test Mission loaded" ) diff --git a/Test Missions/MOOSE_Pickup_Test.miz b/Test Missions/MOOSE_Pickup_Test.miz new file mode 100644 index 0000000000000000000000000000000000000000..b200f5ef241f39b6320604682d1cbfd28ff9b002 GIT binary patch literal 27262 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 YD+h#r%_@JKEI)wtzN)5+jQ;%lAGN~Ga{vGU literal 0 HcmV?d00001 diff --git a/Test Missions/MOOSE_Spawn_Test.lua b/Test Missions/MOOSE_Spawn_Test.lua new file mode 100644 index 000000000..e0ef01e5b --- /dev/null +++ b/Test Missions/MOOSE_Spawn_Test.lua @@ -0,0 +1,15 @@ +Include.File( "Spawn" ) + +SpawnTest = SPAWN:New( 'TEST' ):Schedule( 1, 1, 15, 0.4 ):Repeat() + +SpawnTestPlane = SPAWN:New( 'TESTPLANE' ):Schedule( 1, 1, 15, 0.4 ):RepeatOnLanding() + +SpawnTestShipPlane = SPAWN:New( 'SHIPPLANE' ):Schedule( 1, 1, 15, 0.4 ):RepeatOnLanding() + +SpawnTestShipHeli = SPAWN:New( 'SHIPHELI' ):Schedule( 1, 1, 15, 0.4 ):RepeatOnLanding() + +SpawnCH53E = SPAWN:New( 'VEHICLE' ) + + +SpawnTestHelicopterCleanUp = SPAWN:New( "TEST_HELI_CLEANUP" ):Limit( 3, 100 ):Schedule( 10, 0 ):RandomizeRoute( 1, 1, 1000 ):CleanUp( 180 ) +SpawnTestVehiclesCleanUp = SPAWN:New( "TEST_AAA_CLEANUP" ):Limit( 3, 100 ):Schedule( 10, 0 ):RandomizeRoute( 1, 1, 1000 ) \ No newline at end of file diff --git a/Test Missions/MOOSE_Spawn_Test.miz b/Test Missions/MOOSE_Spawn_Test.miz new file mode 100644 index 0000000000000000000000000000000000000000..fc2b4022b002b9ec02fe7ccf0c4fd54e38d6ae18 GIT binary patch literal 19439 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 ORl!B@AmFnZd+H#rvL8DHB?RTzS65M zVuPokn?!EN${V-718W0}o76JcCGWNOw>7SS1xj6oB#M4(NA5QcLW6BT&YH%|Kflwv zWTX*}YPhq`cJsj*6}5}qLT!uhnc~V7KG)T(MLc*d{Dg>C?GBaq9rw+6Gn5v-xcjO_ zLQZ}Hu>?>Y;0AT^%060hYE|?E=CEW5m+%)qj+JDy*Kpyh670joKw(PV6!9{F4@HMw z$Nc!yH-L4&aRIV-Pu@|%cp}ne_K&Q={E@hI`=jNxUbc|E2C)PQ^}1!aUbvx00*}L( z=(i?Bzlu*F0U49l61d*}r00yVzE2|LZKW&q$JW`8X4}OSdiNhk-3+N|f(}O_;KY4FCxmRhGHCn`^+pS~6;(%gt zPUBX~hE=9`E|=g@zW!<6TURt=Rjrjjyt&jlXnR+r-HoLq7bLr&QJ|z+FT*eqWwJz? zb$&qKrQV8m2buwz97sHRH5Uq`+MPuIUX%Sy_lT%Q2>?jx0RSY|1VEsZAJW|?0EI*? zWpp4uNHObd?_yzImnx{JImEG-1@b6a!@!y_PrFj~#CTdd=A&4B((hRAb7CB*@(q{8 zzCC<}O1p)5`n&f9M&NS~8oiinWh97( zD86KHyT}!|*}BAm$LDUHiBvC4aztuhyvHIH<`nPzAn6_?$MICOBcvIU6UpL92X#F4 zfwzTDm|_?z8-0(3F`ONmamqDrDB>i)jP_^J$4FJrX0@L=5a9oQ`#bJz zv-}qd%&Q?@MVbq`JLvb9|c6E+$=HM)T+%*)9`k0X->pj{Z9_-M8o= zX#jR;a^P#-be>$H-&% zC;-5ax-M;{jr{$gi literal 0 HcmV?d00001