From c999389cda86d91ea07a8c39568ce8a62b1b838b Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 23 Apr 2018 06:51:49 +0200 Subject: [PATCH 1/4] Handler for unloading too. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 268 ++++++-- .../Moose/AI/AI_Cargo_Helicopter.lua | 35 +- Moose Development/Moose/Cargo/Cargo.lua | 20 +- Moose Development/Moose/Cargo/CargoCrate.lua | 6 +- Moose Development/Moose/Cargo/CargoGroup.lua | 20 +- .../Moose/Cargo/CargoSlingload.lua | 8 +- Moose Development/Moose/Cargo/CargoUnit.lua | 2 +- Moose Development/Moose/Core/Database.lua | 20 +- Moose Development/Moose/Core/Point.lua | 14 +- .../Moose/Wrapper/Controllable.lua | 645 +++++++++--------- 10 files changed, 600 insertions(+), 438 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 2c34615cd..68ffc7046 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -24,18 +24,21 @@ AI_CARGO_APC = { --- Creates a new AI_CARGO_APC object. -- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier --- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup +-- @param Wrapper.Group#GROUP CargoCarrier +-- @param Core.Set#SET_CARGO CargoSet -- @param #number CombatRadius -- @return #AI_CARGO_APC -function AI_CARGO_APC:New( CargoCarrier, CargoGroup, CombatRadius ) +function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_APC - self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP + self.CargoSet = CargoSet -- Core.Set#SET_CARGO self.CombatRadius = CombatRadius - self:SetStartState( "UnLoaded" ) + self:SetStartState( "Unloaded" ) + + self:AddTransition( "Unloaded", "Pickup", "*" ) + self:AddTransition( "Loaded", "Deploy", "*" ) self:AddTransition( "*", "Load", "Boarding" ) self:AddTransition( "Boarding", "Board", "Boarding" ) @@ -46,10 +49,85 @@ function AI_CARGO_APC:New( CargoCarrier, CargoGroup, CombatRadius ) self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Follow", "Following" ) - self:AddTransition( "*", "Guard", "Guarding" ) + self:AddTransition( "*", "Guard", "Unloaded" ) self:AddTransition( "*", "Destroyed", "Destroyed" ) + + --- Pickup Handler OnBefore for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnBeforePickup + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + -- @return #boolean + + --- Pickup Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterPickup + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + + --- Pickup Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] Pickup + -- @param #AI_CARGO_APC self + -- @param Core.Point#COORDINATE Coordinate + + --- Pickup Asynchronous Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] __Pickup + -- @param #AI_CARGO_APC self + -- @param #number Delay + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Handler OnBefore for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnBeforeDeploy + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + -- @return #boolean + + --- Deploy Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterDeploy + -- @param #AI_CARGO_APC self + -- @param #string From + -- @param #string Event + -- @param #string To + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] Deploy + -- @param #AI_CARGO_APC self + -- @param Core.Point#COORDINATE Coordinate + + --- Deploy Asynchronous Trigger for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] __Deploy + -- @param #AI_CARGO_APC self + -- @param Core.Point#COORDINATE Coordinate + -- @param #number Delay + + + --- Loaded Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterLoaded + -- @param #AI_CARGO_APC self + -- @param Wrapper.Group#GROUP APC + -- @param #string From + -- @param #string Event + -- @param #string To + + --- Unloaded Handler OnAfter for AI_CARGO_APC + -- @function [parent=#AI_CARGO_APC] OnAfterUnloaded + -- @param #AI_CARGO_APC self + -- @param Wrapper.Group#GROUP APC + -- @param #string From + -- @param #string Event + -- @param #string To + + self:__Monitor( 1 ) self:SetCarrier( CargoCarrier ) @@ -60,11 +138,11 @@ end --- Set the Carrier. -- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier -- @return #AI_CARGO_APC function AI_CARGO_APC:SetCarrier( CargoCarrier ) - self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT + self.CargoCarrier = CargoCarrier -- Wrapper.Group#GROUP self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self ) CargoCarrier:HandleEvent( EVENTS.Dead ) @@ -110,7 +188,7 @@ end -- @param #AI_CARGO_APC self -- @param Core.Point#COORDINATE Coordinate -- @param #number Radius --- @return Wrapper.Unit#UNIT NewCarrier +-- @return Wrapper.Group#GROUP NewCarrier function AI_CARGO_APC:FindCarrier( Coordinate, Radius ) local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) @@ -122,11 +200,12 @@ function AI_CARGO_APC:FindCarrier( Coordinate, Radius ) local Attributes = NearUnit:GetDesc() self:F({Desc=Attributes}) if NearUnit:HasAttribute( "Trucks" ) then - self:SetCarrier( NearUnit ) - break + return NearUnit:GetGroup() end end end + + return nil end @@ -135,7 +214,7 @@ end --- Follow Infantry to the Carrier. -- @param #AI_CARGO_APC self -- @param #AI_CARGO_APC Me --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier -- @param Wrapper.Group#GROUP InfantryGroup -- @return #AI_CARGO_APC function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) @@ -186,7 +265,7 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) @@ -195,32 +274,33 @@ function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) local Coordinate = CargoCarrier:GetCoordinate() self.Zone:Scan( { Object.Category.UNIT } ) if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - if self:Is( "Unloaded" ) or self:Is( "Guarding" ) or self:Is( "Following" ) then + if self:Is( "Unloaded" ) or self:Is( "Following" ) then -- There are no enemies within combat range. Load the CargoCarrier. - self:__Load( 1 ) + self:Load() end else if self:Is( "Loaded" ) then -- There are enemies within combat range. Unload the CargoCarrier. self:__Unload( 1 ) - end - end - if self:Is( "Guarding" ) then - if not self.CargoGroup:IsNear( CargoCarrier, 5 ) then - self:Follow() - end - end - if self:Is( "Following" ) then - local Distance = Coordinate:Get2DDistance( self.CargoGroup:GetCoordinate() ) - self:F( { Distance = Distance } ) - if Distance > 40 then - CargoCarrier:RouteStop() - self.CarrierStopped = true else - if self.CarrierStopped then - if self.CargoGroup:IsNear( CargoCarrier, 10 ) then - CargoCarrier:RouteResume() - self.CarrierStopped = nil + if self:Is( "Unloaded" ) then + if not self.Cargo:IsNear( CargoCarrier, 5 ) then + self:Follow() + end + end + if self:Is( "Following" ) then + local Distance = Coordinate:Get2DDistance( self.Cargo:GetCoordinate() ) + self:F( { Distance = Distance } ) + if Distance > 40 then + CargoCarrier:RouteStop() + self.CarrierStopped = true + else + if self.CarrierStopped then + if self.Cargo:IsNear( CargoCarrier, 10 ) then + CargoCarrier:RouteResume() + self.CarrierStopped = nil + end + end end end end @@ -236,66 +316,77 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_APC:onafterLoad( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC:onbeforeLoad( Carrier, From, Event, To ) + self:F( { Carrier, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteStop() - self:__Board( 10 ) - self.CargoGroup:Board( CargoCarrier, 10 ) + if Carrier and Carrier:IsAlive() then + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( Cargo ) + if Cargo:IsInLoadRadius( Carrier:GetCoordinate() ) then + self:F( "In radius" ) + Carrier:RouteStop() + self:__Board( 1, Cargo ) + Cargo:Board( Carrier:GetUnit(1), 25 ) + return true + end + end end + return false + end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_APC:onafterBoard( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC:onafterBoard( Carrier, From, Event, To, Cargo ) + self:F( { Carrier, From, Event, To, Cargo } ) - if CargoCarrier and CargoCarrier:IsAlive() then - self:F({ IsLoaded = self.CargoGroup:IsLoaded() } ) - if not self.CargoGroup:IsLoaded() then - self:__Board( 10 ) + if Carrier and Carrier:IsAlive() then + self:F({ IsLoaded = Cargo:IsLoaded() } ) + if not Cargo:IsLoaded() then + self:__Board( 10, Cargo ) else - self:__Loaded( 1 ) + self:__Loaded( 1, Cargo ) end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier -function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP CargoCarrier +function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To, Cargo ) + self:F( { CargoCarrier, From, Event, To, Cargo } ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteResume() + self.Cargo = Cargo end end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterUnload( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() - self.CargoGroup:UnBoard( ) + self.Cargo:UnBoard() self:__Unboard( 10 ) end end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) if CargoCarrier and CargoCarrier:IsAlive() then - if not self.CargoGroup:IsUnLoaded() then + if not self.Cargo:IsUnLoaded() then self:__Unboard( 10 ) else self:__Unloaded( 1 ) @@ -305,7 +396,7 @@ function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To ) end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterUnloaded( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) @@ -319,13 +410,13 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP CargoCarrier function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To ) self:F( { CargoCarrier, From, Event, To } ) self:F( "Follow" ) if CargoCarrier and CargoCarrier:IsAlive() then - self.CargoGroup.CargoSet:ForEach( + self.Cargo.CargoSet:ForEach( --- @param Core.Cargo#CARGO Cargo function( Cargo ) self:F( { "Follow", Cargo.CargoObject:GetName() } ) @@ -339,3 +430,66 @@ function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To ) end + +--- @param #AI_CARGO_APC +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC._Pickup( Carrier ) + + Carrier:F( { "AI_CARGO_APC._Pickup:", Carrier:GetName() } ) + + if Carrier:IsAlive() then + Carrier:__Load( 1 ) + end +end + + +--- @param #AI_CARGO_APC +-- @param Wrapper.Group#GROUP Carrier +function AI_CARGO_APC._Deploy( Carrier ) + + Carrier:F( { "AI_CARGO_APC._Deploy:", Carrier:GetName() } ) + + if Carrier:IsAlive() then + Carrier:__Unload( 1 ) + end +end + + + +--- @param #AI_CARGO_APC self +-- @param Wrapper.Group#GROUP Carrier +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_APC:onafterPickup( Carrier, From, Event, To, Coordinate, Speed ) + + if Carrier and Carrier:IsAlive() then + + self.RoutePickup = true + + Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + end + +end + + +--- @param #AI_CARGO_APC self +-- @param Wrapper.Group#GROUP Carrier +-- @param From +-- @param Event +-- @param To +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Speed +function AI_CARGO_APC:onafterDeploy( Carrier, From, Event, To, Coordinate, Speed ) + + if Carrier and Carrier:IsAlive() then + + self.RouteDeploy = true + + Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + end + +end + diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index 05afee6a4..ad502c322 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -24,7 +24,7 @@ AI_CARGO_HELICOPTER = { --- Creates a new AI_CARGO_HELICOPTER object. -- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param Core.Set#SET_CARGO CargoSet -- @param #number CombatRadius -- @return #AI_CARGO_HELICOPTER @@ -116,13 +116,13 @@ end --- Set the Carrier. -- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @return #AI_CARGO_HELICOPTER function AI_CARGO_HELICOPTER:SetCarrier( Helicopter ) local AICargo = self - self.Helicopter = Helicopter -- Wrapper.Unit#UNIT + self.Helicopter = Helicopter -- Wrapper.Group#GROUP self.Helicopter:SetState( self.Helicopter, "AI_CARGO_HELICOPTER", self ) self.RoutePickup = false @@ -173,7 +173,7 @@ end -- @param #AI_CARGO_HELICOPTER self -- @param Core.Point#COORDINATE Coordinate -- @param #number Radius --- @return Wrapper.Unit#UNIT NewCarrier +-- @return Wrapper.Group#GROUP NewCarrier function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius ) local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) @@ -183,18 +183,19 @@ function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius ) self:F({NearUnit=NearUnit}) if not NearUnit:GetState( NearUnit, "AI_CARGO_HELICOPTER" ) then local Attributes = NearUnit:GetDesc() - self:F({Desc=Attributes}) + self:F({Attributes=Attributes}) if NearUnit:HasAttribute( "Trucks" ) then - self:SetCarrier( NearUnit ) - break + return NearUnit:GetGroup() end end end + + return nil end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param From -- @param Event -- @param To @@ -221,7 +222,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param From -- @param Event -- @param To @@ -276,7 +277,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter -- @param From -- @param Event -- @param To @@ -331,7 +332,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinate ) if Helicopter and Helicopter:IsAlive() then @@ -339,7 +340,7 @@ function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinat for _, Cargo in pairs( self.CargoSet:GetSet() ) do if Cargo:IsInLoadRadius( Coordinate ) then self:__Board( 5 ) - Cargo:Board( Helicopter, 25 ) + Cargo:Board( Helicopter:GetUnit(1), 25 ) self.Cargo = Cargo break end @@ -349,7 +350,7 @@ function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinat end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -364,7 +365,7 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -374,7 +375,7 @@ end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -385,7 +386,7 @@ function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then @@ -399,7 +400,7 @@ function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To ) end --- @param #AI_CARGO_HELICOPTER self --- @param Wrapper.Unit#UNIT Helicopter +-- @param Wrapper.Group#GROUP Helicopter function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 446d58da4..6c2bbe033 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -566,14 +566,14 @@ do -- CARGO --- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded. -- @param #CARGO self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the CargoGroup is within the loading radius. function CARGO:IsInLoadRadius( Coordinate ) self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) self:T( Distance ) if Distance <= self.LoadRadius then return true @@ -586,14 +586,14 @@ do -- CARGO --- Check if the Cargo can report itself to be Boarded or Loaded. -- @param #CARGO self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo can report itself. function CARGO:IsInReportRadius( Coordinate ) self:F( { Coordinate } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) self:T( Distance ) if Distance <= self.LoadRadius then return true @@ -606,18 +606,18 @@ do -- CARGO --- Check if CargoCarrier is near the Cargo to be Loaded. -- @param #CARGO self - -- @param Core.Point#POINT_VEC2 PointVec2 + -- @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( PointVec2, NearRadius ) + function CARGO:IsNear( Coordinate, NearRadius ) --self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) if self.CargoObject:IsAlive() then - --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + --local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) --self:F( { CargoObjectName = self.CargoObject:GetName() } ) --self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) --self:F( { PointVec2 = PointVec2:GetVec2() } ) - local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) + local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) --self:F( Distance ) if Distance <= NearRadius then @@ -979,9 +979,9 @@ end function CARGO_PACKAGE:IsNear( CargoCarrier ) self:F() - local CargoCarrierPoint = CargoCarrier:GetPointVec2() + local CargoCarrierPoint = CargoCarrier:GetCoordinate() - local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() ) + local Distance = CargoCarrierPoint:Get2DDistance( self.CargoCarrier:GetCoordinate() ) self:T( Distance ) if Distance <= self.NearRadius then diff --git a/Moose Development/Moose/Cargo/CargoCrate.lua b/Moose Development/Moose/Cargo/CargoCrate.lua index 18c49a4db..7fc3a7293 100644 --- a/Moose Development/Moose/Cargo/CargoCrate.lua +++ b/Moose Development/Moose/Cargo/CargoCrate.lua @@ -166,14 +166,14 @@ do -- CARGO_CRATE --- Check if Cargo Crate is in the radius for the Cargo to be reported. -- @param #CARGO self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Crate is within the report radius. function CARGO_CRATE:IsInReportRadius( Coordinate ) --self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) --self:T( Distance ) if Distance <= self.LoadRadius then return true @@ -193,7 +193,7 @@ do -- CARGO_CRATE local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) --self:T( Distance ) if Distance <= self.NearRadius then return true diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index ab7addf54..d71c81a16 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -58,8 +58,9 @@ do -- CARGO_GROUP local WeightGroup = 0 - self.GroupName = CargoGroup:GetName() - self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) ) + local GroupName = CargoGroup:GetName() + local CargoName = GroupName:match("(.*)~CARGO") or GroupName + self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) ) CargoGroup:Destroy() @@ -67,11 +68,11 @@ do -- CARGO_GROUP for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) - local GroupName = env.getValueDictByKey( GroupTemplate.name ) + --local GroupName = env.getValueDictByKey( GroupTemplate.name ) -- We create a new group object with one unit... -- First we prepare the template... - GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID + GroupTemplate.name = CargoName .. "#CARGO#" .. UnitID GroupTemplate.groupId = nil GroupTemplate.units = {} GroupTemplate.units[1] = UnitTemplate @@ -442,7 +443,7 @@ do -- CARGO_GROUP --- Check if Cargo Group is in the radius for the Cargo to be Boarded. -- @param #CARGO_GROUP self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Group is within the load radius. function CARGO_GROUP:IsInLoadRadius( Coordinate ) --self:F( { Coordinate } ) @@ -452,12 +453,12 @@ do -- CARGO_GROUP if Cargo then local Distance = 0 if Cargo:IsLoaded() then - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoCarrier:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( Cargo.CargoCarrier:GetCoordinate() ) else - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() ) end - --self:T( Distance ) + self:F( { Distance = Distance, LoadRadius = self.LoadRadius } ) if Distance <= self.LoadRadius then return true else @@ -480,9 +481,10 @@ do -- CARGO_GROUP local Cargo = self.CargoSet:GetFirst() -- #CARGO if Cargo then + self:F( { Cargo } ) local Distance = 0 if Cargo:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() ) --self:T( Distance ) if Distance <= self.LoadRadius then return true diff --git a/Moose Development/Moose/Cargo/CargoSlingload.lua b/Moose Development/Moose/Cargo/CargoSlingload.lua index 642fde94f..cb7898175 100644 --- a/Moose Development/Moose/Cargo/CargoSlingload.lua +++ b/Moose Development/Moose/Cargo/CargoSlingload.lua @@ -119,14 +119,14 @@ do -- CARGO_SLINGLOAD --- Check if Cargo Crate is in the radius for the Cargo to be reported. -- @param #CARGO_SLINGLOAD self - -- @param Core.Point#Coordinate Coordinate + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Crate is within the report radius. function CARGO_SLINGLOAD:IsInReportRadius( Coordinate ) --self:F( { Coordinate, LoadRadius = self.LoadRadius } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) if Distance <= self.LoadRadius then return true end @@ -138,14 +138,14 @@ do -- CARGO_SLINGLOAD --- 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 + -- @param Core.Point#COORDINATE Coordinate -- @return #boolean true if the Cargo Slingload is within the loading radius. function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate ) --self:F( { Coordinate } ) local Distance = 0 if self:IsUnLoaded() then - Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) + Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() ) if Distance <= self.NearRadius then return true end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 318852cb1..d28d113a7 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -49,7 +49,7 @@ do -- CARGO_UNIT -- @return #CARGO_UNIT function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius ) local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT - self:F( { Type, Name, Weight, NearRadius } ) + self:I( { Type, Name, Weight, NearRadius } ) self:T( CargoUnit ) self.CargoObject = CargoUnit diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 262175514..6173a355b 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -284,7 +284,7 @@ do -- cargo TemplateName = env.getValueDictByKey( TemplateName ) - local Cargo = TemplateName:match( "#(CARGO)" ) + local Cargo = TemplateName:match( "~(CARGO)" ) return Cargo and Cargo == "CARGO" end @@ -293,6 +293,7 @@ do -- cargo -- @param #DATABASE self -- @return #DATABASE self function DATABASE:RegisterCargos() + for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do if self:IsCargo( CargoGroupName ) then @@ -300,11 +301,12 @@ do -- cargo local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)") local CargoName = CargoGroupName:match("(.*)~CARGO") local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?") - local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") - local LoadRadius = CargoParam and CargoParam:match( "RR=([%a%d]+),?") - local NearRadius = CargoParam and CargoParam:match( "NR=([%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]+),?") ) - CARGO_GROUP:New( CargoGroup, Type, Name or CargoName, LoadRadius, NearRadius ) + self:F({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius ) end end @@ -315,15 +317,17 @@ do -- cargo 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]+),?") + 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 - CARGO_SLINGLOAD:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius ) + self:F({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) else if Category == "CRATE" then - CARGO_CRATE:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius ) + self:F({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) + CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) end end end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index de1a81cfc..15d9cf436 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -274,21 +274,19 @@ do -- COORDINATE - --TODO: check this to replace - --- Calculate the distance from a reference @{DCSTypes#Vec2}. + --- Calculate the distance from a reference @{#COORDINATE}. -- @param #COORDINATE self - -- @param Dcs.DCSTypes#Vec2 Vec2Reference The reference @{DCSTypes#Vec2}. - -- @return Dcs.DCSTypes#Distance The distance from the reference @{DCSTypes#Vec2} in meters. - function COORDINATE:DistanceFromVec2( Vec2Reference ) - self:F2( Vec2Reference ) + -- @param #COORDINATE PointVec2Reference The reference @{#COORDINATE}. + -- @return Dcs.DCSTypes#Distance The distance from the reference @{#COORDINATE} in meters. + function COORDINATE:DistanceFromPointVec2( PointVec2Reference ) + self:F2( PointVec2Reference ) - local Distance = ( ( Vec2Reference.x - self.x ) ^ 2 + ( Vec2Reference.y - self.z ) ^2 ) ^0.5 + local Distance = ( ( PointVec2Reference.x - self.x ) ^ 2 + ( PointVec2Reference.z - self.z ) ^2 ) ^ 0.5 self:T2( Distance ) return Distance end - --- Add a Distance in meters from the COORDINATE orthonormal plane, with the given angle, and calculate the new COORDINATE. -- @param #COORDINATE self -- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters. diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 0b68255c5..c63a94af8 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1761,351 +1761,354 @@ function CONTROLLABLE:TaskRoute( Points ) return DCSTask end ---- (AIR + GROUND) Make the Controllable move to fly to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:RouteToVec2( Point, Speed ) - self:F2( { Point, Speed } ) +do -- Route methods - local ControllablePoint = self:GetUnit( 1 ):GetVec2() - - local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.y - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - ---- (AIR + GROUND) Make the Controllable move to a given point. --- @param #CONTROLLABLE self --- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. --- @param #number Speed The speed to travel. --- @return #CONTROLLABLE self -function CONTROLLABLE:RouteToVec3( Point, Speed ) - self:F2( { Point, Speed } ) - - local ControllableVec3 = self:GetUnit( 1 ):GetVec3() - - local PointFrom = {} - PointFrom.x = ControllableVec3.x - PointFrom.y = ControllableVec3.z - PointFrom.alt = ControllableVec3.y - PointFrom.alt_type = "BARO" - PointFrom.type = "Turning Point" - PointFrom.action = "Turning Point" - PointFrom.speed = Speed - PointFrom.speed_locked = true - PointFrom.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local PointTo = {} - PointTo.x = Point.x - PointTo.y = Point.z - PointTo.alt = Point.y - PointTo.alt_type = "BARO" - PointTo.type = "Turning Point" - PointTo.action = "Fly Over Point" - PointTo.speed = Speed - PointTo.speed_locked = true - PointTo.properties = { - ["vnav"] = 1, - ["scale"] = 0, - ["angle"] = 0, - ["vangle"] = 0, - ["steer"] = 2, - } - - - local Points = { PointFrom, PointTo } - - self:T3( Points ) - - self:Route( Points ) - - return self -end - - - ---- Make the controllable to follow a given route. --- @param #CONTROLLABLE self --- @param #table Route A table of Route Points. --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:Route( Route, DelaySeconds ) - self:F2( Route ) - - local DCSControllable = self:GetDCSObject() - if DCSControllable then - local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route. - self:SetTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1). - return self - end - - return nil -end - - ---- Stops the movement of the vehicle on the route. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE -function CONTROLLABLE:RouteStop() - self:F("RouteStop") + --- (AIR + GROUND) Make the Controllable move to fly to a given point. + -- @param #CONTROLLABLE self + -- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. + -- @param #number Speed The speed to travel. + -- @return #CONTROLLABLE self + function CONTROLLABLE:RouteToVec2( Point, Speed ) + self:F2( { Point, Speed } ) - local CommandStop = self:CommandStopRoute( true ) - self:SetCommand( CommandStop ) - -end - ---- Resumes the movement of the vehicle on the route. --- @param #CONTROLLABLE self --- @return #CONTROLLABLE -function CONTROLLABLE:RouteResume() - self:F("RouteResume") + local ControllablePoint = self:GetUnit( 1 ):GetVec2() - local CommandResume = self:CommandStopRoute( false ) - self:SetCommand( CommandResume ) - -end - ---- Make the GROUND Controllable to drive towards a specific point. --- @param #CONTROLLABLE self --- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. --- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. --- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right". --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:RouteGroundTo( ToCoordinate, Speed, Formation, DelaySeconds ) - - local FromCoordinate = self:GetCoordinate() - - local FromWP = FromCoordinate:WaypointGround() - local ToWP = ToCoordinate:WaypointGround( Speed, Formation ) - - self:Route( { FromWP, ToWP }, DelaySeconds ) - - return self -end - ---- Make the GROUND Controllable to drive towards a specific point using (only) roads. --- @param #CONTROLLABLE self --- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. --- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:RouteGroundOnRoad( ToCoordinate, Speed, DelaySeconds ) - - -- Current coordinate. - local FromCoordinate = self:GetCoordinate() - - -- Formation is set to on road. - local Formation="On Road" - - -- Path on road from current position to destination coordinate. - local path=FromCoordinate:GetPathOnRoad(ToCoordinate) - - -- Route, ground waypoints along roads. - local route={} - table.insert(route, FromCoordinate:WaypointGround(Speed, Formation)) - - -- Convert coordinates to ground waypoints and insert into table. - for _, coord in ipairs(path) do - table.insert(route, coord:WaypointGround(Speed, Formation)) - end - - -- Add the final coordinate because the final coordinate in path is last point on road. - local dist=ToCoordinate:Get2DDistance(path[#path]) - if dist>10 then - table.insert(route, ToCoordinate:WaypointGround(Speed, "Vee")) - end - - -- Route controllable to destination. - self:Route(route, DelaySeconds) - - return self -end - - ---- Make the AIR Controllable fly towards a specific point. --- @param #CONTROLLABLE self --- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. --- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type. --- @param Core.Point#COORDINATE.RoutePointType Type The route point type. --- @param Core.Point#COORDINATE.RoutePointAction Action The route point action. --- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. --- @param #number DelaySeconds Wait for the specified seconds before executing the Route. --- @return #CONTROLLABLE The CONTROLLABLE. -function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds ) - - local FromCoordinate = self:GetCoordinate() - local FromWP = FromCoordinate:WaypointAir() - - local ToWP = ToCoordinate:WaypointAir( AltType, Type, Action, Speed ) - - self:Route( { FromWP, ToWP }, DelaySeconds ) - - return self -end - - ---- (AIR + GROUND) Route the controllable to a given zone. --- The controllable final destination point can be randomized. --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param Core.Zone#ZONE Zone The zone where to route to. --- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. --- @param #number Speed The speed. --- @param Base#FORMATION Formation The formation string. -function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) - self:F2( Zone ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - local PointFrom = {} PointFrom.x = ControllablePoint.x PointFrom.y = ControllablePoint.y PointFrom.type = "Turning Point" - PointFrom.action = Formation or "Cone" - PointFrom.speed = 20 / 1.6 - - + PointFrom.action = "Turning Point" + PointFrom.speed = Speed + PointFrom.speed_locked = true + PointFrom.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local PointTo = {} - local ZonePoint - - if Randomize then - ZonePoint = Zone:GetRandomVec2() - else - ZonePoint = Zone:GetVec2() - end - - PointTo.x = ZonePoint.x - PointTo.y = ZonePoint.y + PointTo.x = Point.x + PointTo.y = Point.y PointTo.type = "Turning Point" - - if Formation then - PointTo.action = Formation - else - PointTo.action = "Cone" - end - - if Speed then - PointTo.speed = Speed - else - PointTo.speed = 20 / 1.6 - end - + PointTo.action = "Fly Over Point" + PointTo.speed = Speed + PointTo.speed_locked = true + PointTo.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local Points = { PointFrom, PointTo } - + self:T3( Points ) - + self:Route( Points ) - + return self end - - return nil -end - ---- (GROUND) Route the controllable to a given Vec2. --- A speed can be given in km/h. --- A given formation can be given. --- @param #CONTROLLABLE self --- @param #Vec2 Vec2 The Vec2 where to route to. --- @param #number Speed The speed. --- @param Base#FORMATION Formation The formation string. -function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation ) - - local DCSControllable = self:GetDCSObject() - - if DCSControllable then - - local ControllablePoint = self:GetVec2() - + + --- (AIR + GROUND) Make the Controllable move to a given point. + -- @param #CONTROLLABLE self + -- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format. + -- @param #number Speed The speed to travel. + -- @return #CONTROLLABLE self + function CONTROLLABLE:RouteToVec3( Point, Speed ) + self:F2( { Point, Speed } ) + + local ControllableVec3 = self:GetUnit( 1 ):GetVec3() + local PointFrom = {} - PointFrom.x = ControllablePoint.x - PointFrom.y = ControllablePoint.y + PointFrom.x = ControllableVec3.x + PointFrom.y = ControllableVec3.z + PointFrom.alt = ControllableVec3.y + PointFrom.alt_type = "BARO" PointFrom.type = "Turning Point" - PointFrom.action = Formation or "Cone" - PointFrom.speed = 20 / 1.6 - - + PointFrom.action = "Turning Point" + PointFrom.speed = Speed + PointFrom.speed_locked = true + PointFrom.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local PointTo = {} - - PointTo.x = Vec2.x - PointTo.y = Vec2.y + PointTo.x = Point.x + PointTo.y = Point.z + PointTo.alt = Point.y + PointTo.alt_type = "BARO" PointTo.type = "Turning Point" - - if Formation then - PointTo.action = Formation - else - PointTo.action = "Cone" - end - - if Speed then - PointTo.speed = Speed - else - PointTo.speed = 60 / 3.6 - end - + PointTo.action = "Fly Over Point" + PointTo.speed = Speed + PointTo.speed_locked = true + PointTo.properties = { + ["vnav"] = 1, + ["scale"] = 0, + ["angle"] = 0, + ["vangle"] = 0, + ["steer"] = 2, + } + + local Points = { PointFrom, PointTo } - + self:T3( Points ) - + self:Route( Points ) - + return self end + + + + --- Make the controllable to follow a given route. + -- @param #CONTROLLABLE self + -- @param #table Route A table of Route Points. + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:Route( Route, DelaySeconds ) + self:F2( Route ) + + local DCSControllable = self:GetDCSObject() + if DCSControllable then + local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route. + self:SetTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1). + return self + end + + return nil + end + + + --- Stops the movement of the vehicle on the route. + -- @param #CONTROLLABLE self + -- @return #CONTROLLABLE + function CONTROLLABLE:RouteStop() + self:F("RouteStop") + + local CommandStop = self:CommandStopRoute( true ) + self:SetCommand( CommandStop ) + + end + + --- Resumes the movement of the vehicle on the route. + -- @param #CONTROLLABLE self + -- @return #CONTROLLABLE + function CONTROLLABLE:RouteResume() + self:F("RouteResume") + + local CommandResume = self:CommandStopRoute( false ) + self:SetCommand( CommandResume ) + + end + + --- Make the GROUND Controllable to drive towards a specific point. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right". + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RouteGroundTo( ToCoordinate, Speed, Formation, DelaySeconds ) + + local FromCoordinate = self:GetCoordinate() + + local FromWP = FromCoordinate:WaypointGround() + local ToWP = ToCoordinate:WaypointGround( Speed, Formation ) + + self:Route( { FromWP, ToWP }, DelaySeconds ) + + return self + end + + --- Make the GROUND Controllable to drive towards a specific point using (only) roads. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RouteGroundOnRoad( ToCoordinate, Speed, DelaySeconds ) + + -- Current coordinate. + local FromCoordinate = self:GetCoordinate() + + -- Formation is set to on road. + local Formation="On Road" + + -- Path on road from current position to destination coordinate. + local path=FromCoordinate:GetPathOnRoad(ToCoordinate) + + -- Route, ground waypoints along roads. + local route={} + table.insert(route, FromCoordinate:WaypointGround(Speed, Formation)) + + -- Convert coordinates to ground waypoints and insert into table. + for _, coord in ipairs(path) do + table.insert(route, coord:WaypointGround(Speed, Formation)) + end + + -- Add the final coordinate because the final coordinate in path is last point on road. + local dist=ToCoordinate:Get2DDistance(path[#path]) + if dist>10 then + table.insert(route, ToCoordinate:WaypointGround(Speed, "Vee")) + end + + -- Route controllable to destination. + self:Route(route, DelaySeconds) + + return self + end + + + --- Make the AIR Controllable fly towards a specific point. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type. + -- @param Core.Point#COORDINATE.RoutePointType Type The route point type. + -- @param Core.Point#COORDINATE.RoutePointAction Action The route point action. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. + -- @return #CONTROLLABLE The CONTROLLABLE. + function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds ) + + local FromCoordinate = self:GetCoordinate() + local FromWP = FromCoordinate:WaypointAir() + + local ToWP = ToCoordinate:WaypointAir( AltType, Type, Action, Speed ) + + self:Route( { FromWP, ToWP }, DelaySeconds ) + + return self + end + + + --- (AIR + GROUND) Route the controllable to a given zone. + -- The controllable final destination point can be randomized. + -- A speed can be given in km/h. + -- A given formation can be given. + -- @param #CONTROLLABLE self + -- @param Core.Zone#ZONE Zone The zone where to route to. + -- @param #boolean Randomize Defines whether to target point gets randomized within the Zone. + -- @param #number Speed The speed. + -- @param Base#FORMATION Formation The formation string. + function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) + self:F2( Zone ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local ControllablePoint = self:GetVec2() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.y + PointFrom.type = "Turning Point" + PointFrom.action = Formation or "Cone" + PointFrom.speed = 20 / 1.6 + + + local PointTo = {} + local ZonePoint + + if Randomize then + ZonePoint = Zone:GetRandomVec2() + else + ZonePoint = Zone:GetVec2() + end + + PointTo.x = ZonePoint.x + PointTo.y = ZonePoint.y + PointTo.type = "Turning Point" + + if Formation then + PointTo.action = Formation + else + PointTo.action = "Cone" + end + + if Speed then + PointTo.speed = Speed + else + PointTo.speed = 20 / 1.6 + end + + local Points = { PointFrom, PointTo } + + self:T3( Points ) + + self:Route( Points ) + + return self + end + + return nil + end + + --- (GROUND) Route the controllable to a given Vec2. + -- A speed can be given in km/h. + -- A given formation can be given. + -- @param #CONTROLLABLE self + -- @param #Vec2 Vec2 The Vec2 where to route to. + -- @param #number Speed The speed. + -- @param Base#FORMATION Formation The formation string. + function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation ) + + local DCSControllable = self:GetDCSObject() + + if DCSControllable then + + local ControllablePoint = self:GetVec2() + + local PointFrom = {} + PointFrom.x = ControllablePoint.x + PointFrom.y = ControllablePoint.y + PointFrom.type = "Turning Point" + PointFrom.action = Formation or "Cone" + PointFrom.speed = 20 / 1.6 + + + local PointTo = {} + + PointTo.x = Vec2.x + PointTo.y = Vec2.y + PointTo.type = "Turning Point" + + if Formation then + PointTo.action = Formation + else + PointTo.action = "Cone" + end + + if Speed then + PointTo.speed = Speed + else + PointTo.speed = 60 / 3.6 + end + + local Points = { PointFrom, PointTo } + + self:T3( Points ) + + self:Route( Points ) + + return self + end + + return nil + end - return nil -end - +end -- Route methods -- Commands From 810d900d7eed50de5e6d3e7ace0d324f6eda25c7 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 2 May 2018 22:18:07 +0200 Subject: [PATCH 2/4] Working with Transporting mode on or off. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 369 ++++++++++++------ Moose Development/Moose/Cargo/Cargo.lua | 45 ++- Moose Development/Moose/Cargo/CargoGroup.lua | 249 ++++++++---- Moose Development/Moose/Cargo/CargoUnit.lua | 27 +- Moose Development/Moose/Core/Point.lua | 2 + .../Moose/Wrapper/Controllable.lua | 39 +- .../Moose/Wrapper/Positionable.lua | 9 + 7 files changed, 545 insertions(+), 195 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 68ffc7046..d5022f135 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -1,4 +1,4 @@ ---- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo). +--- **AI** -- (R2.3) - Models the intelligent transportation of infantry and other cargo. -- -- === -- @@ -12,14 +12,69 @@ -- @extends Core.Fsm#FSM_CONTROLLABLE ---- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE} +--- # AI\_CARGO\_APC class, extends @{Core.Base#BASE} -- -- === -- +-- AI\_CARGO\APC brings a dynamic cargo handling capability for AI groups. +-- +-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- +-- ## Cargo loading. +-- +-- The module will load automatically cargo when the APCs are within boarding or loading range. +-- The boarding or loading range is specified when the cargo is created in the simulation, and therefore, this range depends on the type of cargo +-- and the specified boarding range. +-- +-- ## Enemies nearby. +-- +-- When the APCs are approaching enemy units, something special is happening. +-- The APCs will stop moving, and the loaded infantry will unboard and follow the APCs and will help to defend the group. +-- The carrier will hold the route once the unboarded infantry is further than 50 meters from the APCs, +-- to ensure that the APCs are not too far away from the following running infantry. +-- Once all enemies are cleared, the infantry will board again automatically into the APCs. Once boarded, the APCs will follow its pre-defined route. +-- +-- A combat range needs to be specified in meters at the @{#AI_CARGO_APC.New}() method. +-- This combat range will trigger the unboarding of troops when enemies are within the combat range around the APCs. +-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit range (effectiveness) versus +-- vulnerability of the infantry. It all depends on the kind of enemies that are expected to be encountered. +-- A combat range of 350 meters to 500 meters has been proven to be the most effective and efficient. +-- +-- ## Infantry health. +-- +-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield. +-- As a result, the unboarding infantry is very _healthy_ every time it unboards. +-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter. +-- However, infantry that was destroyed when unboarded and following the APCs, won't be respawned again. Destroyed is destroyed. +-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance this has +-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every +-- time is not so much of an issue ... +-- +-- ## Control the APCs on the map. +-- +-- It is possible also as a human ground commander to influence the path of the APCs, by pointing a new path using the DCS user interface on the map. +-- In this case, the APCs will change the direction towards its new indicated route. However, there is a catch! +-- Once the APCs are near the enemy, and infantry is unboarded, the APCs won't be able to hold the route until the infantry could catch up. +-- The APCs will simply drive on and won't stop! This is a limitation in ED that prevents user actions being controlled by the scripting engine. +-- No workaround is possible on this. +-- +-- ## Cargo deployment. +-- +-- Using the @{#AI_CARGO_APC.Deploy}() method, you are able to direct the APCs towards a point on the battlefield to unboard/unload the cargo at the specific coordinate. +-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment. +-- +-- ## Cargo pickup. +-- +-- Using the @{#AI_CARGO_APC.Pickup}() method, you are able to direct the APCs towards a point on the battlefield to board/load the cargo at the specific coordinate. +-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment. +-- +-- +-- -- @field #AI_CARGO_APC AI_CARGO_APC = { ClassName = "AI_CARGO_APC", - Coordinate = nil -- Core.Point#COORDINATE, + Coordinate = nil, -- Core.Point#COORDINATE, + APC_Cargo = {}, } --- Creates a new AI_CARGO_APC object. @@ -45,7 +100,7 @@ function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) self:AddTransition( "Boarding", "Loaded", "Loaded" ) self:AddTransition( "Loaded", "Unload", "Unboarding" ) self:AddTransition( "Unboarding", "Unboard", "Unboarding" ) - self:AddTransition( "Unboarding", "Unloaded", "Unloaded" ) + self:AddTransition( { "Unboarding", "Unloaded" }, "Unloaded", "Unloaded" ) self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Follow", "Following" ) @@ -131,6 +186,7 @@ function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius ) self:__Monitor( 1 ) self:SetCarrier( CargoCarrier ) + self.Transporting = false return self end @@ -184,6 +240,11 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier ) end +function AI_CARGO_APC:IsTransporting() + + return self.Transporting == true +end + --- Find a free Carrier within a range. -- @param #AI_CARGO_APC self -- @param Core.Point#COORDINATE Coordinate @@ -214,18 +275,20 @@ end --- Follow Infantry to the Carrier. -- @param #AI_CARGO_APC self -- @param #AI_CARGO_APC Me --- @param Wrapper.Group#GROUP CargoCarrier --- @param Wrapper.Group#GROUP InfantryGroup +-- @param Wrapper.Unit#UNIT APCUnit +-- @param Cargo.CargoGroup#CARGO_GROUP Cargo -- @return #AI_CARGO_APC -function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) +function AI_CARGO_APC:FollowToCarrier( Me, APCUnit, CargoGroup ) + + local InfantryGroup = CargoGroup:GetGroup() self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } ) --if self:Is( "Following" ) then - if CargoCarrier:IsAlive() then + if APCUnit:IsAlive() then -- We check if the Cargo is near to the CargoCarrier. - if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then + if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", APCUnit, 25 ) ) then -- The Cargo does not need to follow the Carrier. Me:Guard() @@ -246,12 +309,12 @@ function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) self:F({FromGround=FromGround}) table.insert( Waypoints, FromGround ) - local ToCoord = CargoCarrier:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 ) + local ToCoord = APCUnit:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 ) local ToGround = ToCoord:WaypointGround( 10, "Diamond" ) self:F({ToGround=ToGround}) table.insert( Waypoints, ToGround ) - local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, CargoCarrier, InfantryGroup ) + local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, APCUnit, CargoGroup ) self:F({Waypoints = Waypoints}) local Waypoint = Waypoints[#Waypoints] @@ -265,40 +328,43 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterMonitor( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then + if APC and APC:IsAlive() then if self.CarrierCoordinate then - local Coordinate = CargoCarrier:GetCoordinate() - self.Zone:Scan( { Object.Category.UNIT } ) - if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then - if self:Is( "Unloaded" ) or self:Is( "Following" ) then - -- There are no enemies within combat range. Load the CargoCarrier. - self:Load() - end - else - if self:Is( "Loaded" ) then - -- There are enemies within combat range. Unload the CargoCarrier. - self:__Unload( 1 ) + if self:IsTransporting() then + local Coordinate = APC:GetCoordinate() + self.Zone:Scan( { Object.Category.UNIT } ) + if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then + if self:Is( "Unloaded" ) or self:Is( "Following" ) then + -- There are no enemies within combat range. Load the CargoCarrier. + self:Load() + end else - if self:Is( "Unloaded" ) then - if not self.Cargo:IsNear( CargoCarrier, 5 ) then + if self:Is( "Loaded" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + self:__Unload( 1 ) + else + if self:Is( "Unloaded" ) then self:Follow() end - end - if self:Is( "Following" ) then - local Distance = Coordinate:Get2DDistance( self.Cargo:GetCoordinate() ) - self:F( { Distance = Distance } ) - if Distance > 40 then - CargoCarrier:RouteStop() - self.CarrierStopped = true - else - if self.CarrierStopped then - if self.Cargo:IsNear( CargoCarrier, 10 ) then - CargoCarrier:RouteResume() - self.CarrierStopped = nil + if self:Is( "Following" ) then + for APCUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + if Cargo:IsAlive() then + if not Cargo:IsNear( APCUnit, 40 ) then + APCUnit:RouteStop() + self.CarrierStopped = true + else + if self.CarrierStopped then + if Cargo:IsNear( APCUnit, 25 ) then + APCUnit:RouteResume() + self.CarrierStopped = nil + end + end + end end end end @@ -307,7 +373,7 @@ function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To ) end end - self.CarrierCoordinate = CargoCarrier:GetCoordinate() + self.CarrierCoordinate = APC:GetCoordinate() end self:__Monitor( -5 ) @@ -316,25 +382,40 @@ end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC:onbeforeLoad( Carrier, From, Event, To ) - self:F( { Carrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if Carrier and Carrier:IsAlive() then - for _, Cargo in pairs( self.CargoSet:GetSet() ) do - local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( Cargo ) - if Cargo:IsInLoadRadius( Carrier:GetCoordinate() ) then - self:F( "In radius" ) - Carrier:RouteStop() - self:__Board( 1, Cargo ) - Cargo:Board( Carrier:GetUnit(1), 25 ) - return true + local Boarding = false + self.BoardingCount = 0 + + if APC and APC:IsAlive() then + self.APC_Cargo = {} + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsUnLoaded = Cargo:IsUnLoaded() } ) + if Cargo:IsUnLoaded() then + if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then + self:F( { "In radius", APCUnit:GetName() } ) + APC:RouteStop() + --Cargo:Ungroup() + Cargo:Board( APCUnit, 25 ) + self:__Board( 1, Cargo ) + Boarding = true + + -- So now this APCUnit has Cargo that is being loaded. + -- This will be used further in the logic to follow and to check cargo status. + self.APC_Cargo[APCUnit] = Cargo + break + end + end end end end - - return false + + return Boarding end @@ -348,147 +429,203 @@ function AI_CARGO_APC:onafterBoard( Carrier, From, Event, To, Cargo ) if not Cargo:IsLoaded() then self:__Board( 10, Cargo ) else - self:__Loaded( 1, Cargo ) + self:__Loaded( 1 ) end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To, Cargo ) - self:F( { CargoCarrier, From, Event, To, Cargo } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteResume() - self.Cargo = Cargo + local Loaded = true + + if APC and APC:IsAlive() then + for APCUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) + if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then + Loaded = false + end + end + end + if Loaded == true then + APC:RouteResume() + end + + return Loaded + end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterUnload( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterUnload( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) - if CargoCarrier and CargoCarrier:IsAlive() then - CargoCarrier:RouteStop() - self.Cargo:UnBoard() - self:__Unboard( 10 ) + if APC and APC:IsAlive() then + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + APC:RouteStop() + for _, Cargo in pairs( APCUnit:GetCargo() ) do + Cargo:UnBoard() + self:__Unboard( 10, Cargo ) + end + end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo ) + self:F( { APC, From, Event, To, Cargo:GetName() } ) - if CargoCarrier and CargoCarrier:IsAlive() then - if not self.Cargo:IsUnLoaded() then - self:__Unboard( 10 ) + if APC and APC:IsAlive() then + if not Cargo:IsUnLoaded() then + self:__Unboard( 10, Cargo ) else - self:__Unloaded( 1 ) + self:__Unloaded( 1, Cargo ) end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterUnloaded( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) + self:F( { APC, From, Event, To, Cargo:GetName() } ) - if CargoCarrier and CargoCarrier:IsAlive() then - self:Guard() - self.CargoCarrier = CargoCarrier - CargoCarrier:RouteResume() + local AllUnloaded = true + + --Cargo:Regroup() + + if APC and APC:IsAlive() then + for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do + local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO + self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) + if CargoCheck:IsUnLoaded() == false then + AllUnloaded = false + break + end + end + + if AllUnloaded == true then + self:Guard() + self.CargoCarrier = APC + self.APC_Cargo = {} + end end + self:F( { AllUnloaded = AllUnloaded } ) + return AllUnloaded + end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP CargoCarrier -function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To ) - self:F( { CargoCarrier, From, Event, To } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterFollow( APC, From, Event, To ) + self:F( { APC, From, Event, To } ) self:F( "Follow" ) - if CargoCarrier and CargoCarrier:IsAlive() then - self.Cargo.CargoSet:ForEach( - --- @param Core.Cargo#CARGO Cargo - function( Cargo ) - self:F( { "Follow", Cargo.CargoObject:GetName() } ) - if Cargo.CargoObject:IsAlive() == true then - self:F( { "Follow", Cargo.CargoObject:GetID() } ) - self:FollowToCarrier( self, CargoCarrier, Cargo.CargoObject:GetGroup() ) - end + if APC and APC:IsAlive() then + for APCUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + if Cargo:IsUnLoaded() then + self:FollowToCarrier( self, APCUnit, Cargo ) + APCUnit:RouteResume() end - ) + end end end --- @param #AI_CARGO_APC --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC._Pickup( Carrier ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC._Pickup( APC, self ) - Carrier:F( { "AI_CARGO_APC._Pickup:", Carrier:GetName() } ) + APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } ) - if Carrier:IsAlive() then - Carrier:__Load( 1 ) + if APC:IsAlive() then + self:Load() + self.Transporting = true end end --- @param #AI_CARGO_APC --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC._Deploy( Carrier ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC._Deploy( APC, self ) - Carrier:F( { "AI_CARGO_APC._Deploy:", Carrier:GetName() } ) + APC:F( { "AI_CARGO_APC._Deploy:", APC } ) - if Carrier:IsAlive() then - Carrier:__Unload( 1 ) + if APC:IsAlive() then + self:Unload() + self.Transporting = false end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier +-- @param Wrapper.Group#GROUP APC -- @param From -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterPickup( Carrier, From, Event, To, Coordinate, Speed ) +function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed ) - if Carrier and Carrier:IsAlive() then + if APC and APC:IsAlive() then - self.RoutePickup = true + if Coordinate then + self.RoutePickup = true + + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + + local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. - Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. + else + AI_CARGO_APC._Pickup( APC, self ) + end end end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier +-- @param Wrapper.Group#GROUP APC -- @param From -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterDeploy( Carrier, From, Event, To, Coordinate, Speed ) +function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed ) - if Carrier and Carrier:IsAlive() then + if APC and APC:IsAlive() then self.RouteDeploy = true - Carrier:RouteGroundOnRoad( Coordinate, Speed, 1 ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + + local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. + + APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. end end diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 6c2bbe033..215b1cba7 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -293,7 +293,41 @@ do -- CARGO local CargoFound = _DATABASE:FindCargo( CargoName ) return CargoFound - end + 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 @@ -431,7 +465,16 @@ do -- CARGO 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 diff --git a/Moose Development/Moose/Cargo/CargoGroup.lua b/Moose Development/Moose/Cargo/CargoGroup.lua index d71c81a16..c4712c10e 100644 --- a/Moose Development/Moose/Cargo/CargoGroup.lua +++ b/Moose Development/Moose/Cargo/CargoGroup.lua @@ -53,47 +53,47 @@ do -- CARGO_GROUP self:F( { Type, Name, LoadRadius } ) self.CargoSet = SET_CARGO:New() + self.CargoGroup = CargoGroup + self.Grouped = true + self.CargoUnitTemplate = {} self:SetDeployed( false ) local WeightGroup = 0 + self.CargoGroup:Destroy() + local GroupName = CargoGroup:GetName() - local CargoName = GroupName:match("(.*)~CARGO") or GroupName + self.CargoName = GroupName:match("(.*)~CARGO") or GroupName self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) ) + + local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate ) + GroupTemplate.name = self.CargoName .. "#CARGO" + GroupTemplate.groupId = nil - CargoGroup:Destroy() + GroupTemplate.units = {} - -- We iterate through the group template and for each unit in the template, we create a new group with one unit. for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do - - 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 = CargoName .. "#CARGO#" .. UnitID - GroupTemplate.groupId = nil - GroupTemplate.units = {} - GroupTemplate.units[1] = UnitTemplate - local UnitName = UnitTemplate.name .. "#CARGO" - GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO" - - - -- 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 ) + UnitTemplate.name = UnitTemplate.name .. "#CARGO" + local CargoUnitName = UnitTemplate.name + self.CargoUnitTemplate[CargoUnitName] = UnitTemplate + + GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName] + GroupTemplate.units[#GroupTemplate.units].unitId = nil -- And we register the spawned unit as part of the CargoSet. - local Unit = UNIT:FindByName( UnitName ) + local Unit = UNIT:Register( CargoUnitName ) --local WeightUnit = Unit:GetDesc().massEmpty --WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) - self.CargoSet:Add( UnitName, CargoUnit ) + local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10 ) + self.CargoSet:Add( CargoUnitName, CargoUnit ) end - + + -- Then we register the new group in the database + self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) self:SetWeight( WeightGroup ) self.CargoLimit = 10 @@ -112,13 +112,108 @@ do -- CARGO_GROUP return self 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 + 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:F("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:F( { 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:F( { "Regroup", GroupTemplate } ) + + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + end + + end + + --- @param #CARGO_GROUP self -- @param Core.Event#EVENTDATA EventData function CARGO_GROUP:OnEventCargoDead( EventData ) + self:I( EventData ) - local Destroyed = false + local Destroyed = false - if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then + 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 @@ -171,10 +266,10 @@ do -- CARGO_GROUP --- Enter Loaded State. -- @param #CARGO_GROUP self - -- @param Wrapper.Unit#UNIT CargoCarrier -- @param #string Event -- @param #string From -- @param #string To + -- @param Wrapper.Unit#UNIT CargoCarrier function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) --self:F( { From, Event, To, CargoCarrier, ...} ) @@ -187,6 +282,7 @@ do -- CARGO_GROUP --self.CargoObject:Destroy() self.CargoCarrier = CargoCarrier + self.CargoCarrier:AddCargo( self ) end @@ -244,14 +340,6 @@ do -- CARGO_GROUP end 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 - --- Enter UnBoarding State. -- @param #CARGO_GROUP self @@ -274,10 +362,12 @@ do -- CARGO_GROUP -- 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 ) - - Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) - Timer = Timer + 3 + if not Cargo:IsDestroyed() then + Cargo:__UnBoard( Timer, ToPointVec2, NearRadius ) + Timer = Timer + 3 + end end, { NearRadius } ) @@ -307,7 +397,7 @@ do -- CARGO_GROUP -- 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.current ) + self:T( { Cargo:GetName(), Cargo.current } ) if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then UnBoarded = false end @@ -362,6 +452,9 @@ do -- CARGO_GROUP end + self.CargoCarrier:RemoveCargo( self ) + self.CargoCarrier = nil + end @@ -371,8 +464,8 @@ do -- CARGO_GROUP -- @return #nil There is no valid Cargo in the CargoGroup. function CARGO_GROUP:GetCoordinate() self:F() - - local Cargo = self.CargoSet:GetFirst() + + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO if Cargo then return Cargo.CargoObject:GetCoordinate() @@ -387,26 +480,46 @@ do -- CARGO_GROUP -- @return #boolean false if the CargoGroup is dead. function CARGO_GROUP:IsAlive() - local Alive = true - - -- For each Cargo within the CargoSet, check if the Cargo is Alive. - -- 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. - self.CargoSet:ForEach( - function( Cargo ) - if self:IsLoaded() then - Alive = Alive == true and Cargo.CargoCarrier:IsAlive() - else - Alive = Alive == true and Cargo.CargoObject:IsAlive() - end - end - ) - - return Alive + 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 amount of cargo units in the 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 @@ -430,12 +543,16 @@ do -- CARGO_GROUP -- @return #boolean The Cargo is near to the Carrier. -- @return #nil The Cargo is not near to the Carrier. function CARGO_GROUP:IsNear( CargoCarrier, NearRadius ) - --self:F( {NearRadius = NearRadius } ) + self:F( {NearRadius = NearRadius } ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO - - if Cargo then - return Cargo:IsNear( CargoCarrier:GetCoordinate(), 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:F( "Near" ) + return true + end + end end return nil @@ -448,7 +565,7 @@ do -- CARGO_GROUP function CARGO_GROUP:IsInLoadRadius( Coordinate ) --self:F( { Coordinate } ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO if Cargo then local Distance = 0 @@ -478,7 +595,7 @@ do -- CARGO_GROUP function CARGO_GROUP:IsInReportRadius( Coordinate ) --self:F( { Coordinate } ) - local Cargo = self.CargoSet:GetFirst() -- #CARGO + local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO if Cargo then self:F( { Cargo } ) diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index d28d113a7..85b6ea6cc 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -146,13 +146,13 @@ do -- CARGO_UNIT local Distance = 5 if From == "UnBoarding" then - if self:IsNear( ToPointVec2, NearRadius ) then + --if self:IsNear( ToPointVec2, NearRadius ) then return true - else + --else - self:__UnBoarding( 1, ToPointVec2, NearRadius ) - end - return false + --self:__UnBoarding( 1, ToPointVec2, NearRadius ) + --end + --return false end end @@ -258,14 +258,17 @@ do -- CARGO_UNIT 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( -1, CargoCarrier, NearRadius ) @@ -295,7 +298,7 @@ do -- CARGO_UNIT else self:__Boarding( -1, CargoCarrier, NearRadius, ... ) self.RunCount = self.RunCount + 1 - if self.RunCount >= 60 then + if self.RunCount >= 40 then self.RunCount = 0 local Speed = 90 local Angle = 180 @@ -308,12 +311,15 @@ do -- CARGO_UNIT 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 ) + 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 ) @@ -367,6 +373,7 @@ do -- CARGO_UNIT if self.CargoObject then self:T("Destroying") self.CargoObject:Destroy() + --self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 ) end end diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 15d9cf436..c49f02994 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -893,11 +893,13 @@ do -- COORDINATE function COORDINATE:WaypointGround( Speed, Formation ) self:F2( { Formation, Speed } ) + local RoutePoint = {} RoutePoint.x = self.x RoutePoint.y = self.z RoutePoint.action = Formation or "" + --RoutePoint.formation_template = Formation and "" or nil RoutePoint.speed = ( Speed or 20 ) / 3.6 diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index c63a94af8..6f55ff3d6 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -359,7 +359,7 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime ) local Controller = self:_GetController() Controller:setTask( DCSTask ) else - BASE:E( DCSControllableName .. " is not alive anymore. Cannot set DCSTask " .. DCSTask ) + BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } ) end end @@ -1964,11 +1964,46 @@ do -- Route methods end -- Route controllable to destination. - self:Route(route, DelaySeconds) + self:Route( route, DelaySeconds ) return self end + + --- Make a task for a GROUND Controllable to drive towards a specific point using (only) roads. + -- @param #CONTROLLABLE self + -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. + -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @return Task + function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed ) + + -- Current coordinate. + local FromCoordinate = self:GetCoordinate() + + -- Formation is set to on road. + local Formation="On Road" + + -- Path on road from current position to destination coordinate. + local path=FromCoordinate:GetPathOnRoad( ToCoordinate ) + + -- Route, ground waypoints along roads. + local Route = {} + table.insert( Route, FromCoordinate:WaypointGround( Speed, Formation ) ) + + -- Convert coordinates to ground waypoints and insert into table. + for _, coord in ipairs(path) do + table.insert( Route, coord:WaypointGround( Speed, Formation ) ) + end + + -- Add the final coordinate because the final coordinate in path is last point on road. + local dist=ToCoordinate:Get2DDistance(path[#path]) + if dist>10 then + table.insert( Route, ToCoordinate:WaypointGround( Speed, "Vee" ) ) + end + + return Route + end + --- Make the AIR Controllable fly towards a specific point. -- @param #CONTROLLABLE self diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 2a6605bb9..d9308e8bb 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -808,6 +808,15 @@ function POSITIONABLE:AddCargo( Cargo ) return self end +--- Get all contained cargo. +-- @param #POSITIONABLE self +-- @return #POSITIONABLE +function POSITIONABLE:GetCargo() + return self.__.Cargo +end + + + --- Remove cargo. -- @param #POSITIONABLE self -- @param Core.Cargo#CARGO Cargo From 19b3dcec2194345a92d40fafbcc04f0897e8d542 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sun, 6 May 2018 07:36:58 +0200 Subject: [PATCH 3/4] # Conflicts: # Moose Development/Moose/AI/AI_Cargo_APC.lua # Moose Development/Moose/Wrapper/Controllable.lua --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 29 ++++--- .../Moose/AI/AI_Cargo_Helicopter.lua | 83 ++++++++++++++++--- .../Moose/Wrapper/Controllable.lua | 5 +- 3 files changed, 90 insertions(+), 27 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index d5022f135..be3b2b77e 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -395,7 +395,7 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) local APCUnit = APCUnit -- Wrapper.Unit#UNIT for _, Cargo in pairs( self.CargoSet:GetSet() ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( { IsUnLoaded = Cargo:IsUnLoaded() } ) + self:F( { IsUnLoaded = Cargo:IsUnLoaded(), Cargo:GetName(), APC:GetName() } ) if Cargo:IsUnLoaded() then if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then self:F( { "In radius", APCUnit:GetName() } ) @@ -420,12 +420,12 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To ) end --- @param #AI_CARGO_APC self --- @param Wrapper.Group#GROUP Carrier -function AI_CARGO_APC:onafterBoard( Carrier, From, Event, To, Cargo ) - self:F( { Carrier, From, Event, To, Cargo } ) +-- @param Wrapper.Group#GROUP APC +function AI_CARGO_APC:onafterBoard( APC, From, Event, To, Cargo ) + self:F( { APC, From, Event, To, Cargo } ) - if Carrier and Carrier:IsAlive() then - self:F({ IsLoaded = Cargo:IsLoaded() } ) + if APC and APC:IsAlive() then + self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), APC:GetName() } ) if not Cargo:IsLoaded() then self:__Board( 10, Cargo ) else @@ -445,7 +445,7 @@ function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To ) if APC and APC:IsAlive() then for APCUnit, Cargo in pairs( self.APC_Cargo ) do local Cargo = Cargo -- Cargo.Cargo#CARGO - self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) + self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), APC:GetName() } ) if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then Loaded = false end @@ -505,8 +505,9 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo ) --Cargo:Regroup() if APC and APC:IsAlive() then - for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do - local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO + for _, APCUnit in pairs( APC:GetUnits() ) do + local APCUnit = APCUnit -- Wrapper.Unit#UNIT + local CargoCheck = self.APC_Cargo[APCUnit] self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) if CargoCheck:IsUnLoaded() == false then AllUnloaded = false @@ -580,14 +581,15 @@ end -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed ) +-- @param #string EndPointFormation The formation at the end point of the action. +function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, EndPointFormation ) if APC and APC:IsAlive() then if Coordinate then self.RoutePickup = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) @@ -611,13 +613,14 @@ end -- @param To -- @param Core.Point#COORDINATE Coordinate -- @param #number Speed -function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed ) +-- @param #string EndPointFormation The formation at the end point of the action. +function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, EndPointFormation ) if APC and APC:IsAlive() then self.RouteDeploy = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self ) diff --git a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua index ad502c322..c993755ee 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Helicopter.lua @@ -333,19 +333,41 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinate ) +function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To, Coordinate ) + + local Boarding = false if Helicopter and Helicopter:IsAlive() then - for _, Cargo in pairs( self.CargoSet:GetSet() ) do - if Cargo:IsInLoadRadius( Coordinate ) then - self:__Board( 5 ) - Cargo:Board( Helicopter:GetUnit(1), 25 ) - self.Cargo = Cargo - break + self.BoardingCount = 0 + + if Helicopter and Helicopter:IsAlive() then + self.Helicopter_Cargo = {} + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( self.CargoSet:GetSet() ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsUnLoaded = Cargo:IsUnLoaded() } ) + if Cargo:IsUnLoaded() then + if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then + self:F( { "In radius", HelicopterUnit:GetName() } ) + --Cargo:Ungroup() + Cargo:Board( HelicopterUnit, 25 ) + self:__Board( 1, Cargo ) + Boarding = true + + -- So now this APCUnit has Cargo that is being loaded. + -- This will be used further in the logic to follow and to check cargo status. + self.Helicopter_Cargo[HelicopterUnit] = Cargo + break + end + end + end end end end + + return Boarding end @@ -366,11 +388,23 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To ) + + local Loaded = true if Helicopter and Helicopter:IsAlive() then + for HelicopterUnit, Cargo in pairs( self.APC_Cargo ) do + local Cargo = Cargo -- Cargo.Cargo#CARGO + self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } ) + if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then + Loaded = false + end + end + end + return Loaded + end @@ -379,9 +413,15 @@ end function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To ) if Helicopter and Helicopter:IsAlive() then - self.Cargo:UnBoard() - self:__Unboard( 10 ) + for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do + local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT + for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do + Cargo:UnBoard() + self:__Unboard( 10, Cargo ) + end + end end + end @@ -401,12 +441,31 @@ end --- @param #AI_CARGO_HELICOPTER self -- @param Wrapper.Group#GROUP Helicopter -function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To ) +function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To ) + + local AllUnloaded = true + + --Cargo:Regroup() if Helicopter and Helicopter:IsAlive() then - self.Helicopter = Helicopter + for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do + local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO + self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } ) + if CargoCheck:IsUnLoaded() == false then + AllUnloaded = false + break + end + end + + if AllUnloaded == true then + self.Helicopter = Helicopter + self.Helicopter_Cargo = {} + end end + self:F( { AllUnloaded = AllUnloaded } ) + return AllUnloaded + end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 6f55ff3d6..11809e47a 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1974,8 +1974,9 @@ do -- Route methods -- @param #CONTROLLABLE self -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #string EndPointFormation The formation to achieve at the end point. -- @return Task - function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed ) + function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, EndPointFormation ) -- Current coordinate. local FromCoordinate = self:GetCoordinate() @@ -1998,7 +1999,7 @@ do -- Route methods -- Add the final coordinate because the final coordinate in path is last point on road. local dist=ToCoordinate:Get2DDistance(path[#path]) if dist>10 then - table.insert( Route, ToCoordinate:WaypointGround( Speed, "Vee" ) ) + table.insert( Route, ToCoordinate:WaypointGround( Speed, EndPointFormation ) ) end return Route From dd636939bb075863a978af615462013fa208819a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Mon, 7 May 2018 06:11:58 +0200 Subject: [PATCH 4/4] Documentation and performance fix. --- Moose Development/Moose/AI/AI_Cargo_APC.lua | 3 + Moose Development/Moose/Cargo/Cargo.lua | 70 ++++++------------- Moose Development/Moose/Core/Point.lua | 14 ++-- .../Moose/Wrapper/Controllable.lua | 4 +- 4 files changed, 38 insertions(+), 53 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index be3b2b77e..424f81d9c 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -19,6 +19,9 @@ -- AI\_CARGO\APC brings a dynamic cargo handling capability for AI groups. -- -- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation. +-- The AI\_CARGO\APC module uses the @{Cargo} capabilities within the MOOSE framework. +-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\APC object recognize the cargo. +-- Please consult the @{Cargo} module for more information. -- -- ## Cargo loading. -- diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index 215b1cba7..8869a14cc 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -6,31 +6,11 @@ -- -- === -- --- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ): --- --- * CARGO_UNIT, represented by a @{Unit} in a singleton @{Group}: Cargo can be represented by a Unit in a Group. a CARGO_UNIT is representable... --- * CARGO_GROUP, represented by a @{Group}. A CARGO_GROUP is reportable... -- -- This module is still under construction, but is described above works already, and will keep working ... -- -- === -- --- # Demo Missions --- --- ### [CARGO Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CGO%20-%20Cargo) --- --- ### [CARGO Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CGO%20-%20Cargo) --- --- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases) --- --- === --- --- # YouTube Channel --- --- ### [CARGO YouTube Channel](https://www.youtube.com/watch?v=tM00lTlkpYs&list=PL7ZUrU4zZUl2zUTuKrLW5RsO9zLMqUtbf) --- --- === --- -- ### Author: **FlightControl** -- ### Contributions: -- @@ -172,11 +152,31 @@ do -- CARGO -- @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. - --- # (R2.1) CARGO class, extends @{Fsm#FSM_PROCESS} + --- # (R2.4) CARGO class, extends @{Fsm#FSM_PROCESS} -- -- The CARGO class 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. + -- 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_Plane#AI_CARGO_PLANE} 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. -- @@ -186,32 +186,8 @@ do -- CARGO -- * @{#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.Dead}( Controllable ): The cargo is dead. The cargo process will be ended. + -- * @{#CARGO.Destroyed}( Controllable ): The cargo is dead. The cargo process will be ended. -- - -- ## CARGO States: - -- - -- * **UnLoaded**: The cargo is unloaded from a carrier. - -- * **Boarding**: The cargo is currently boarding (= running) into a carrier. - -- * **Loaded**: The cargo is loaded into a carrier. - -- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier. - -- * **Dead**: The cargo is dead ... - -- * **End**: The process has come to an end. - -- - -- ## CARGO state transition methods: - -- - -- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state. - -- There are 2 moments when state transition methods will be called by the state machine: - -- - -- * **Leaving** the state. - -- The state transition method needs to start with the name **OnLeave + the name of the state**. - -- If the state transition method returns false, then the processing of the state transition will not be done! - -- If you want to change the behaviour of the AIControllable at this event, return false, - -- but then you'll need to specify your own logic using the AIControllable! - -- - -- * **Entering** the state. - -- The state transition method needs to start with the name **OnEnter + the name of the state**. - -- These state transition methods need to provide a return value, which is specified at the function description. - -- -- @field #CARGO CARGO = { ClassName = "CARGO", diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index c49f02994..79bacd0f6 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -942,11 +942,15 @@ do -- COORDINATE function COORDINATE:GetPathOnRoad(ToCoord) local Path={} local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z) - for i, v in ipairs(path) do - --self:E(v) - local coord=COORDINATE:NewFromVec2(v) - Path[#Path+1]=COORDINATE:NewFromVec2(v) - end + Path[#Path+1]=COORDINATE:NewFromVec2(path[1]) + Path[#Path+1]=COORDINATE:NewFromVec2(path[#path]) + -- I've removed this stuff because it severely slows down DCS in case of paths with a lot of segments. + -- Just the beginning and the end point is sufficient. +-- for i, v in ipairs(path) do +-- self:I(v) +-- local coord=COORDINATE:NewFromVec2(v) +-- Path[#Path+1]=COORDINATE:NewFromVec2(v) +-- end return Path end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 11809e47a..9667bd6fc 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -357,7 +357,9 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime ) local function SetTask( Controller, DCSTask ) if self and self:IsAlive() then local Controller = self:_GetController() + self:I( "Before SetTask" ) Controller:setTask( DCSTask ) + self:I( "After SetTask" ) else BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } ) end @@ -496,7 +498,7 @@ function CONTROLLABLE:SetTaskWaypoint( Waypoint, Task ) Waypoint.task = self:TaskCombo( { Task } ) - self:T3( { Waypoint.task } ) + self:F( { Waypoint.task } ) return Waypoint.task end