From 454c0e55435bb846309087e05d27898871b2455a Mon Sep 17 00:00:00 2001 From: FlightControl_Master Date: Wed, 4 Oct 2017 14:34:24 +0200 Subject: [PATCH] Progress --- Moose Development/Moose/Core/Database.lua | 119 +++++++ Moose Development/Moose/Core/Goal.lua | 5 +- Moose Development/Moose/Core/ZoneGoal.lua | 1 - .../Moose/Functional/ZoneCaptureCoalition.lua | 2 +- .../Moose/Tasking/Task_ZoneCapture.lua | 299 ++++++++++++++++++ 5 files changed, 422 insertions(+), 4 deletions(-) create mode 100644 Moose Development/Moose/Tasking/Task_ZoneCapture.lua diff --git a/Moose Development/Moose/Core/Database.lua b/Moose Development/Moose/Core/Database.lua index 81c8f13c5..f1a1aedd3 100644 --- a/Moose Development/Moose/Core/Database.lua +++ b/Moose Development/Moose/Core/Database.lua @@ -70,6 +70,8 @@ DATABASE = { NavPoints = {}, PLAYERSETTINGS = {}, ZONENAMES = {}, + HITS = {}, + DESTROYS = {}, } local _DATABASECoalition = @@ -104,6 +106,7 @@ function DATABASE:New() self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + self:HandleEvent( EVENTS.Hit, self.AccountHits ) self:HandleEvent( EVENTS.NewCargo ) self:HandleEvent( EVENTS.DeleteCargo ) @@ -722,6 +725,8 @@ function DATABASE:_EventOnDeadOrCrash( Event ) end end end + + self:AccountDestroys( Event ) end @@ -1053,6 +1058,120 @@ function DATABASE:_RegisterTemplates() return self end + --- Account the Hits of the Players. + -- @param #DATABASE self + -- @param Core.Event#EVENTDATA Event + function DATABASE:AccountHits( Event ) + self:F( { Event } ) + + if Event.IniPlayerName ~= nil then -- It is a player that is hitting something + self:T( "Hitting Something" ) + + -- What is he hitting? + if Event.TgtCategory then + + -- A target got hit + self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {} + local Hit = self.HITS[Event.TgtUnitName] + + Hit.Players = Hit.Players or {} + Hit.Players[Event.IniPlayerName] = true + end + end + + -- It is a weapon initiated by a player, that is hitting something + -- This seems to occur only with scenery and static objects. + if Event.WeaponPlayerName ~= nil then + self:T( "Hitting Scenery" ) + + -- What is he hitting? + if Event.TgtCategory then + + if Event.IniCoalition then -- A coalition object was hit, probably a static. + -- A target got hit + self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {} + local Hit = self.HITS[Event.TgtUnitName] + + Hit.Players = Hit.Players or {} + Hit.Players[Event.WeaponPlayerName] = true + else -- A scenery object was hit. + end + end + end + end + + --- Account the destroys. + -- @param #DATABASE self + -- @param Core.Event#EVENTDATA Event + function DATABASE:AccountDestroys( Event ) + self:F( { Event } ) + + local TargetUnit = nil + local TargetGroup = nil + local TargetUnitName = "" + local TargetGroupName = "" + local TargetPlayerName = "" + local TargetCoalition = nil + local TargetCategory = nil + local TargetType = nil + local TargetUnitCoalition = nil + local TargetUnitCategory = nil + local TargetUnitType = nil + + if Event.IniDCSUnit then + + TargetUnit = Event.IniUnit + TargetUnitName = Event.IniDCSUnitName + TargetGroup = Event.IniDCSGroup + TargetGroupName = Event.IniDCSGroupName + TargetPlayerName = Event.IniPlayerName + + TargetCoalition = Event.IniCoalition + --TargetCategory = TargetUnit:getCategory() + --TargetCategory = TargetUnit:getDesc().category -- Workaround + TargetCategory = Event.IniCategory + TargetType = Event.IniTypeName + + TargetUnitCoalition = _SCORINGCoalition[TargetCoalition] + TargetUnitCategory = _SCORINGCategory[TargetCategory] + TargetUnitType = TargetType + + self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) + end + + -- Player contains the score and reference data for the player. + for PlayerName, Player in pairs( self.Players ) do + if Player then -- This should normally not happen, but i'll test it anyway. + self:T( "Something got destroyed" ) + + -- Some variables + local InitUnitName = Player.UnitName + local InitUnitType = Player.UnitType + local InitCoalition = Player.UnitCoalition + local InitCategory = Player.UnitCategory + local InitUnitCoalition = _SCORINGCoalition[InitCoalition] + local InitUnitCategory = _SCORINGCategory[InitCategory] + + self:T( { InitUnitName, InitUnitType, InitUnitCoalition, InitCoalition, InitUnitCategory, InitCategory } ) + + local Destroyed = false + + -- What is the player destroying? + if self.HITS[TargetUnitName] then -- Was there a hit for this unit for this player before registered??? + + + self.DESTROYS[Event.TgtUnitName] = self.DESTROYS[Event.TgtUnitName] or {} + + local PlayerDestroys = self.DESTROYS[Event.TgtUnitName] + + if TargetCoalition then + PlayerDestroys = PlayerDestroys or {} + PlayerDestroys[PlayerName] = true + end + end + end + end + end diff --git a/Moose Development/Moose/Core/Goal.lua b/Moose Development/Moose/Core/Goal.lua index 67aa91930..d6f4d405b 100644 --- a/Moose Development/Moose/Core/Goal.lua +++ b/Moose Development/Moose/Core/Goal.lua @@ -200,7 +200,7 @@ do -- Goal -- @param #GOAL self -- @param #number Delay - self:AddTransition( "On", "Achieved", "Achieved" ) + self:AddTransition( "*", "Achieved", "Achieved" ) --- Achieved Handler OnBefore for GOAL -- @function [parent=#GOAL] OnBeforeAchieved @@ -230,10 +230,11 @@ do -- Goal self.AchievedScheduler = nil self:SetEventPriority( 5 ) - + return self end + --- @param #GOAL self -- @param From -- @param Event diff --git a/Moose Development/Moose/Core/ZoneGoal.lua b/Moose Development/Moose/Core/ZoneGoal.lua index 59d34ca94..d5f7b9dda 100644 --- a/Moose Development/Moose/Core/ZoneGoal.lua +++ b/Moose Development/Moose/Core/ZoneGoal.lua @@ -57,7 +57,6 @@ do -- Zone self.Zone = Zone -- Core.Zone#ZONE_BASE self.Goal = GOAL:New() - self.Goal:Start() do diff --git a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua index c80b409bc..2f3d17215 100644 --- a/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua +++ b/Moose Development/Moose/Functional/ZoneCaptureCoalition.lua @@ -58,7 +58,7 @@ do -- ZoneGoal --- @param #ZONE_CAPTURE_COALITION self function ZONE_CAPTURE_COALITION:onenterCaptured() - self:GetParent( self ):onenterCaptured() + self:GetParent( self, ZONE_CAPTURE_COALITION ).onenterCaptured( self ) self.Goal:Achieved() end diff --git a/Moose Development/Moose/Tasking/Task_ZoneCapture.lua b/Moose Development/Moose/Tasking/Task_ZoneCapture.lua new file mode 100644 index 000000000..5ee4e8c43 --- /dev/null +++ b/Moose Development/Moose/Tasking/Task_ZoneCapture.lua @@ -0,0 +1,299 @@ +--- **Tasking** - The TASK_Protect models tasks for players to protect or capture specific zones. +-- +-- ==== +-- +-- ### Author: **Sven Van de Velde (FlightControl)** +-- +-- ### Contributions: MillerTime +-- +-- ==== +-- +-- @module Task_Protect + +do -- TASK_ZONE_GOAL + + --- The TASK_ZONE_GOAL class + -- @type TASK_ZONE_GOAL + -- @field Core.ZoneGoal#ZONE_GOAL ZoneGoal + -- @extends Tasking.Task#TASK + + --- # TASK_ZONE_GOAL class, extends @{Task#TASK} + -- + -- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone. + -- The TASK_ZONE_GOAL is implemented using a @{Fsm#FSM_TASK}, and has the following statuses: + -- + -- * **None**: Start of the process + -- * **Planned**: The A2G task is planned. + -- * **Assigned**: The A2G task is assigned to a @{Group#GROUP}. + -- * **Success**: The A2G task is successfully completed. + -- * **Failed**: The A2G task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. + -- + -- ## Set the scoring of achievements in an A2G attack. + -- + -- Scoring or penalties can be given in the following circumstances: + -- + -- * @{#TASK_ZONE_GOAL.SetScoreOnDestroy}(): Set a score when a target in scope of the A2G attack, has been destroyed. + -- * @{#TASK_ZONE_GOAL.SetScoreOnSuccess}(): Set a score when all the targets in scope of the A2G attack, have been destroyed. + -- * @{#TASK_ZONE_GOAL.SetPenaltyOnFailed}(): Set a penalty when the A2G attack has failed. + -- + -- @field #TASK_ZONE_GOAL + TASK_ZONE_GOAL = { + ClassName = "TASK_ZONE_GOAL", + } + + --- Instantiates a new TASK_ZONE_GOAL. + -- @param #TASK_ZONE_GOAL self + -- @param Tasking.Mission#MISSION Mission + -- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal + -- @return #TASK_ZONE_GOAL self + function TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoal, TaskType, TaskBriefing ) + local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType, TaskBriefing ) ) -- #TASK_ZONE_GOAL + self:F() + + self.ZoneGoal = ZoneGoal + self.TaskType = TaskType + + local Fsm = self:GetUnitProcess() + + + Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "StartMonitoring", Rejected = "Reject" } ) + + Fsm:AddTransition( "Assigned", "StartMonitoring", "Monitoring" ) + Fsm:AddTransition( "Monitoring", "Monitor", "Monitoring", {} ) + Fsm:AddTransition( "Monitoring", "RouteToTarget", "Monitoring" ) + Fsm:AddProcess( "Monitoring", "RouteToZone", ACT_ROUTE_ZONE:New(), {} ) + + --Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" ) + --Fsm:AddTransition( "Accounted", "Success", "Success" ) + Fsm:AddTransition( "Rejected", "Reject", "Aborted" ) + Fsm:AddTransition( "Failed", "Fail", "Failed" ) + + self:SetTargetZone( self.ZoneGoal:GetZone() ) + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task#TASK_ZONE_GOAL Task + function Fsm:onafterStartMonitoring( TaskUnit, Task ) + self:E( { self } ) + self:__Protect( 0.1 ) + self:__RouteToTarget( 0.1 ) + end + + --- Monitor Loop + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task#TASK_ZONE_GOAL Task + function Fsm:onafterMonitor( TaskUnit, Task ) + self:E( { self } ) + self:__Protect( 15 ) + end + + --- Test + -- @param #FSM_PROCESS self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @param Tasking.Task_A2G#TASK_ZONE_GOAL Task + function Fsm:onafterRouteToTarget( TaskUnit, Task ) + self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } ) + -- Determine the first Unit from the self.TargetSetUnit + + if Task:GetTargetZone( TaskUnit ) then + self:__RouteToTargetZone( 0.1 ) + end + end + + return self + + end + + --- @param #TASK_ZONE_GOAL self + -- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal Engine. + function TASK_ZONE_GOAL:SetProtect( ZoneGoal ) + + self.ZoneGoal = ZoneGoal -- Core.ZoneGoal#ZONE_GOAL + end + + + + --- @param #TASK_ZONE_GOAL self + function TASK_ZONE_GOAL:GetPlannedMenuText() + return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.ZoneGoal:GetZoneName() .. " )" + end + + + --- @param #TASK_ZONE_GOAL self + -- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map. + -- @param Wrapper.Unit#UNIT TaskUnit + function TASK_ZONE_GOAL:SetTargetZone( TargetZone, TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteZone = ProcessUnit:GetProcess( "Monitoring", "RouteToZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE + ActRouteZone:SetZone( TargetZone ) + end + + + --- @param #TASK_ZONE_GOAL self + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map. + function TASK_ZONE_GOAL:GetTargetZone( TaskUnit ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + local ActRouteZone = ProcessUnit:GetProcess( "Monitoring", "RouteToZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE + return ActRouteZone:GetZone() + end + + function TASK_ZONE_GOAL:SetGoalTotal() + + self.GoalTotal = 1 + end + + function TASK_ZONE_GOAL:GetGoalTotal() + + return self.GoalTotal + end + +end + + +do -- TASK_CAPTURE_ZONE + + --- The TASK_CAPTURE_ZONE class + -- @type TASK_CAPTURE_ZONE + -- @field Set#SET_UNIT TargetSetUnit + -- @extends Tasking.TaskZoneGoal#TASK_ZONE_GOAL + + --- # TASK_CAPTURE_ZONE class, extends @{TaskZoneGoal#TASK_ZONE_GOAL} + -- + -- The TASK_CAPTURE_ZONE class defines an Suppression or Extermination of Air Defenses task for a human player to be executed. + -- These tasks are important to be executed as they will help to achieve air superiority at the vicinity. + -- + -- The TASK_CAPTURE_ZONE is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks + -- based on detected enemy ground targets. + -- + -- @field #TASK_CAPTURE_ZONE + TASK_CAPTURE_ZONE = { + ClassName = "TASK_CAPTURE_ZONE", + } + + --- Instantiates a new TASK_CAPTURE_ZONE. + -- @param #TASK_CAPTURE_ZONE self + -- @param Tasking.Mission#MISSION Mission + -- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal + -- @param #string TaskBriefing The briefing of the task. + -- @return #TASK_CAPTURE_ZONE self + function TASK_CAPTURE_ZONE:New( Mission, SetGroup, TaskName, ZoneGoal, TaskBriefing) + local self = BASE:Inherit( self, TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoal, "CAPTURE", TaskBriefing ) ) -- #TASK_CAPTURE_ZONE + self:F() + + Mission:AddTask( self ) + + self.TaskCoalition = ZoneGoal:GetCoalition() + self.TaskCoalitionName = ZoneGoal:GetCoalitionName() + self.TaskZoneName = self.ZoneGoal:GetZoneName() + + self:SetBriefing( + TaskBriefing or + "Capture zone " .. self.TaskZoneName .. "." + ) + + self:UpdateTaskInfo() + + return self + end + + --- Instantiates a new TASK_CAPTURE_ZONE. + -- @param #TASK_CAPTURE_ZONE self + function TASK_CAPTURE_ZONE:UpdateTaskInfo() + + + local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate() + self:SetInfo( "Coordinates", ZoneCoordinate, 0 ) + self:SetInfo( "Zone Name", self.TaskZoneName, 10 ) + self:SetInfo( "Zone Coalition", self.TaskCoalitionName, 11 ) + end + + function TASK_CAPTURE_ZONE:ReportOrder( ReportGroup ) + local Coordinate = self:GetInfo( "Coordinates" ) + --local Coordinate = self.TaskInfo.Coordinates.TaskInfoText + local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate ) + + return Distance + end + + + --- @param #TASK_CAPTURE_ZONE self + -- @param Wrapper.Unit#UNIT TaskUnit + function TASK_CAPTURE_ZONE:OnAfterGoal( From, Event, To, PlayerUnit, PlayerName ) + + self:E( { PlayerUnit = PlayerUnit } ) + + if self.ZoneGoal then + local ProtectCoalition = self.ZoneGoal:GetCoalition() + local TaskCoalition = self.Coalition + + self:E( { ProtectCoalition = ProtectCoalition, TaskCoalition = TaskCoalition } ) + + if ProtectCoalition ~= TaskCoalition then + self:Success() + end + end + + self:__Goal( -10, PlayerUnit, PlayerName ) + end + + --- Set a score when a target in scope of the A2G attack, has been destroyed . + -- @param #TASK_CAPTURE_ZONE self + -- @param #string PlayerName The name of the player. + -- @param #number Score The score in points to be granted when task process has been achieved. + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return #TASK_CAPTURE_ZONE + function TASK_CAPTURE_ZONE:SetScoreOnProgress( PlayerName, Score, TaskUnit ) + self:F( { PlayerName, Score, TaskUnit } ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + --ProcessUnit:AddScoreProcess( "Protecting", "ZoneGoal", "Captured", "Player " .. PlayerName .. " has SEADed a target.", Score ) + + return self + end + + --- Set a score when all the targets in scope of the A2G attack, have been destroyed. + -- @param #TASK_CAPTURE_ZONE self + -- @param #string PlayerName The name of the player. + -- @param #number Score The score in points. + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return #TASK_CAPTURE_ZONE + function TASK_CAPTURE_ZONE:SetScoreOnSuccess( PlayerName, Score, TaskUnit ) + self:F( { PlayerName, Score, TaskUnit } ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + ProcessUnit:AddScore( "Success", "The zone has been captured!", Score ) + + return self + end + + --- Set a penalty when the A2G attack has failed. + -- @param #TASK_CAPTURE_ZONE self + -- @param #string PlayerName The name of the player. + -- @param #number Penalty The penalty in points, must be a negative value! + -- @param Wrapper.Unit#UNIT TaskUnit + -- @return #TASK_CAPTURE_ZONE + function TASK_CAPTURE_ZONE:SetScoreOnFail( PlayerName, Penalty, TaskUnit ) + self:F( { PlayerName, Penalty, TaskUnit } ) + + local ProcessUnit = self:GetUnitProcess( TaskUnit ) + + ProcessUnit:AddScore( "Failed", "The zone has been lost!", Penalty ) + + return self + end + +end +