From 2d178252681ee8f9073f82179166d8c03a729164 Mon Sep 17 00:00:00 2001 From: Sven Van de Velde Date: Wed, 3 Aug 2016 11:41:52 +0200 Subject: [PATCH] Progress --- Moose Development/Moose/Cargo.lua | 401 +++++++++++---------- Moose Development/Moose/Process_Pickup.lua | 173 +++++++++ Moose Development/Moose/Task_Pickup.lua | 137 +++++++ 3 files changed, 529 insertions(+), 182 deletions(-) create mode 100644 Moose Development/Moose/Process_Pickup.lua create mode 100644 Moose Development/Moose/Task_Pickup.lua diff --git a/Moose Development/Moose/Cargo.lua b/Moose Development/Moose/Cargo.lua index f4372934e..f02e61406 100644 --- a/Moose Development/Moose/Cargo.lua +++ b/Moose Development/Moose/Cargo.lua @@ -1,17 +1,227 @@ ---- CARGO Classes --- @module CARGO +--- This module contains the CARGO classes. +-- +-- === +-- +-- 1) @{Cargo#CARGO_BASE} class, extends @{Base#BASE} +-- ================================================== +-- The @{#CARGO_BASE} class defines the core functions that defines a cargo object within MOOSE. +-- A cargo is a logical object defined within a @{Mission}, that is available for transport, and has a life status within a simulation. +-- +-- Cargo can be of various forms: +-- +-- * CARGO_UNIT, represented by a @{Unit} in a @{Group}: Cargo can be represented by a Unit in a Group. Destruction of the Unit will mean that the cargo is lost. +-- * CARGO_STATIC, represented by a @{Static}: Cargo can be represented by a Static. Destruction of the Static will mean that the cargo is lost. +-- * CARGO_PACKAGE, contained in a @{Unit} of a @{Group}: Cargo can be contained within a Unit of a Group. The cargo can be **delivered** by the @{Unit}. If the Unit is destroyed, the cargo will be destroyed also. +-- * CARGO_PACKAGE, Contained in a @{Static}: Cargo can be contained within a Static. The cargo can be **collected** from the @Static. If the @{Static} is destroyed, the cargo will be destroyed. +-- * CARGO_SLINGLOAD, represented by a @{Cargo} that is transportable: Cargo can be represented by a Cargo object that is transportable. Destruction of the Cargo will mean that the cargo is lost. +-- +-- @module Cargo - - - - ---- Clients are those Groups defined within the Mission Editor that have the skillset defined as "Client" or "Player". --- These clients are defined within the Mission Orchestration Framework (MOF) - CARGOS = {} +--- @type CARGO +-- @field #string Type A string defining the type of the cargo. eg. Engineers, Equipment, Screwdrivers. +-- @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 ReportRadius (optional) A number defining the radius in meters when the cargo is signalling or reporting to a Carrier. +-- @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 Positionable#POSITIONABLE CargoObject The alive DCS object representing the cargo. This value can be nil, meaning, that the cargo is not represented anywhere... +-- @field Positionable#POSITIONABLE 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. +-- @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. +CARGO = { + ClassName = "CARGO", + STATUS = { + NONE = 0, + LOADED = 1, + UNLOADED = 2, + LOADING = 3 + }, + Type = nil, + Name = nil, + Weight = nil, + CargoObject = nil, + CargoCarrier = nil, + Representable = false, + Slingloadable = false, + Moveable = false, + Containable = false, +} + + +--- Add Cargo to the mission... +function CARGO:New( Mission, Type, Name, Weight, ReportRadius, NearRadius ) local self = BASE:Inherit( self, BASE:New() ) -- #CARGO + self:F( { Type, Name, Weight, ReportRadius, NearRadius } ) + + + self.Type = Type + self.Name = Name + self.Weight = Weight + self.ReportRadius = ReportRadius + self.NearRadius = NearRadius + self.CargoObject = nil + self.CargoCarrier = nil + self.Representable = false + self.Slingloadable = false + self.Moveable = false + self.Containable = false + + self:StatusNone() + + return self +end + +function CARGO:Spawn( PointVec2 ) + self:F() + + return self + +end + +function CARGO:Load( CargoObject, CargoCarrier ) + self:F() + + self:StatusLoaded( CargoCarrier ) + + return self +end + + +function CARGO:UnLoad( CargoCarrier, CargoObject ) + self:F() + + self:StatusUnLoaded( CargoObject ) + + return self +end + +function CARGO:OnBoard( CargoObject, CargoCarrier ) + self:F() + +end + +function CARGO:OnBoarded( CargoCarrier ) + self:F() + + local OnBoarded = false + + return OnBoarded +end + + +function CARGO:IsNear( CargoCarrier, CargoObject, Radius ) + self:F() + + local Near = true + + return Near + +end + + +function CARGO:IsLoading() + self:F() + + if self:IsStatusLoading() then + return self.Object + end + + return nil + +end + + +function CARGO:IsContained() + self:F() + + if self:IsStatusContained() then + return self.Object + end + + return nil + +end + + +function CARGO:IsLandingRequired() + self:F() + return true +end + +function CARGO:IsSlingLoad() + self:F() + return false +end + + +function CARGO:StatusNone() + self:F() + + self.CargoClient = nil + self.CargoStatus = CARGO.STATUS.NONE + + return self +end + +function CARGO:StatusLoading( Carrier ) + self:F() + + self.CargoClient = Carrier + self.CargoStatus = CARGO.STATUS.LOADING + self:T( "Cargo " .. self.CargoName .. " loading to Client: " .. self.CargoClient:GetClientGroupName() ) + + return self +end + +function CARGO:StatusLoaded( Client ) + self:F() + + self.CargoClient = Client + self.CargoStatus = CARGO.STATUS.LOADED + self:T( "Cargo " .. self.CargoName .. " loaded in Client: " .. self.CargoClient:GetClientGroupName() ) + + return self +end + +function CARGO:StatusUnLoaded() + self:F() + + self.CargoClient = nil + self.CargoStatus = CARGO.STATUS.UNLOADED + + return self +end + + +function CARGO:IsStatusNone() + self:F() + + return self.CargoStatus == CARGO.STATUS.NONE +end + +function CARGO:IsStatusLoading() + self:F() + + return self.CargoStatus == CARGO.STATUS.LOADING +end + +function CARGO:IsStatusLoaded() + self:F() + + return self.CargoStatus == CARGO.STATUS.LOADED +end + +function CARGO:IsStatusUnLoaded() + self:F() + + return self.CargoStatus == CARGO.STATUS.UNLOADED +end + + CARGO_ZONE = { ClassName="CARGO_ZONE", @@ -326,180 +536,7 @@ function CARGO_ZONE:GetCargoZoneName() return self.CargoZoneName end -CARGO = { - ClassName = "CARGO", - STATUS = { - NONE = 0, - LOADED = 1, - UNLOADED = 2, - LOADING = 3 - }, - CargoClient = nil -} ---- Add Cargo to the mission... Cargo functionality needs to be reworked a bit, so this is still under construction. I need to make a CARGO Class... -function CARGO:New( CargoType, CargoName, CargoWeight ) local self = BASE:Inherit( self, BASE:New() ) - self:F( { CargoType, CargoName, CargoWeight } ) - - - self.CargoType = CargoType - self.CargoName = CargoName - self.CargoWeight = CargoWeight - - self:StatusNone() - - return self -end - -function CARGO:Spawn( Client ) - self:F() - - return self - -end - -function CARGO:IsNear( Client, LandingZone ) - self:F() - - local Near = true - - return Near - -end - - -function CARGO:IsLoadingToClient() - self:F() - - if self:IsStatusLoading() then - return self.CargoClient - end - - return nil - -end - - -function CARGO:IsLoadedInClient() - self:F() - - if self:IsStatusLoaded() then - return self.CargoClient - end - - return nil - -end - - -function CARGO:UnLoad( Client, TargetZoneName ) - self:F() - - self:StatusUnLoaded() - - return self -end - -function CARGO:OnBoard( Client, LandingZone ) - self:F() - - local Valid = true - - self.CargoClient = Client - local ClientUnit = Client:GetClientGroupDCSUnit() - - return Valid -end - -function CARGO:OnBoarded( Client, LandingZone ) - self:F() - - local OnBoarded = true - - return OnBoarded -end - -function CARGO:Load( Client ) - self:F() - - self:StatusLoaded( Client ) - - return self -end - -function CARGO:IsLandingRequired() - self:F() - return true -end - -function CARGO:IsSlingLoad() - self:F() - return false -end - - -function CARGO:StatusNone() - self:F() - - self.CargoClient = nil - self.CargoStatus = CARGO.STATUS.NONE - - return self -end - -function CARGO:StatusLoading( Client ) - self:F() - - self.CargoClient = Client - self.CargoStatus = CARGO.STATUS.LOADING - self:T( "Cargo " .. self.CargoName .. " loading to Client: " .. self.CargoClient:GetClientGroupName() ) - - return self -end - -function CARGO:StatusLoaded( Client ) - self:F() - - self.CargoClient = Client - self.CargoStatus = CARGO.STATUS.LOADED - self:T( "Cargo " .. self.CargoName .. " loaded in Client: " .. self.CargoClient:GetClientGroupName() ) - - return self -end - -function CARGO:StatusUnLoaded() - self:F() - - self.CargoClient = nil - self.CargoStatus = CARGO.STATUS.UNLOADED - - return self -end - - -function CARGO:IsStatusNone() - self:F() - - return self.CargoStatus == CARGO.STATUS.NONE -end - -function CARGO:IsStatusLoading() - self:F() - - return self.CargoStatus == CARGO.STATUS.LOADING -end - -function CARGO:IsStatusLoaded() - self:F() - - return self.CargoStatus == CARGO.STATUS.LOADED -end - -function CARGO:IsStatusUnLoaded() - self:F() - - return self.CargoStatus == CARGO.STATUS.UNLOADED -end CARGO_GROUP = { diff --git a/Moose Development/Moose/Process_Pickup.lua b/Moose Development/Moose/Process_Pickup.lua new file mode 100644 index 000000000..968d1235d --- /dev/null +++ b/Moose Development/Moose/Process_Pickup.lua @@ -0,0 +1,173 @@ +--- @module Process_Pickup + +--- PROCESS_PICKUP class +-- @type PROCESS_PICKUP +-- @field Unit#UNIT ProcessUnit +-- @field Set#SET_UNIT TargetSetUnit +-- @extends Process#PROCESS +PROCESS_PICKUP = { + ClassName = "PROCESS_PICKUP", + Fsm = {}, + TargetSetUnit = nil, +} + + +--- Creates a new DESTROY process. +-- @param #PROCESS_PICKUP self +-- @param Task#TASK Task +-- @param Unit#UNIT ProcessUnit +-- @param Set#SET_UNIT TargetSetUnit +-- @return #PROCESS_PICKUP self +function PROCESS_PICKUP:New( Task, ProcessName, ProcessUnit ) + + -- Inherits from BASE + local self = BASE:Inherit( self, PROCESS:New( ProcessName, Task, ProcessUnit ) ) -- #PROCESS_PICKUP + + self.DisplayInterval = 30 + self.DisplayCount = 30 + self.DisplayMessage = true + self.DisplayTime = 10 -- 10 seconds is the default + self.DisplayCategory = "HQ" -- Targets is the default display category + + self.Fsm = STATEMACHINE_PROCESS:New( self, { + initial = 'Assigned', + events = { + { name = 'Start', from = 'Assigned', to = 'Navigating' }, + { name = 'Start', from = 'Navigating', to = 'Navigating' }, + { name = 'Nearby', from = 'Navigating', to = 'Preparing' }, + { name = 'Pickup', from = 'Preparing', to = 'Loading' }, + { name = 'Load', from = 'Loading', to = 'Success' }, + { name = 'Fail', from = 'Assigned', to = 'Failed' }, + { name = 'Fail', from = 'Navigating', to = 'Failed' }, + { name = 'Fail', from = 'Preparing', to = 'Failed' }, + }, + callbacks = { + onStart = self.OnStart, + onNearby = self.OnNearby, + onPickup = self.OnPickup, + onLoad = self.OnLoad, + }, + endstates = { 'Success', 'Failed' } + } ) + + return self +end + +--- Process Events + +--- StateMachine callback function for a PROCESS +-- @param #PROCESS_PICKUP self +-- @param StateMachine#STATEMACHINE_PROCESS Fsm +-- @param #string Event +-- @param #string From +-- @param #string To +function PROCESS_PICKUP:OnStart( Fsm, Event, From, To ) + + self:NextEvent( Fsm.Start ) +end + +--- StateMachine callback function for a PROCESS +-- @param #PROCESS_PICKUP self +-- @param StateMachine#STATEMACHINE_PROCESS Fsm +-- @param #string Event +-- @param #string From +-- @param #string To +function PROCESS_PICKUP:OnNavigating( Fsm, Event, From, To ) + + local TaskGroup = self.ProcessUnit:GetGroup() + if self.DisplayCount >= self.DisplayInterval then + MESSAGE:New( "Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed.", 5, "HQ" ):ToGroup( TaskGroup ) + self.DisplayCount = 1 + else + self.DisplayCount = self.DisplayCount + 1 + end + + return true -- Process always the event. + +end + + +--- StateMachine callback function for a PROCESS +-- @param #PROCESS_PICKUP self +-- @param StateMachine#STATEMACHINE_PROCESS Fsm +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Event#EVENTDATA Event +function PROCESS_PICKUP:OnHitTarget( Fsm, Event, From, To, Event ) + + + self.TargetSetUnit:Flush() + + if self.TargetSetUnit:FindUnit( Event.IniUnitName ) then + self.TargetSetUnit:RemoveUnitsByName( Event.IniUnitName ) + local TaskGroup = self.ProcessUnit:GetGroup() + MESSAGE:New( "You hit a target. Your group with assigned " .. self.Task:GetName() .. " task has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed.", 15, "HQ" ):ToGroup( TaskGroup ) + end + + + if self.TargetSetUnit:Count() > 0 then + self:NextEvent( Fsm.MoreTargets ) + else + self:NextEvent( Fsm.Destroyed ) + end +end + +--- StateMachine callback function for a PROCESS +-- @param #PROCESS_PICKUP self +-- @param StateMachine#STATEMACHINE_PROCESS Fsm +-- @param #string Event +-- @param #string From +-- @param #string To +function PROCESS_PICKUP:OnMoreTargets( Fsm, Event, From, To ) + + +end + +--- StateMachine callback function for a PROCESS +-- @param #PROCESS_PICKUP self +-- @param StateMachine#STATEMACHINE_PROCESS Fsm +-- @param #string Event +-- @param #string From +-- @param #string To +-- @param Event#EVENTDATA DCSEvent +function PROCESS_PICKUP:OnKilled( Fsm, Event, From, To ) + + self:NextEvent( Fsm.Restart ) + +end + +--- StateMachine callback function for a PROCESS +-- @param #PROCESS_PICKUP self +-- @param StateMachine#STATEMACHINE_PROCESS Fsm +-- @param #string Event +-- @param #string From +-- @param #string To +function PROCESS_PICKUP:OnRestart( Fsm, Event, From, To ) + + self:NextEvent( Fsm.Menu ) + +end + +--- StateMachine callback function for a PROCESS +-- @param #PROCESS_PICKUP self +-- @param StateMachine#STATEMACHINE_PROCESS Fsm +-- @param #string Event +-- @param #string From +-- @param #string To +function PROCESS_PICKUP:OnDestroyed( Fsm, Event, From, To ) + +end + +--- DCS Events + +--- @param #PROCESS_PICKUP self +-- @param Event#EVENTDATA Event +function PROCESS_PICKUP:EventDead( Event ) + + if Event.IniDCSUnit then + self:NextEvent( self.Fsm.HitTarget, Event ) + end +end + + diff --git a/Moose Development/Moose/Task_Pickup.lua b/Moose Development/Moose/Task_Pickup.lua new file mode 100644 index 000000000..cb73cb894 --- /dev/null +++ b/Moose Development/Moose/Task_Pickup.lua @@ -0,0 +1,137 @@ +--- This module contains the TASK_PICKUP classes. +-- +-- 1) @{#TASK_PICKUP} class, extends @{Task#TASK_BASE} +-- =================================================== +-- The @{#TASK_PICKUP} class defines a pickup task of a @{Set} of @{CARGO} objects defined within the mission. +-- based on the tasking capabilities defined in @{Task#TASK_BASE}. +-- The TASK_PICKUP is implemented using a @{Statemachine#STATEMACHINE_TASK}, and has the following statuses: +-- +-- * **None**: Start of the process +-- * **Planned**: The SEAD task is planned. Upon Planned, the sub-process @{Process_Assign#PROCESS_ASSIGN_ACCEPT} is started to accept the task. +-- * **Assigned**: The SEAD task is assigned to a @{Group#GROUP}. Upon Assigned, the sub-process @{Process_Route#PROCESS_ROUTE} is started to route the active Units in the Group to the attack zone. +-- * **Success**: The SEAD task is successfully completed. Upon Success, the sub-process @{Process_SEAD#PROCESS_SEAD} is started to follow-up successful SEADing of the targets assigned in the task. +-- * **Failed**: The SEAD task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ. +-- +-- === +-- +-- ### Authors: FlightControl - Design and Programming +-- +-- @module Task_PICKUP + + +do -- TASK_PICKUP + + --- The TASK_PICKUP class + -- @type TASK_PICKUP + -- @extends Task#TASK_BASE + TASK_PICKUP = { + ClassName = "TASK_PICKUP", + } + + --- Instantiates a new TASK_PICKUP. + -- @param #TASK_PICKUP self + -- @param Mission#MISSION Mission + -- @param Set#SET_GROUP AssignedSetGroup The set of groups for which the Task can be assigned. + -- @param #string TaskName The name of the Task. + -- @param #string TaskType BAI or CAS + -- @param Set#SET_UNIT UnitSetTargets + -- @param Zone#ZONE_BASE TargetZone + -- @return #TASK_PICKUP self + function TASK_PICKUP:New( Mission, AssignedSetGroup, TaskName, TaskType ) + local self = BASE:Inherit( self, TASK_BASE:New( Mission, AssignedSetGroup, TaskName, TaskType, "PICKUP" ) ) + self:F() + + _EVENTDISPATCHER:OnPlayerLeaveUnit( self._EventPlayerLeaveUnit, self ) + _EVENTDISPATCHER:OnDead( self._EventDead, self ) + _EVENTDISPATCHER:OnCrash( self._EventDead, self ) + _EVENTDISPATCHER:OnPilotDead( self._EventDead, self ) + + return self + end + + --- Removes a TASK_PICKUP. + -- @param #TASK_PICKUP self + -- @return #nil + function TASK_PICKUP:CleanUp() + + self:GetParent( self ):CleanUp() + + return nil + end + + + --- Assign the @{Task} to a @{Unit}. + -- @param #TASK_PICKUP self + -- @param Unit#UNIT TaskUnit + -- @return #TASK_PICKUP self + function TASK_PICKUP:AssignToUnit( TaskUnit ) + self:F( TaskUnit:GetName() ) + + local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN_ACCEPT:New( self, TaskUnit, self.TaskBriefing ) ) + local ProcessPickup = self:AddProcess( TaskUnit, PROCESS_PICKUP:New( self, self.TaskType, TaskUnit ) ) + + local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, TaskUnit, { + initial = 'None', + events = { + { name = 'Next', from = 'None', to = 'Planned' }, + { name = 'Next', from = 'Planned', to = 'Assigned' }, + { name = 'Next', from = 'Assigned', to = 'Success' }, + { name = 'Fail', from = 'Assigned', to = 'Failed' }, + }, + callbacks = { + onNext = self.OnNext, + }, + subs = { + Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Start', returnevents = { 'Next', 'Reject' } }, + Pickup = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessDestroy.Fsm, event = 'Start', returnevents = { 'Next' } }, + } + } ) ) + + ProcessRoute:AddScore( "Failed", "failed to destroy a ground unit", -100 ) + ProcessDestroy:AddScore( "Pickup", "Picked-Up a Cargo", 25 ) + ProcessDestroy:AddScore( "Failed", "failed to destroy a ground unit", -100 ) + + Process:Next() + + return self + end + + --- StateMachine callback function for a TASK + -- @param #TASK_PICKUP self + -- @param StateMachine#STATEMACHINE_TASK Fsm + -- @param #string Event + -- @param #string From + -- @param #string To + -- @param Event#EVENTDATA Event + function TASK_PICKUP:OnNext( Fsm, Event, From, To, Event ) + + self:SetState( self, "State", To ) + + end + + --- @param #TASK_PICKUP self + function TASK_PICKUP:GetPlannedMenuText() + return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )" + end + + + --- @param #TASK_PICKUP self + function TASK_PICKUP:_Schedule() + self:F2() + + self.TaskScheduler = SCHEDULER:New( self, _Scheduler, {}, 15, 15 ) + return self + end + + + --- @param #TASK_PICKUP self + function TASK_PICKUP._Scheduler() + self:F2() + + return true + end + +end + + +