diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index 8c6491753..defb6bd81 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -60,57 +60,48 @@ end --- Follow Infantry to the Carrier. -- @param #AI_CARGO_TROOPS self +-- @param #AI_CARGO_TROOPS Me +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Wrapper.Group#GROUP InfantryGroup -- @return #AI_CARGO_TROOPS -function AI_CARGO_TROOPS:FollowToCarrier( Me ) +function AI_CARGO_TROOPS:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) - self = Me - - self:F( { self = self:GetClassNameAndID(), CargoGroup = self.CargoGroup:GetName() } ) + self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } ) -- We check if the Cargo is near to the CargoCarrier. - if self.CargoGroup:IsNear( self.CargoCarrier, 5 ) then + if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then -- The Cargo does not need to follow the Carrier. - self:Guard() + Me:Guard() else + + self:F( { InfantryGroup = InfantryGroup:GetName() } ) - -- The Cargo needs to continue to follow the Carrier. - if self:Is( "Following" ) then - - -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 - self.CargoGroup.CargoSet:ForEach( - --- @param Core.Cargo#CARGO Cargo - function( Cargo ) - local CargoUnit = Cargo.CargoObject -- Wrapper.Unit#UNIT - self:F( { UnitName = CargoUnit:GetName() } ) + if InfantryGroup:IsAlive() then - if CargoUnit:IsAlive() then - - local InfantryGroup = CargoUnit:GetGroup() - self:F( { GroupName = InfantryGroup:GetName() } ) - - local Waypoints = {} - - -- Calculate the new Route. - local FromCoord = InfantryGroup:GetCoordinate() - local FromGround = FromCoord:WaypointGround( 10, "Diamond" ) - table.insert( Waypoints, FromGround ) + self:F( { InfantryGroup = InfantryGroup:GetName() } ) - local ToCoord = self.CargoCarrier:GetCoordinate() - local ToGround = ToCoord:WaypointGround( 10, "Diamond" ) - table.insert( Waypoints, ToGround ) - - local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_TROOPS.FollowToCarrier", self ) - - self:F({Waypoints = Waypoints}) - local Waypoint = Waypoints[#Waypoints] - InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. - - InfantryGroup:Route( Waypoints ) -- Move after a random seconds to the Route. See the Route method for details. - end - end - ) + local Waypoints = {} + + -- Calculate the new Route. + local FromCoord = InfantryGroup:GetCoordinate() + local FromGround = FromCoord:WaypointGround( 10, "Diamond" ) + self:F({FromGround=FromGround}) + table.insert( Waypoints, FromGround ) + + local ToCoord = CargoCarrier:GetCoordinate() + local ToGround = ToCoord:WaypointGround( 10, "Diamond" ) + self:F({ToGround=ToGround}) + table.insert( Waypoints, ToGround ) + + local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_TROOPS.FollowToCarrier", Me, CargoCarrier, InfantryGroup ) + + self:F({Waypoints = Waypoints}) + local Waypoint = Waypoints[#Waypoints] + InfantryGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone. + + InfantryGroup:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details. end end end @@ -240,7 +231,16 @@ function AI_CARGO_TROOPS:onafterFollow( CargoCarrier, From, Event, To ) self:F( "Follow" ) if CargoCarrier and CargoCarrier:IsAlive() then - self:FollowToCarrier( self ) + self.CargoGroup.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 + end + ) end end diff --git a/Moose Development/Moose/Core/Cargo.lua b/Moose Development/Moose/Core/Cargo.lua index 4cc5eac2b..8cfa3037f 100644 --- a/Moose Development/Moose/Core/Cargo.lua +++ b/Moose Development/Moose/Core/Cargo.lua @@ -1,5 +1,7 @@ --- **Core** -- Management of CARGO logistics, that can be transported from and to transportation carriers. -- +-- === +-- -- ![Banner Image](..\Presentations\CARGO\Dia1.JPG) -- -- === @@ -163,7 +165,7 @@ do -- CARGO -- @field #string Name A string defining the name of the cargo. The name is the unique identifier of the cargo. -- @field #number Weight A number defining the weight of the cargo. The weight is expressed in kg. -- @field #number NearRadius (optional) A number defining the radius in meters when the cargo is near to a Carrier, so that it can be loaded. - -- @field Wrapper.Controllable#CONTROLLABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... + -- @field Wrapper.Unit#UNIT CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... -- @field Wrapper.Client#CLIENT CargoCarrier The alive DCS object carrying the cargo. This value can be nil, meaning, that the cargo is not contained anywhere... -- @field #boolean Slingloadable This flag defines if the cargo can be slingloaded. -- @field #boolean Moveable This flag defines if the cargo is moveable. @@ -259,7 +261,7 @@ function CARGO:New( Type, Name, Weight ) --R2.1 self.Name = Name self.Weight = Weight self.CargoObject = nil - self.CargoCarrier = nil + self.CargoCarrier = nil -- Wrapper.Client#CLIENT self.Representable = false self.Slingloadable = false self.Moveable = false @@ -607,23 +609,19 @@ end -- CARGO_REPRESENTABLE --- CARGO_REPORTABLE Constructor. -- @param #CARGO_REPORTABLE self - -- @param Wrapper.Controllable#Controllable CargoObject -- @param #string Type -- @param #string Name -- @param #number Weight -- @param #number ReportRadius (optional) -- @param #number NearRadius (optional) -- @return #CARGO_REPORTABLE - function CARGO_REPORTABLE:New( CargoObject, Type, Name, Weight, ReportRadius ) + function CARGO_REPORTABLE:New( Type, Name, Weight, ReportRadius ) local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight ) ) -- #CARGO_REPORTABLE self:F( { Type, Name, Weight, ReportRadius } ) self.CargoSet = SET_CARGO:New() -- Core.Set#SET_CARGO self.ReportRadius = ReportRadius or 1000 - self.CargoObject = CargoObject - - return self end @@ -773,11 +771,12 @@ do -- CARGO_UNIT -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - ToPointVec2 = ToPointVec2 or CargoRoutePointVec2 + ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, 5 ) local DirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3(ToPointVec2) local Angle = CargoCarrierPointVec2:GetAngleDegrees(DirectionVec3) - local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, Angle ) + local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, 5 ) local FromPointVec2 = CargoCarrierPointVec2 @@ -946,7 +945,7 @@ do -- CARGO_UNIT -- @param #string Event -- @param #string From -- @param #string To - -- @param Wrapper.Unit#UNIT CargoCarrier + -- @param Wrapper.Client#CLIENT CargoCarrier -- @param #number NearRadius function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } ) @@ -1157,56 +1156,81 @@ do -- CARGO_GROUP ClassName = "CARGO_GROUP", } - --- CARGO_GROUP constructor. - -- @param #CARGO_GROUP self - -- @param Wrapper.Group#GROUP CargoGroup - -- @param #string Type - -- @param #string Name - -- @param #number ReportRadius (optional) - -- @param #number NearRadius (optional) - -- @return #CARGO_GROUP - function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) - local self = BASE:Inherit( self, CARGO_REPORTABLE:New( CargoGroup, Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP - self:F( { Type, Name, ReportRadius } ) +--- CARGO_GROUP constructor. +-- This make a new CARGO_GROUP from a @{Group} object. +-- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects. +-- @param #CARGO_GROUP self +-- @param Wrapper.Group#GROUP CargoGroup +-- @param #string Type +-- @param #string Name +-- @param #number ReportRadius (optional) +-- @param #number NearRadius (optional) +-- @return #CARGO_GROUP +function CARGO_GROUP:New( CargoGroup, Type, Name, ReportRadius ) + local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, ReportRadius ) ) -- #CARGO_GROUP + self:F( { Type, Name, ReportRadius } ) + + self:SetDeployed( false ) - self.CargoObject = CargoGroup - self:SetDeployed( false ) - self.CargoGroup = CargoGroup - - local WeightGroup = 0 - - for UnitID, UnitData in pairs( CargoGroup:GetUnits() ) do - local Unit = UnitData -- Wrapper.Unit#UNIT - local WeightUnit = Unit:GetDesc().massEmpty - WeightGroup = WeightGroup + WeightUnit - local CargoUnit = CARGO_UNIT:New( Unit, Type, Unit:GetName(), WeightUnit ) - self.CargoSet:Add( CargoUnit:GetName(), CargoUnit ) - end + local WeightGroup = 0 + local GroupName = CargoGroup:GetName() - self:SetWeight( WeightGroup ) - - self:T( { "Weight Cargo", WeightGroup } ) + CargoGroup:Destroy() - -- Cargo objects are added to the _DATABASE and SET_CARGO objects. - _EVENTDISPATCHER:CreateEventNewCargo( self ) + -- 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( _DATABASE:GetGroupTemplate(GroupName).units ) do - self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) - self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + local GroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate(GroupName) ) + local GroupName = env.getValueDictByKey( GroupTemplate.name ) + self:E( GroupName ) - self:SetEventPriority( 4 ) + -- We create a new group object with one unit... + -- First we prepare the template... + GroupTemplate.name = GroupName .. "#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) - return self + -- Now we spawn the new group based on the template created. + _DATABASE:Spawn( GroupTemplate ) + + -- And we register the spawned unit as part of the CargoSet. + local Unit = UNIT:FindByName( UnitName ) + --local WeightUnit = Unit:GetDesc().massEmpty + --WeightGroup = WeightGroup + WeightUnit + local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 ) + self.CargoSet:Add( UnitName, CargoUnit ) end - --- @param #CARGO_GROUP self - -- @param Core.Event#EVENTDATA EventData - function CARGO_GROUP:OnEventCargoDead( EventData ) + + self:SetWeight( WeightGroup ) + + self:T( { "Weight Cargo", WeightGroup } ) + + -- Cargo objects are added to the _DATABASE and SET_CARGO objects. + _EVENTDISPATCHER:CreateEventNewCargo( self ) + + self:HandleEvent( EVENTS.Dead, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.Crash, self.OnEventCargoDead ) + self:HandleEvent( EVENTS.PlayerLeaveUnit, self.OnEventCargoDead ) + + self:SetEventPriority( 4 ) + + return self +end + +--- @param #CARGO_GROUP self +-- @param Core.Event#EVENTDATA EventData +function CARGO_GROUP:OnEventCargoDead( EventData ) + + local Destroyed = false - self:_F( { "Dead Event", EventData = EventData } ) - - local Destroyed = false - if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then Destroyed = true for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 0a787216a..0bb49c265 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -336,6 +336,18 @@ do -- COORDINATE end + --- Return a random Coordinate within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. + -- @param #COORDINATE self + -- @param Dcs.DCSTypes#Distance OuterRadius + -- @param Dcs.DCSTypes#Distance InnerRadius + -- @return #COORDINATE + function COORDINATE:GetRandomCoordinateInRadius( OuterRadius, InnerRadius ) + self:F2( { OuterRadius, InnerRadius } ) + + return COORDINATE:NewFromVec2( self:GetRandomVec2InRadius( OuterRadius, InnerRadius ) ) + end + + --- Return a random Vec3 within an Outer Radius and optionally NOT within an Inner Radius of the COORDINATE. -- @param #COORDINATE self -- @param Dcs.DCSTypes#Distance OuterRadius diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index f46c2701b..0606b14a0 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -336,7 +336,7 @@ end -- @param #number UnitNumber The number of the UNIT wrapper class to be returned. -- @return Wrapper.Unit#UNIT The UNIT wrapper class. function GROUP:GetUnit( UnitNumber ) - self:F2( { self.GroupName, UnitNumber } ) + self:E( { self.GroupName, UnitNumber } ) local DCSGroup = self:GetDCSObject() diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index 26d30ed91..9c0fcad57 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -193,10 +193,12 @@ end -- @param #number Heading The heading of the unit respawn. function UNIT:ReSpawn( SpawnVec3, Heading ) + self:T( self:Name() ) local SpawnGroupTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplateFromUnitName( self:Name() ) ) self:T( SpawnGroupTemplate ) local SpawnGroup = self:GetGroup() + self:T( { SpawnGroup = SpawnGroup } ) if SpawnGroup then @@ -221,7 +223,8 @@ function UNIT:ReSpawn( SpawnVec3, Heading ) end for UnitTemplateID, UnitTemplateData in pairs( SpawnGroupTemplate.units ) do - self:T( UnitTemplateData.name ) + self:T( { UnitTemplateData.name, self:Name() } ) + SpawnGroupTemplate.units[UnitTemplateID].unitId = nil if UnitTemplateData.name == self:Name() then self:T("Adjusting") SpawnGroupTemplate.units[UnitTemplateID].alt = SpawnVec3.y @@ -261,6 +264,10 @@ function UNIT:ReSpawn( SpawnVec3, Heading ) i = i + 1 end end + + SpawnGroupTemplate.groupId = nil + + self:T( SpawnGroupTemplate ) _DATABASE:Spawn( SpawnGroupTemplate ) end @@ -379,7 +386,7 @@ function UNIT:GetGroup() local DCSUnit = self:GetDCSObject() if DCSUnit then - local UnitGroup = GROUP:Find( DCSUnit:getGroup() ) + local UnitGroup = GROUP:FindByName( DCSUnit:getGroup():getName() ) return UnitGroup end