From a247f56c7e8fed690884e284dfb48671bd1dec01 Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Sat, 7 Apr 2018 10:18:52 +0200 Subject: [PATCH] Progress on AI_CARGO_TROOPS --- .../Moose/AI/AI_Cargo_Troops.lua | 170 ++++++++++++++---- Moose Development/Moose/Cargo/Cargo.lua | 14 +- Moose Development/Moose/Cargo/CargoUnit.lua | 72 ++++---- Moose Development/Moose/Core/Zone.lua | 8 + Moose Development/Moose/Wrapper/Group.lua | 9 +- .../Moose/Wrapper/Identifiable.lua | 20 +++ Moose Development/Moose/Wrapper/Object.lua | 2 + 7 files changed, 215 insertions(+), 80 deletions(-) diff --git a/Moose Development/Moose/AI/AI_Cargo_Troops.lua b/Moose Development/Moose/AI/AI_Cargo_Troops.lua index 754409aeb..2051fa22d 100644 --- a/Moose Development/Moose/AI/AI_Cargo_Troops.lua +++ b/Moose Development/Moose/AI/AI_Cargo_Troops.lua @@ -24,19 +24,16 @@ AI_CARGO_TROOPS = { --- Creates a new AI_CARGO_TROOPS object. -- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup +-- @param #number CombatRadius -- @return #AI_CARGO_TROOPS function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) local self = BASE:Inherit( self, FSM_CONTROLLABLE:New( ) ) -- #AI_CARGO_TROOPS - self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT - self.CargoGroup = CargoGroup -- Core.Cargo#CARGO_GROUP + self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP self.CombatRadius = CombatRadius - - self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, CombatRadius ) - self.Coalition = self.CargoCarrier:GetCoalition() - - self:SetControllable( CargoCarrier ) self:SetStartState( "UnLoaded" ) @@ -50,14 +47,91 @@ function AI_CARGO_TROOPS:New( CargoCarrier, CargoGroup, CombatRadius ) self:AddTransition( "*", "Monitor", "*" ) self:AddTransition( "*", "Follow", "Following" ) self:AddTransition( "*", "Guard", "Guarding" ) + + self:AddTransition( "*", "Destroyed", "Destroyed" ) self:__Monitor( 1 ) - self:__Load( 1 ) + + self:SetCarrier( CargoCarrier ) return self end +--- Set the Carrier. +-- @param #AI_CARGO_TROOPS self +-- @param Wrapper.Unit#UNIT CargoCarrier +-- @return #AI_CARGO_TROOPS +function AI_CARGO_TROOPS:SetCarrier( CargoCarrier ) + + self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT + self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_TROOPS", self ) + + CargoCarrier:HandleEvent( EVENTS.Dead ) + CargoCarrier:HandleEvent( EVENTS.Hit ) + + function CargoCarrier:OnEventDead( EventData ) + self:F({"dead"}) + local AICargoTroops = self:GetState( self, "AI_CARGO_TROOPS" ) + self:F({AICargoTroops=AICargoTroops}) + if AICargoTroops then + self:F({}) + if not AICargoTroops:Is( "Loaded" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + AICargoTroops:Destroyed() + end + end + end + + function CargoCarrier:OnEventHit( EventData ) + self:F({"hit"}) + local AICargoTroops = self:GetState( self, "AI_CARGO_TROOPS" ) + if AICargoTroops then + self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } ) + if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then + -- There are enemies within combat range. Unload the CargoCarrier. + AICargoTroops:Unload() + end + end + end + + self.Zone = ZONE_UNIT:New( self.CargoCarrier:GetName() .. "-Zone", self.CargoCarrier, self.CombatRadius ) + self.Coalition = self.CargoCarrier:GetCoalition() + + self:SetControllable( CargoCarrier ) + + self:Guard() + + return self +end + + +--- Find a free Carrier within a range. +-- @param #AI_CARGO_TROOPS self +-- @param Core.Point#COORDINATE Coordinate +-- @param #number Radius +-- @return Wrapper.Unit#UNIT NewCarrier +function AI_CARGO_TROOPS:FindCarrier( Coordinate, Radius ) + + local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius ) + CoordinateZone:Scan( { Object.Category.UNIT } ) + for _, DCSUnit in pairs( CoordinateZone:GetScannedUnits() ) do + local NearUnit = UNIT:Find( DCSUnit ) + self:F({NearUnit=NearUnit}) + if not NearUnit:GetState( NearUnit, "AI_CARGO_TROOPS" ) then + local Attributes = NearUnit:GetDesc() + self:F({Desc=Attributes}) + if NearUnit:HasAttribute( "Trucks" ) then + self:SetCarrier( NearUnit ) + break + end + end + end + +end + + + --- Follow Infantry to the Carrier. -- @param #AI_CARGO_TROOPS self -- @param #AI_CARGO_TROOPS Me @@ -68,40 +142,44 @@ function AI_CARGO_TROOPS:FollowToCarrier( Me, CargoCarrier, InfantryGroup ) self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } ) - -- We check if the Cargo is near to the CargoCarrier. - if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then + --if self:Is( "Following" ) then - -- The Cargo does not need to follow the Carrier. - Me:Guard() + if CargoCarrier:IsAlive() then + -- We check if the Cargo is near to the CargoCarrier. + if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then - else + -- The Cargo does not need to follow the Carrier. + Me:Guard() - self:F( { InfantryGroup = InfantryGroup:GetName() } ) - - if InfantryGroup:IsAlive() then - + else + self:F( { InfantryGroup = InfantryGroup:GetName() } ) - - 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. + if InfantryGroup:IsAlive() then + + self:F( { InfantryGroup = InfantryGroup:GetName() } ) + + 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():GetRandomCoordinateInRadius( 10, 5 ) + 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 end @@ -132,6 +210,22 @@ function AI_CARGO_TROOPS:onafterMonitor( CargoCarrier, From, Event, To ) 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 + end + end + end + end + end self.CarrierCoordinate = CargoCarrier:GetCoordinate() end @@ -149,7 +243,7 @@ function AI_CARGO_TROOPS:onafterLoad( CargoCarrier, From, Event, To ) if CargoCarrier and CargoCarrier:IsAlive() then CargoCarrier:RouteStop() self:__Board( 10 ) - self.CargoGroup:Board( CargoCarrier, 100 ) + self.CargoGroup:Board( CargoCarrier, 10 ) end end diff --git a/Moose Development/Moose/Cargo/Cargo.lua b/Moose Development/Moose/Cargo/Cargo.lua index cdba0ec8f..eb44217a3 100644 --- a/Moose Development/Moose/Cargo/Cargo.lua +++ b/Moose Development/Moose/Cargo/Cargo.lua @@ -325,7 +325,7 @@ do -- CARGO -- @param #CARGO self function CARGO:Destroy() if self.CargoObject then - self.CargoObject:Destroy() + self.CargoObject:Destroy( false ) end self:Destroyed() end @@ -576,21 +576,23 @@ do -- CARGO -- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision). -- @return #boolean function CARGO:IsNear( PointVec2, NearRadius ) - self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } ) + self:F2( { PointVec2 = PointVec2, NearRadius = NearRadius } ) if self.CargoObject:IsAlive() then --local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() ) - self:F( { CargoObjectName = self.CargoObject:GetName() } ) - self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) - self:F( { PointVec2 = PointVec2:GetVec2() } ) + --self:F( { CargoObjectName = self.CargoObject:GetName() } ) + --self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } ) + --self:F( { PointVec2 = PointVec2:GetVec2() } ) local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() ) - self:T( Distance ) + --self:F( Distance ) if Distance <= NearRadius then + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } ) return true end end + self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } ) return false end diff --git a/Moose Development/Moose/Cargo/CargoUnit.lua b/Moose Development/Moose/Cargo/CargoUnit.lua index 5f6b4e941..2ba33aa4b 100644 --- a/Moose Development/Moose/Cargo/CargoUnit.lua +++ b/Moose Development/Moose/Cargo/CargoUnit.lua @@ -23,7 +23,7 @@ do -- CARGO_UNIT --- Models CARGO in the form of units, which can be boarded, unboarded, loaded, unloaded. -- @type CARGO_UNIT - -- @extends #CARGO_REPRESENTABLE + -- @extends Cargo.Cargo#CARGO_REPRESENTABLE --- # CARGO\_UNIT class, extends @{#CARGO_REPRESENTABLE} -- @@ -82,42 +82,48 @@ do -- CARGO_UNIT if not self:IsDestroyed() then local CargoCarrier = self.CargoCarrier -- Wrapper.Controllable#CONTROLLABLE - - local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() - local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. - local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - - - local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - - -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 - local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) - local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) - local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) - --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) - - ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) - - -- Respawn the group... - if self.CargoObject then - self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) - self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) - self.CargoCarrier = nil + if CargoCarrier:IsAlive() then - local Points = {} - - -- From - Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) - - -- To - Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) + local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() + local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees. + local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle ) - local TaskRoute = self.CargoObject:TaskRoute( Points ) - self.CargoObject:SetTask( TaskRoute, 1 ) - + + local CargoRoutePointVec2 = CargoCarrierPointVec2:Translate( RouteDistance, CargoDeployHeading ) - self:__UnBoarding( 1, ToPointVec2, NearRadius ) + + -- if there is no ToPointVec2 given, then use the CargoRoutePointVec2 + local FromDirectionVec3 = CargoCarrierPointVec2:GetDirectionVec3( ToPointVec2 or CargoRoutePointVec2 ) + local FromAngle = CargoCarrierPointVec2:GetAngleDegrees(FromDirectionVec3) + local FromPointVec2 = CargoCarrierPointVec2:Translate( DeployDistance, FromAngle ) + --local CargoDeployPointVec2 = CargoCarrierPointVec2:GetRandomCoordinateInRadius( 10, 5 ) + + ToPointVec2 = ToPointVec2 or CargoCarrierPointVec2:GetRandomCoordinateInRadius( NearRadius, DeployDistance ) + + -- Respawn the group... + if self.CargoObject then + self.CargoObject:ReSpawn( FromPointVec2:GetVec3(), CargoDeployHeading ) + self:F( { "CargoUnits:", self.CargoObject:GetGroup():GetName() } ) + self.CargoCarrier = nil + + local Points = {} + + -- From + Points[#Points+1] = FromPointVec2:WaypointGround( Speed, "Vee" ) + + -- To + Points[#Points+1] = ToPointVec2:WaypointGround( Speed, "Vee" ) + + local TaskRoute = self.CargoObject:TaskRoute( Points ) + self.CargoObject:SetTask( TaskRoute, 1 ) + + + self:__UnBoarding( 1, ToPointVec2, NearRadius ) + end + else + -- the Carrier is dead. This cargo is dead too! + self:Destroyed() end end end diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 72317d2ba..8c05d8a14 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -603,6 +603,7 @@ function ZONE_RADIUS:Scan( ObjectCategories ) self.ScanData = {} self.ScanData.Coalitions = {} self.ScanData.Scenery = {} + self.ScanData.Units = {} local ZoneCoord = self:GetCoordinate() local ZoneRadius = self:GetRadius() @@ -625,6 +626,7 @@ function ZONE_RADIUS:Scan( ObjectCategories ) (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then local CoalitionDCSUnit = ZoneObject:getCoalition() self.ScanData.Coalitions[CoalitionDCSUnit] = true + self.ScanData.Units[ZoneObject] = ZoneObject self:F( { Name = ZoneObject:getName(), Coalition = CoalitionDCSUnit } ) end if ObjectCategory == Object.Category.SCENERY then @@ -643,6 +645,12 @@ function ZONE_RADIUS:Scan( ObjectCategories ) end +function ZONE_RADIUS:GetScannedUnits() + + return self.ScanData.Units +end + + function ZONE_RADIUS:CountScannedCoalitions() local Count = 0 diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 26062ea09..23fd5da1a 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -239,14 +239,17 @@ end -- Note that this destroy method also raises a destroy event at run-time. -- So all event listeners will catch the destroy event of this DCS Group. -- @param #GROUP self -function GROUP:Destroy() +-- @param #boolean GenerateEvent +function GROUP:Destroy( GenerateEvent ) self:F2( self.GroupName ) local DCSGroup = self:GetDCSObject() if DCSGroup then - for Index, UnitData in pairs( DCSGroup:getUnits() ) do - self:CreateEventCrash( timer.getTime(), UnitData ) + if not GenerateEvent then + for Index, UnitData in pairs( DCSGroup:getUnits() ) do + self:CreateEventCrash( timer.getTime(), UnitData ) + end end USERFLAG:New( self:GetName() ):Set( 100 ) DCSGroup:destroy() diff --git a/Moose Development/Moose/Wrapper/Identifiable.lua b/Moose Development/Moose/Wrapper/Identifiable.lua index baa83eedb..edd123665 100644 --- a/Moose Development/Moose/Wrapper/Identifiable.lua +++ b/Moose Development/Moose/Wrapper/Identifiable.lua @@ -229,6 +229,26 @@ function IDENTIFIABLE:GetDesc() return nil end +--- Check if the Object has the attribute. +-- @param #IDENTIFIABLE self +-- @param #string AttributeName The attribute name. +-- @return #boolean true if the attribute exists. +-- @return #nil The DCS Identifiable is not existing or alive. +function IDENTIFIABLE:HasAttribute( AttributeName ) + self:F2( self.IdentifiableName ) + + local DCSIdentifiable = self:GetDCSObject() + + if DCSIdentifiable then + local IdentifiableHasAttribute = DCSIdentifiable:hasAttribute( AttributeName ) + self:T2( IdentifiableHasAttribute ) + return IdentifiableHasAttribute + end + + self:F( self.ClassName .. " " .. self.IdentifiableName .. " not found!" ) + return nil +end + --- Gets the CallSign of the IDENTIFIABLE, which is a blank by default. -- @param #IDENTIFIABLE self -- @return #string The CallSign of the IDENTIFIABLE. diff --git a/Moose Development/Moose/Wrapper/Object.lua b/Moose Development/Moose/Wrapper/Object.lua index fc3c11126..29901fd4b 100644 --- a/Moose Development/Moose/Wrapper/Object.lua +++ b/Moose Development/Moose/Wrapper/Object.lua @@ -91,3 +91,5 @@ end + +