From 833705830691999ce3fe3b07a610a78140a1b8b0 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 26 Dec 2019 23:20:55 +0100 Subject: [PATCH] CAPTURE ZONE --- Moose Development/Moose/Core/Zone.lua | 69 +++- .../Moose/Functional/ZoneCaptureCoalition.lua | 355 +++++++++--------- .../Moose/Functional/ZoneGoal.lua | 9 +- .../Moose/Functional/ZoneGoalCoalition.lua | 3 + 4 files changed, 248 insertions(+), 188 deletions(-) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 9dedcb35a..07c93f7b9 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -685,30 +685,44 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories ) local function EvaluateZone( ZoneObject ) --if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5 - if ZoneObject then + if ZoneObject then + local ObjectCategory = ZoneObject:getCategory() - if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or - (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then + + if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isExist() and ZoneObject:isActive() ) or (ObjectCategory == Object.Category.STATIC and ZoneObject:isExist()) then + local CoalitionDCSUnit = ZoneObject:getCoalition() + local Include = false if not UnitCategories then + -- Anythink found is included. Include = true else + -- Check if found object is in specified categories. local CategoryDCSUnit = ZoneObject:getDesc().category + for UnitCategoryID, UnitCategory in pairs( UnitCategories ) do if UnitCategory == CategoryDCSUnit then Include = true break end end + end + if Include then + local CoalitionDCSUnit = ZoneObject:getCoalition() + + -- This coalition is inside the zone. self.ScanData.Coalitions[CoalitionDCSUnit] = true + self.ScanData.Units[ZoneObject] = ZoneObject + self:F2( { Name = ZoneObject:getName(), Coalition = CoalitionDCSUnit } ) end end + if ObjectCategory == Object.Category.SCENERY then local SceneryType = ZoneObject:getTypeName() local SceneryName = ZoneObject:getName() @@ -716,21 +730,29 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories ) self.ScanData.Scenery[SceneryType][SceneryName] = SCENERY:Register( SceneryName, ZoneObject ) self:F2( { SCENERY = self.ScanData.Scenery[SceneryType][SceneryName] } ) end + end + return true end + -- Search objects. world.searchObjects( ObjectCategories, SphereSearch, EvaluateZone ) end - +--- Count the number of different coalitions inside the zone. +-- @param #ZONE_RADIUS self +-- @return #table Table of DCS units and DCS statics inside the zone. function ZONE_RADIUS:GetScannedUnits() return self.ScanData.Units end +--- Count the number of different coalitions inside the zone. +-- @param #ZONE_RADIUS self +-- @return Core.Set#SET_UNIT Set of units and statics inside the zone. function ZONE_RADIUS:GetScannedSetUnit() local SetUnit = SET_UNIT:New() @@ -756,6 +778,9 @@ function ZONE_RADIUS:GetScannedSetUnit() end +--- Count the number of different coalitions inside the zone. +-- @param #ZONE_RADIUS self +-- @return #number Counted coalitions. function ZONE_RADIUS:CountScannedCoalitions() local Count = 0 @@ -763,14 +788,25 @@ function ZONE_RADIUS:CountScannedCoalitions() for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do Count = Count + 1 end + return Count end +--- Check if a certain coalition is inside a scanned zone. +-- @param #ZONE_RADIUS self +-- @param #number Coalition The coalition id, e.g. coalition.side.BLUE. +-- @return #boolean If true, the coalition is inside the zone. +function ZONE_RADIUS:CheckScannedCoalition( Coalition ) + if Coalition then + return self.ScanData.Coalitions[Coalition] + end + return nil +end --- Get Coalitions of the units in the Zone, or Check if there are units of the given Coalition in the Zone. --- Returns nil if there are none ot two Coalitions in the zone! +-- Returns nil if there are none to two Coalitions in the zone! -- Returns one Coalition if there are only Units of one Coalition in the Zone. --- Returns the Coalition for the given Coalition if there are units of the Coalition in the Zone +-- Returns the Coalition for the given Coalition if there are units of the Coalition in the Zone. -- @param #ZONE_RADIUS self -- @return #table function ZONE_RADIUS:GetScannedCoalition( Coalition ) @@ -795,20 +831,27 @@ function ZONE_RADIUS:GetScannedCoalition( Coalition ) end +--- Get scanned scenery type +-- @param #ZONE_RADIUS self +-- @return #table Table of DCS scenery type objects. function ZONE_RADIUS:GetScannedSceneryType( SceneryType ) return self.ScanData.Scenery[SceneryType] end +--- Get scanned scenery table +-- @param #ZONE_RADIUS self +-- @return #table Table of DCS scenery objects. function ZONE_RADIUS:GetScannedScenery() return self.ScanData.Scenery end --- Is All in Zone of Coalition? +-- Check if only the specifed coalition is inside the zone and noone else. -- @param #ZONE_RADIUS self --- @param Coalition --- @return #boolean +-- @param #number Coalition Coalition ID of the coalition which is checked to be the only one in the zone. +-- @return #boolean True, if **only** that coalition is inside the zone and no one else. -- @usage -- self.Zone:Scan() -- local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition ) @@ -820,11 +863,12 @@ end --- Is All in Zone of Other Coalition? +-- Check if only one coalition is inside the zone and the specified coalition is not the one. -- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated! -- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set. -- @param #ZONE_RADIUS self --- @param Coalition --- @return #boolean +-- @param #number Coalition Coalition ID of the coalition which is not supposed to be in the zone. +-- @return #boolean True, if and only if only one coalition is inside the zone and the specified coalition is not it. -- @usage -- self.Zone:Scan() -- local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition ) @@ -836,11 +880,12 @@ end --- Is Some in Zone of Coalition? +-- Check if more than one coaltion is inside the zone and the specifed coalition is one of them. -- You first need to use the @{#ZONE_RADIUS.Scan} method to scan the zone before it can be evaluated! -- Note that once a zone has been scanned, multiple evaluations can be done on the scan result set. -- @param #ZONE_RADIUS self --- @param Coalition --- @return #boolean +-- @param #number Coalition ID of the coaliton which is checked to be inside the zone. +-- @return #boolean True if more than one coalition is inside the zone and the specified coalition is one of them. -- @usage -- self.Zone:Scan() -- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition ) diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index 4ee91c93f..1615c70ff 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -197,8 +197,7 @@ do -- ZONE_CAPTURE_COALITION -- -- ### IMPORTANT -- - -- **Each capture zone object must have the monitoring process started specifically. - -- The monitoring process is NOT started by default!!!** + -- **Each capture zone object must have the monitoring process started specifically. The monitoring process is NOT started by default!** -- -- -- # Full Example @@ -554,175 +553,7 @@ do -- ZONE_CAPTURE_COALITION return self end - - --- @param #ZONE_CAPTURE_COALITION self - function ZONE_CAPTURE_COALITION:onenterCaptured() - - self:F({"hello"}) - - self:GetParent( self, ZONE_CAPTURE_COALITION ).onenterCaptured( self ) - - self.Goal:Achieved() - end - - - function ZONE_CAPTURE_COALITION:IsGuarded() - - local IsGuarded = self:IsAllInZoneOfCoalition( self.Coalition ) - self:F( { IsGuarded = IsGuarded } ) - return IsGuarded - end - - - function ZONE_CAPTURE_COALITION:IsEmpty() - - local IsEmpty = self:IsNoneInZone() - self:F( { IsEmpty = IsEmpty } ) - return IsEmpty - end - - - function ZONE_CAPTURE_COALITION:IsCaptured() - - local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition ) - self:F( { IsCaptured = IsCaptured } ) - return IsCaptured - end - - - function ZONE_CAPTURE_COALITION:IsAttacked() - - local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition ) - self:F( { IsAttacked = IsAttacked } ) - return IsAttacked - end - - - - --- Mark. - -- @param #ZONE_CAPTURE_COALITION self - function ZONE_CAPTURE_COALITION:Mark() - - local Coord = self:GetCoordinate() - local ZoneName = self:GetZoneName() - local State = self:GetState() - - if self.MarkRed and self.MarkBlue then - self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } ) - Coord:RemoveMark( self.MarkRed ) - Coord:RemoveMark( self.MarkBlue ) - end - - if self.Coalition == coalition.side.BLUE then - self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State ) - self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State ) - else - self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Red\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State ) - self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Red\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State ) - end - end - - --- Bound. - -- @param #ZONE_CAPTURE_COALITION self - function ZONE_CAPTURE_COALITION:onenterGuarded() - - --self:GetParent( self ):onenterGuarded() - - if self.Coalition == coalition.side.BLUE then - --elf.ProtectZone:BoundZone( 12, country.id.USA ) - else - --self.ProtectZone:BoundZone( 12, country.id.RUSSIA ) - end - - self:Mark() - - end - - function ZONE_CAPTURE_COALITION:onenterCaptured() - - --self:GetParent( self ):onenterCaptured() - - local NewCoalition = self:GetScannedCoalition() - self:F( { NewCoalition = NewCoalition } ) - self:SetCoalition( NewCoalition ) - - self:Mark() - self.Goal:Achieved() - end - - - function ZONE_CAPTURE_COALITION:onenterEmpty() - - --self:GetParent( self ):onenterEmpty() - - self:Mark() - end - - - function ZONE_CAPTURE_COALITION:onenterAttacked() - - --self:GetParent( self ):onenterAttacked() - - self:Mark() - end - - - --- When started, check the Coalition status. - -- @param #ZONE_CAPTURE_COALITION self - function ZONE_CAPTURE_COALITION:onafterGuard() - - --self:F({BASE:GetParent( self )}) - --BASE:GetParent( self ).onafterGuard( self ) - - if not self.SmokeScheduler then - self.SmokeScheduler = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 0.1, nil, self.StatusSmoke, self ) - end - end - - - function ZONE_CAPTURE_COALITION:IsCaptured() - - local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition ) - self:F( { IsCaptured = IsCaptured } ) - return IsCaptured - end - - - function ZONE_CAPTURE_COALITION:IsAttacked() - - local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition ) - self:F( { IsAttacked = IsAttacked } ) - return IsAttacked - end - - - --- Check status Coalition ownership. - -- @param #ZONE_CAPTURE_COALITION self - function ZONE_CAPTURE_COALITION:StatusZone() - - local State = self:GetState() - self:F( { State = self:GetState() } ) - - self:GetParent( self, ZONE_CAPTURE_COALITION ).StatusZone( self ) - - if State ~= "Guarded" and self:IsGuarded() then - self:Guard() - end - - if State ~= "Empty" and self:IsEmpty() then - self:Empty() - end - - if State ~= "Attacked" and self:IsAttacked() then - self:Attack() - end - - if State ~= "Captured" and self:IsCaptured() then - self:Capture() - end - - end --- Starts the zone capturing monitoring process. -- This process can be CPU intensive, ensure that you specify reasonable time intervals for the monitoring process. @@ -753,6 +584,7 @@ do -- ZONE_CAPTURE_COALITION if self.ScheduleStatusZone then self:ScheduleStop( self.ScheduleStatusZone ) end + self.ScheduleStatusZone = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 1.5, nil, self.StatusZone, self ) end @@ -812,7 +644,184 @@ do -- ZONE_CAPTURE_COALITION end end - - -end + + --- On after "Guard" event. + -- @param #ZONE_CAPTURE_COALITION self + function ZONE_CAPTURE_COALITION:onafterGuard() + + if not self.SmokeScheduler then + self.SmokeScheduler = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 0.1, nil, self.StatusSmoke, self ) + end + + end + + --- On enter "Guarded" state. + -- @param #ZONE_CAPTURE_COALITION self + function ZONE_CAPTURE_COALITION:onenterGuarded() + self:Mark() + end + + --- On enter "Captured" state. + -- @param #ZONE_CAPTURE_COALITION self + function ZONE_CAPTURE_COALITION:onenterCaptured() + + -- Get new coalition. + local NewCoalition = self:GetScannedCoalition() + self:F( { NewCoalition = NewCoalition } ) + + -- Set new owner of zone. + self:SetCoalition( NewCoalition ) + + -- Update mark. + self:Mark() + + -- Goal achieved. + self.Goal:Achieved() + end + + --- On enter "Empty" state. + -- @param #ZONE_CAPTURE_COALITION self + function ZONE_CAPTURE_COALITION:onenterEmpty() + self:Mark() + end + + --- On enter "Attacked" state. + -- @param #ZONE_CAPTURE_COALITION self + function ZONE_CAPTURE_COALITION:onenterAttacked() + self:Mark() + end + + + + --- Check if zone is "Guarded" + -- @param #ZONE_CAPTURE_COALITION self + -- @return #boolean self:IsAllInZoneOfCoalition( self.Coalition ) + function ZONE_CAPTURE_COALITION:IsGuarded() + + local IsGuarded = self:IsAllInZoneOfCoalition( self.Coalition ) + self:F( { IsGuarded = IsGuarded } ) + return IsGuarded + end + + --- Check if zone is "Empty" + -- @param #ZONE_CAPTURE_COALITION self + -- @return #boolean self:IsNoneInZone() + function ZONE_CAPTURE_COALITION:IsEmpty() + + local IsEmpty = self:IsNoneInZone() + self:F( { IsEmpty = IsEmpty } ) + return IsEmpty + end + + --- Check if zone is "Captured" + -- @param #ZONE_CAPTURE_COALITION self + -- @return #boolean self:IsAllInZoneOfOtherCoalition( self.Coalition ) + function ZONE_CAPTURE_COALITION:IsCaptured() + + local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition ) + self:F( { IsCaptured = IsCaptured } ) + return IsCaptured + end + + --- Check if zone is "Attacked" + -- @param #ZONE_CAPTURE_COALITION self + -- @return #boolean self:IsSomeInZoneOfCoalition( self.Coalition ) + function ZONE_CAPTURE_COALITION:IsAttacked() + + local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition ) + self:F( { IsAttacked = IsAttacked } ) + return IsAttacked + end + + + --- Check if zone is captured. + -- @param #ZONE_CAPTURE_COALITION self + -- @return #boolean self:IsAllInZoneOfOtherCoalition( self.Coalition ) + function ZONE_CAPTURE_COALITION:IsCaptured() + + local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition ) + self:F( { IsCaptured = IsCaptured } ) + return IsCaptured + end + + --- Check if zone is attacked. + -- @param #ZONE_CAPTURE_COALITION self + -- @return #boolean self:IsSomeInZoneOfCoalition( self.Coalition ) + function ZONE_CAPTURE_COALITION:IsAttacked() + + local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition ) + self:F( { IsAttacked = IsAttacked } ) + return IsAttacked + end + + + --- Check status Coalition ownership. + -- @param #ZONE_CAPTURE_COALITION self + function ZONE_CAPTURE_COALITION:StatusZone() + + -- Get FSM state. + local State = self:GetState() + + -- Scan zone in parent class ZONE_GOAL_COALITION + self:GetParent( self, ZONE_CAPTURE_COALITION ).StatusZone( self ) + + -- Check if zone is guarded. + if State ~= "Guarded" and self:IsGuarded() then + self:Guard() + end + + -- Check if zone is empty. + if State ~= "Empty" and self:IsEmpty() then + self:Empty() + end + + -- Check if zone is attacked. + if State ~= "Attacked" and self:IsAttacked() then + self:Attack() + end + + -- Check if zone is captured. + if State ~= "Captured" and self:IsCaptured() then + self:Capture() + end + + -- + local text=string.format("CAPTURE ZONE %s: Status %s", self:GetZoneName(), State) + + local NewState = self:GetState() + if NewState~=State then + text=text..string.format(" --> %s", NewState) + end + self:I(text) + + end + + --- Update Mark on F10 map. + -- @param #ZONE_CAPTURE_COALITION self + function ZONE_CAPTURE_COALITION:Mark() + + local Coord = self:GetCoordinate() + local ZoneName = self:GetZoneName() + local State = self:GetState() + + if self.MarkRed and self.MarkBlue then + self:F( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } ) + Coord:RemoveMark( self.MarkRed ) + Coord:RemoveMark( self.MarkBlue ) + end + + if self.Coalition == coalition.side.BLUE then + self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State ) + self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State ) + elseif self.Coalition == coalition.side.RED then + self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Red\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State ) + self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Red\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State ) + else + self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Neutral\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State ) + self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Neutral\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State ) + end + end + + +end diff --git a/Moose Development/Moose/Functional/ZoneGoal.lua b/Moose Development/Moose/Functional/ZoneGoal.lua index 67f6a872b..5a7e85397 100644 --- a/Moose Development/Moose/Functional/ZoneGoal.lua +++ b/Moose Development/Moose/Functional/ZoneGoal.lua @@ -17,10 +17,10 @@ do -- Zone --- @type ZONE_GOAL - -- @extends Core.Fsm#FSM + -- @extends Core.Zone#ZONE_RADIUS - -- Models processes that have a Goal with a defined achievement involving a Zone. + --- Models processes that have a Goal with a defined achievement involving a Zone. -- Derived classes implement the ways how the achievements can be realized. -- -- ## 1. ZONE_GOAL constructor @@ -39,7 +39,10 @@ do -- Zone -- -- @field #ZONE_GOAL ZONE_GOAL = { - ClassName = "ZONE_GOAL", + ClassName = "ZONE_GOAL", + Goal = nil, + SmokeTime = nil, + SmokeScheduler = nil, } --- ZONE_GOAL Constructor. diff --git a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua index 1de5218f3..0625aaae1 100644 --- a/Moose Development/Moose/Functional/ZoneGoalCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneGoalCoalition.lua @@ -38,6 +38,8 @@ do -- ZoneGoal -- @field #ZONE_GOAL_COALITION ZONE_GOAL_COALITION = { ClassName = "ZONE_GOAL_COALITION", + Coalition = nil, + } --- @field #table ZONE_GOAL_COALITION.States @@ -104,6 +106,7 @@ do -- ZoneGoal local State = self:GetState() self:F( { State = self:GetState() } ) + env.info("scanning") self:Scan( { Object.Category.UNIT, Object.Category.STATIC } ) end