Merge pull request #156 from FlightControl-Master/MR2-Solve-Garbage-Collection

Modified SCHEDULER, so that it gets garbage collected when the SCHEDULER is attached to an SchedulerObject that has been destroyed.

-- Modifed SCHEDULER
-- Created SCHEDULEDISPATCHER
-- New central MOOSE object _SCHEDULEDISPATCHER is created that dispatches the schedules.
-- Created the documentation.
-- Created various test mission for schedule testing and explanation.
This commit is contained in:
Sven Van de Velde 2016-12-14 11:13:01 +01:00 committed by GitHub
commit 14d592b8b9
94 changed files with 884 additions and 358 deletions

View File

@ -124,11 +124,15 @@ end
function BASE:_Destructor()
--self:E("_Destructor")
self:EventRemoveAll()
--self:EventRemoveAll()
end
function BASE:_SetDestructor()
-- TODO: Okay, this is really technical...
-- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
-- Therefore, I am parking this logic until I've properly discussed all this with the community.
--[[
local proxy = newproxy(true)
local proxyMeta = getmetatable(proxy)
@ -143,7 +147,7 @@ function BASE:_SetDestructor()
-- table is about to be garbage-collected - then the __gc hook
-- will be invoked and the destructor called
rawset( self, '__proxy', proxy )
--]]
end
--- This is the worker method to inherit from a parent class.

View File

@ -1,6 +1,19 @@
--- The EVENT class models an efficient event handling process between other classes and its units, weapons.
--- This module contains the EVENT class.
--
-- ===
--
-- Takes care of EVENT dispatching between DCS events and event handling functions defined in MOOSE classes.
--
-- ===
--
-- The above menus classes **are derived** from 2 main **abstract** classes defined within the MOOSE framework (so don't use these):
--
-- ===
--
-- ### Contributions: -
-- ### Authors: FlightControl : Design & Programming
--
-- @module Event
-- @author FlightControl
--- The EVENT structure
-- @type EVENT
@ -87,16 +100,13 @@ function EVENT:Init( EventID, EventClass )
self:F3( { _EVENTCODES[EventID], EventClass } )
if not self.Events[EventID] then
self.Events[EventID] = {}
-- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned.
local Meta = {}
setmetatable( self.Events[EventID], Meta )
Meta.__mode = "k"
self.Events[EventID] = setmetatable( {}, { __mode = "k" } )
end
if not self.Events[EventID][EventClass] then
self.Events[EventID][EventClass] = {}
self.Events[EventID][EventClass] = setmetatable( {}, { __mode = "k" } )
end
return self.Events[EventID][EventClass]
end
@ -714,6 +724,10 @@ function EVENT:onEvent( Event )
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
Event.IniUnitName = Event.IniDCSUnitName
Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName )
if not Event.IniUnit then
-- Unit can be a CLIENT. Most likely this will be the case ...
Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true )
end
Event.IniDCSGroupName = ""
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
Event.IniDCSGroupName = Event.IniDCSGroup:getName()

View File

@ -62,7 +62,7 @@
-- @field #number x The x coordinate in 3D space.
-- @field #number y The y coordinate in 3D space.
-- @field #number z The z coordiante in 3D space.
-- @field #POINT_VEC3.SmokeColor SmokeColor
-- @field Utilities.Utils#SMOKECOLOR SmokeColor
-- @field Utilities.Utils#FLARECOLOR FlareColor
-- @field #POINT_VEC3.RoutePointAltType RoutePointAltType
-- @field #POINT_VEC3.RoutePointType RoutePointType

View File

@ -0,0 +1,210 @@
--- This module defines the SCHEDULEDISPATCHER class, which is used by a central object called _SCHEDULEDISPATCHER.
--
-- ===
--
-- Takes care of the creation and dispatching of scheduled functions for SCHEDULER objects.
--
-- This class is tricky and needs some thorought explanation.
-- SCHEDULE classes are used to schedule functions for objects, or as persistent objects.
-- The SCHEDULEDISPATCHER class ensures that:
--
-- - Scheduled functions are planned according the SCHEDULER object parameters.
-- - Scheduled functions are repeated when requested, according the SCHEDULER object parameters.
-- - Scheduled functions are automatically removed when the schedule is finished, according the SCHEDULER object parameters.
--
-- The SCHEDULEDISPATCHER class will manage SCHEDULER object in memory during garbage collection:
-- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER
-- object is _persistent_ within memory.
-- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection!
-- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected.
-- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object,
-- these will not be executed anymore when the SCHEDULER object has been destroyed.
--
-- The SCHEDULEDISPATCHER allows multiple scheduled functions to be planned and executed for one SCHEDULER object.
-- The SCHEDULER object therefore keeps a table of "CallID's", which are returned after each planning of a new scheduled function by the SCHEDULEDISPATCHER.
-- The SCHEDULER object plans new scheduled functions through the @{Core.Scheduler#SCHEDULER.Schedule}() method.
-- The Schedule() method returns the CallID that is the reference ID for each planned schedule.
--
-- ===
--
-- ===
--
-- ### Contributions: -
-- ### Authors: FlightControl : Design & Programming
--
-- @module ScheduleDispatcher
--- The SCHEDULEDISPATCHER structure
-- @type SCHEDULEDISPATCHER
SCHEDULEDISPATCHER = {
ClassName = "SCHEDULEDISPATCHER",
CallID = 0,
}
function SCHEDULEDISPATCHER:New()
local self = BASE:Inherit( self, BASE:New() )
self:F3()
return self
end
--- Add a Schedule to the ScheduleDispatcher.
-- The development of this method was really tidy.
-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified.
-- Nothing of this code should be modified without testing it thoroughly.
-- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop )
self:F( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } )
self.CallID = self.CallID + 1
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
self.PersistentSchedulers = self.PersistentSchedulers or {}
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
if Scheduler.SchedulerObject then
self.ObjectSchedulers[self.CallID] = Scheduler
self:T3( { self.CallID, self.ObjectSchedulers[self.CallID] } )
else
self.PersistentSchedulers[self.CallID] = Scheduler
self:T3( { self.CallID, self.PersistentSchedulers[self.CallID] } )
end
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
self.Schedule[Scheduler] = {}
self.Schedule[Scheduler][self.CallID] = {}
self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction
self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 )
self.Schedule[Scheduler][self.CallID].Start = Start + .001
self.Schedule[Scheduler][self.CallID].Repeat = Repeat
self.Schedule[Scheduler][self.CallID].Randomize = Randomize
self.Schedule[Scheduler][self.CallID].Stop = Stop
self:T3( self.Schedule[Scheduler][self.CallID] )
self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID )
self:F( CallID )
local ErrorHandler = function( errmsg )
env.info( "Error in timer function: " .. errmsg )
if debug ~= nil then
env.info( debug.traceback() )
end
return errmsg
end
local Scheduler = self.ObjectSchedulers[CallID]
if not Scheduler then
Scheduler = self.PersistentSchedulers[CallID]
end
self:T( { Scheduler = Scheduler } )
if Scheduler then
local Schedule = self.Schedule[Scheduler][CallID]
self:T( { Schedule = Schedule } )
local ScheduleObject = Scheduler.SchedulerObject
--local ScheduleObjectName = Scheduler.SchedulerObject:GetNameAndClassID()
local ScheduleFunction = Schedule.Function
local ScheduleArguments = Schedule.Arguments
local Start = Schedule.Start
local Repeat = Schedule.Repeat or 0
local Randomize = Schedule.Randomize or 0
local Stop = Schedule.Stop or 0
local ScheduleID = Schedule.ScheduleID
local Status, Result
if ScheduleObject then
local function Timer()
return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) )
end
Status, Result = xpcall( Timer, ErrorHandler )
else
local function Timer()
return ScheduleFunction( unpack( ScheduleArguments ) )
end
Status, Result = xpcall( Timer, ErrorHandler )
end
local CurrentTime = timer.getTime()
local StartTime = CurrentTime + Start
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then
if Repeat ~= 0 and ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) then
local ScheduleTime =
CurrentTime +
Repeat +
math.random(
- ( Randomize * Repeat / 2 ),
( Randomize * Repeat / 2 )
) +
0.01
self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
return ScheduleTime -- returns the next time the function needs to be called.
else
self:Stop( Scheduler, CallID )
end
else
self:Stop( Scheduler, CallID )
end
else
--self:E( "Scheduled obscolete call for CallID: " .. CallID )
end
return nil
end
self:Start( Scheduler, self.CallID )
return self.CallID
end
function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
self:F( { Remove = CallID, Scheduler = Scheduler } )
if CallID then
self:Stop( Scheduler, CallID )
self.Schedule[Scheduler][CallID] = nil
end
end
function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
self:F( { Start = CallID, Scheduler = Scheduler } )
if CallID then
local Schedule = self.Schedule[Scheduler]
Schedule[CallID].ScheduleID = timer.scheduleFunction(
Schedule[CallID].CallHandler,
CallID,
timer.getTime() + Schedule[CallID].Start
)
else
for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do
self:Start( Scheduler, CallID ) -- Recursive
end
end
end
function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
self:F( { Stop = CallID, Scheduler = Scheduler } )
if CallID then
local Schedule = self.Schedule[Scheduler]
timer.removeFunction( Schedule[CallID].ScheduleID )
else
for CallID, Schedule in pairs( self.Schedule[Scheduler] ) do
self:Stop( Scheduler, CallID ) -- Recursive
end
end
end

View File

@ -1,36 +1,43 @@
--- This module contains the SCHEDULER class.
--
-- 1) @{Core.Scheduler#SCHEDULER} class, extends @{Core.Base#BASE}
-- =====================================================
-- The @{Core.Scheduler#SCHEDULER} class models time events calling given event handling functions.
-- # 1) @{Core.Scheduler#SCHEDULER} class, extends @{Core.Base#BASE}
--
-- The @{Core.Scheduler#SCHEDULER} class creates schedule.
--
-- 1.1) SCHEDULER constructor
-- --------------------------
-- The SCHEDULER class is quite easy to use:
-- ## 1.1) SCHEDULER constructor
--
-- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters:
--
-- * @{Core.Scheduler#SCHEDULER.New}: Setup a new scheduler and start it with the specified parameters.
-- * @{Core.Scheduler#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection.
-- * @{Core.Scheduler#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
-- * @{Core.Scheduler#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
-- * @{Core.Scheduler#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
--
-- ## 1.2) SCHEDULER timer stopping and (re-)starting.
--
-- 1.2) SCHEDULER timer stop and start
-- -----------------------------------
-- The SCHEDULER can be stopped and restarted with the following methods:
--
-- * @{Core.Scheduler#SCHEDULER.Start}: (Re-)Start the scheduler.
-- * @{Core.Scheduler#SCHEDULER.Stop}: Stop the scheduler.
-- * @{Core.Scheduler#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started.
-- * @{Core.Scheduler#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped.
--
-- 1.3) Reschedule new time event
-- ------------------------------
-- With @{Core.Scheduler#SCHEDULER.Schedule} a new time event can be scheduled.
-- ## 1.3) Create a new schedule
--
-- With @{Core.Scheduler#SCHEDULER.Schedule}() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned.
--
-- ===
--
-- ### Contributions:
--
-- * Mechanist : Concept & Testing
-- * FlightControl : Concept & Testing
--
-- ### Authors:
--
-- * FlightControl : Design & Programming
--
-- ### Test Missions:
--
-- * SCH - Scheduler
--
-- ===
--
-- @module Scheduler
@ -42,149 +49,96 @@
-- @extends Core.Base#BASE
SCHEDULER = {
ClassName = "SCHEDULER",
Schedules = {},
}
--- SCHEDULER constructor.
-- @param #SCHEDULER self
-- @param #table TimeEventObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference.
-- @param #function TimeEventFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in TimeEventFunctionArguments.
-- @param #table TimeEventFunctionArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @param #number StartSeconds Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #number RepeatSecondsInterval Specifies the interval in seconds when the scheduler will call the event function.
-- @param #number RandomizationFactor Specifies a randomization factor between 0 and 1 to randomize the RepeatSecondsInterval.
-- @param #number StopSeconds Specifies the amount of seconds when the scheduler will be stopped.
-- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference.
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
-- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function.
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
-- @return #SCHEDULER self
function SCHEDULER:New( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds )
-- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
local self = BASE:Inherit( self, BASE:New() )
self:F2( { StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds } )
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
local ScheduleID = nil
if SchedulerFunction then
ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
end
self:Schedule( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds )
return self
return self, ScheduleID
end
--function SCHEDULER:_Destructor()
-- --self:E("_Destructor")
--
-- _SCHEDULEDISPATCHER:RemoveSchedule( self.CallID )
--end
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
-- @param #SCHEDULER self
-- @param #table TimeEventObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference.
-- @param #function TimeEventFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in TimeEventFunctionArguments.
-- @param #table TimeEventFunctionArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @param #number StartSeconds Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #number RepeatSecondsInterval Specifies the interval in seconds when the scheduler will call the event function.
-- @param #number RandomizationFactor Specifies a randomization factor between 0 and 1 to randomize the RepeatSecondsInterval.
-- @param #number StopSeconds Specifies the amount of seconds when the scheduler will be stopped.
-- @return #SCHEDULER self
function SCHEDULER:Schedule( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds )
self:F2( { StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds } )
self:T3( { TimeEventFunctionArguments } )
-- @param #table SchedulerObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference.
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
-- @param #table SchedulerArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
-- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function.
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
-- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
self:T3( { SchedulerArguments } )
self.TimeEventObject = TimeEventObject
self.TimeEventFunction = TimeEventFunction
self.TimeEventFunctionArguments = TimeEventFunctionArguments
self.StartSeconds = StartSeconds
self.Repeat = false
self.RepeatSecondsInterval = RepeatSecondsInterval or 0
self.RandomizationFactor = RandomizationFactor or 0
self.StopSeconds = StopSeconds
self.StartTime = timer.getTime()
self.SchedulerObject = SchedulerObject
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
self,
SchedulerFunction,
SchedulerArguments,
Start,
Repeat,
RandomizeFactor,
Stop
)
self.Schedules[#self.Schedules+1] = ScheduleID
self:Start()
return self
return ScheduleID
end
--- (Re-)Starts the scheduler.
--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided.
-- @param #SCHEDULER self
-- @return #SCHEDULER self
function SCHEDULER:Start()
self:F2()
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Start( ScheduleID )
self:F3( { ScheduleID } )
if self.RepeatSecondsInterval ~= 0 then
self.Repeat = true
end
if self.StartSeconds then
if self.ScheduleID then
timer.removeFunction( self.ScheduleID )
end
self:T( { self.StartSeconds } )
self.ScheduleID = timer.scheduleFunction( self._Scheduler, self, timer.getTime() + self.StartSeconds + .001 )
end
return self
_SCHEDULEDISPATCHER:Start( self, ScheduleID )
end
--- Stops the scheduler.
--- Stops the schedules or a specific schedule if a valid ScheduleID is provided.
-- @param #SCHEDULER self
-- @return #SCHEDULER self
function SCHEDULER:Stop()
self:F2( self.TimeEventObject )
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Stop( ScheduleID )
self:F3( { ScheduleID } )
self.Repeat = false
if self.ScheduleID then
self:E( "Stop Schedule" )
timer.removeFunction( self.ScheduleID )
end
self.ScheduleID = nil
return self
_SCHEDULEDISPATCHER:Stop( self, ScheduleID )
end
-- Private Functions
--- Removes a specific schedule if a valid ScheduleID is provided.
-- @param #SCHEDULER self
-- @param #number ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
function SCHEDULER:Remove( ScheduleID )
self:F3( { ScheduleID } )
--- @param #SCHEDULER self
function SCHEDULER:_Scheduler()
self:F2( self.TimeEventFunctionArguments )
local ErrorHandler = function( errmsg )
env.info( "Error in SCHEDULER function:" .. errmsg )
if debug ~= nil then
env.info( debug.traceback() )
end
return errmsg
end
local StartTime = self.StartTime
local StopSeconds = self.StopSeconds
local Repeat = self.Repeat
local RandomizationFactor = self.RandomizationFactor
local RepeatSecondsInterval = self.RepeatSecondsInterval
local ScheduleID = self.ScheduleID
local Status, Result
if self.TimeEventObject then
Status, Result = xpcall( function() return self.TimeEventFunction( self.TimeEventObject, unpack( self.TimeEventFunctionArguments ) ) end, ErrorHandler )
else
Status, Result = xpcall( function() return self.TimeEventFunction( unpack( self.TimeEventFunctionArguments ) ) end, ErrorHandler )
end
self:T( { "Timer Event2 .. " .. self.ScheduleID, Status, Result, StartTime, RepeatSecondsInterval, RandomizationFactor, StopSeconds } )
if Status and ( ( Result == nil ) or ( Result and Result ~= false ) ) then
if Repeat and ( not StopSeconds or ( StopSeconds and timer.getTime() <= StartTime + StopSeconds ) ) then
local ScheduleTime =
timer.getTime() +
self.RepeatSecondsInterval +
math.random(
- ( RandomizationFactor * RepeatSecondsInterval / 2 ),
( RandomizationFactor * RepeatSecondsInterval / 2 )
) +
0.01
self:T( { self.TimeEventFunctionArguments, "Repeat:", timer.getTime(), ScheduleTime } )
return ScheduleTime -- returns the next time the function needs to be called.
else
timer.removeFunction( ScheduleID )
self.ScheduleID = nil
end
else
timer.removeFunction( ScheduleID )
self.ScheduleID = nil
end
return nil
_SCHEDULEDISPATCHER:Remove( self, ScheduleID )
end
@ -201,4 +155,3 @@ end

View File

@ -230,7 +230,7 @@ end
--- Smokes the zone boundaries in a color.
-- @param #ZONE_BASE self
-- @param SmokeColor The smoke color.
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.
function ZONE_BASE:SmokeZone( SmokeColor )
self:F2( SmokeColor )
@ -298,7 +298,7 @@ end
--- Smokes the zone boundaries in a color.
-- @param #ZONE_RADIUS self
-- @param #POINT_VEC3.SmokeColor SmokeColor The smoke color.
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.
-- @param #number Points (optional) The amount of points in the circle.
-- @return #ZONE_RADIUS self
function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
@ -689,7 +689,7 @@ end
--- Smokes the zone boundaries in a color.
-- @param #ZONE_POLYGON_BASE self
-- @param #POINT_VEC3.SmokeColor SmokeColor The smoke color.
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.
-- @return #ZONE_POLYGON_BASE self
function ZONE_POLYGON_BASE:SmokeZone( SmokeColor )
self:F2( SmokeColor )

View File

@ -3,3 +3,6 @@
trigger = {} --#timer

View File

@ -58,6 +58,8 @@ do -- FSM
self._EndStates = {}
self._Scores = {}
self.CallScheduler = SCHEDULER:New( self )
return self
end
@ -313,7 +315,8 @@ do -- FSM
self:E( { EventName = EventName } )
return function( self, DelaySeconds, ... )
self:T( "Delayed Event: " .. EventName )
SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds )
local CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 )
self:T( { CallID = CallID } )
end
end
@ -491,6 +494,8 @@ do -- FSM_PROCESS
function FSM_PROCESS:New( Controllable, Task )
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Fsm.Fsm#FSM_PROCESS
self:F( Controllable, Task )
self:Assign( Controllable, Task )
@ -631,7 +636,7 @@ do -- FSM_PROCESS
self:E( { ProcessUnit, Event, From, To, Dummy, self:IsTrace() } )
if self:IsTrace() then
MESSAGE:New( "Process " .. self.ProcessName .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
MESSAGE:New( "Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 15 ):ToAll()
end
self:E( self.Scores[To] )

View File

@ -85,18 +85,18 @@ function AIRBASEPOLICE_BASE:New( SetClient, Airbases )
self.Airbases = Airbases
for AirbaseID, Airbase in pairs( self.Airbases ) do
Airbase.ZoneBoundary = ZONE_POLYGON_BASE:New( "Boundary", Airbase.PointsBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
Airbase.ZoneBoundary = ZONE_POLYGON_BASE:New( "Boundary", Airbase.PointsBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
for PointsRunwayID, PointsRunway in pairs( Airbase.PointsRunways ) do
Airbase.ZoneRunways[PointsRunwayID] = ZONE_POLYGON_BASE:New( "Runway " .. PointsRunwayID, PointsRunway ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
Airbase.ZoneRunways[PointsRunwayID] = ZONE_POLYGON_BASE:New( "Runway " .. PointsRunwayID, PointsRunway ):SmokeZone(SMOKECOLOR.Red):Flush()
end
end
-- -- Template
-- local TemplateBoundary = GROUP:FindByName( "Template Boundary" )
-- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" )
-- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
self.SetClient:ForEachClient(
--- @param Wrapper.Client#CLIENT Client
@ -749,197 +749,197 @@ function AIRBASEPOLICE_CAUCASUS:New( SetClient )
-- -- AnapaVityazevo
-- local AnapaVityazevoBoundary = GROUP:FindByName( "AnapaVityazevo Boundary" )
-- self.Airbases.AnapaVityazevo.ZoneBoundary = ZONE_POLYGON:New( "AnapaVityazevo Boundary", AnapaVityazevoBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.AnapaVityazevo.ZoneBoundary = ZONE_POLYGON:New( "AnapaVityazevo Boundary", AnapaVityazevoBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local AnapaVityazevoRunway1 = GROUP:FindByName( "AnapaVityazevo Runway 1" )
-- self.Airbases.AnapaVityazevo.ZoneRunways[1] = ZONE_POLYGON:New( "AnapaVityazevo Runway 1", AnapaVityazevoRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.AnapaVityazevo.ZoneRunways[1] = ZONE_POLYGON:New( "AnapaVityazevo Runway 1", AnapaVityazevoRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Batumi
-- local BatumiBoundary = GROUP:FindByName( "Batumi Boundary" )
-- self.Airbases.Batumi.ZoneBoundary = ZONE_POLYGON:New( "Batumi Boundary", BatumiBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Batumi.ZoneBoundary = ZONE_POLYGON:New( "Batumi Boundary", BatumiBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local BatumiRunway1 = GROUP:FindByName( "Batumi Runway 1" )
-- self.Airbases.Batumi.ZoneRunways[1] = ZONE_POLYGON:New( "Batumi Runway 1", BatumiRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Batumi.ZoneRunways[1] = ZONE_POLYGON:New( "Batumi Runway 1", BatumiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Beslan
-- local BeslanBoundary = GROUP:FindByName( "Beslan Boundary" )
-- self.Airbases.Beslan.ZoneBoundary = ZONE_POLYGON:New( "Beslan Boundary", BeslanBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Beslan.ZoneBoundary = ZONE_POLYGON:New( "Beslan Boundary", BeslanBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local BeslanRunway1 = GROUP:FindByName( "Beslan Runway 1" )
-- self.Airbases.Beslan.ZoneRunways[1] = ZONE_POLYGON:New( "Beslan Runway 1", BeslanRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Beslan.ZoneRunways[1] = ZONE_POLYGON:New( "Beslan Runway 1", BeslanRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Gelendzhik
-- local GelendzhikBoundary = GROUP:FindByName( "Gelendzhik Boundary" )
-- self.Airbases.Gelendzhik.ZoneBoundary = ZONE_POLYGON:New( "Gelendzhik Boundary", GelendzhikBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Gelendzhik.ZoneBoundary = ZONE_POLYGON:New( "Gelendzhik Boundary", GelendzhikBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local GelendzhikRunway1 = GROUP:FindByName( "Gelendzhik Runway 1" )
-- self.Airbases.Gelendzhik.ZoneRunways[1] = ZONE_POLYGON:New( "Gelendzhik Runway 1", GelendzhikRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Gelendzhik.ZoneRunways[1] = ZONE_POLYGON:New( "Gelendzhik Runway 1", GelendzhikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Gudauta
-- local GudautaBoundary = GROUP:FindByName( "Gudauta Boundary" )
-- self.Airbases.Gudauta.ZoneBoundary = ZONE_POLYGON:New( "Gudauta Boundary", GudautaBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Gudauta.ZoneBoundary = ZONE_POLYGON:New( "Gudauta Boundary", GudautaBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local GudautaRunway1 = GROUP:FindByName( "Gudauta Runway 1" )
-- self.Airbases.Gudauta.ZoneRunways[1] = ZONE_POLYGON:New( "Gudauta Runway 1", GudautaRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Gudauta.ZoneRunways[1] = ZONE_POLYGON:New( "Gudauta Runway 1", GudautaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Kobuleti
-- local KobuletiBoundary = GROUP:FindByName( "Kobuleti Boundary" )
-- self.Airbases.Kobuleti.ZoneBoundary = ZONE_POLYGON:New( "Kobuleti Boundary", KobuletiBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Kobuleti.ZoneBoundary = ZONE_POLYGON:New( "Kobuleti Boundary", KobuletiBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local KobuletiRunway1 = GROUP:FindByName( "Kobuleti Runway 1" )
-- self.Airbases.Kobuleti.ZoneRunways[1] = ZONE_POLYGON:New( "Kobuleti Runway 1", KobuletiRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Kobuleti.ZoneRunways[1] = ZONE_POLYGON:New( "Kobuleti Runway 1", KobuletiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- KrasnodarCenter
-- local KrasnodarCenterBoundary = GROUP:FindByName( "KrasnodarCenter Boundary" )
-- self.Airbases.KrasnodarCenter.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarCenter Boundary", KrasnodarCenterBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.KrasnodarCenter.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarCenter Boundary", KrasnodarCenterBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local KrasnodarCenterRunway1 = GROUP:FindByName( "KrasnodarCenter Runway 1" )
-- self.Airbases.KrasnodarCenter.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarCenter Runway 1", KrasnodarCenterRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.KrasnodarCenter.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarCenter Runway 1", KrasnodarCenterRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- KrasnodarPashkovsky
-- local KrasnodarPashkovskyBoundary = GROUP:FindByName( "KrasnodarPashkovsky Boundary" )
-- self.Airbases.KrasnodarPashkovsky.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarPashkovsky Boundary", KrasnodarPashkovskyBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.KrasnodarPashkovsky.ZoneBoundary = ZONE_POLYGON:New( "KrasnodarPashkovsky Boundary", KrasnodarPashkovskyBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local KrasnodarPashkovskyRunway1 = GROUP:FindByName( "KrasnodarPashkovsky Runway 1" )
-- self.Airbases.KrasnodarPashkovsky.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 1", KrasnodarPashkovskyRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.KrasnodarPashkovsky.ZoneRunways[1] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 1", KrasnodarPashkovskyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
-- local KrasnodarPashkovskyRunway2 = GROUP:FindByName( "KrasnodarPashkovsky Runway 2" )
-- self.Airbases.KrasnodarPashkovsky.ZoneRunways[2] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 2", KrasnodarPashkovskyRunway2 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.KrasnodarPashkovsky.ZoneRunways[2] = ZONE_POLYGON:New( "KrasnodarPashkovsky Runway 2", KrasnodarPashkovskyRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Krymsk
-- local KrymskBoundary = GROUP:FindByName( "Krymsk Boundary" )
-- self.Airbases.Krymsk.ZoneBoundary = ZONE_POLYGON:New( "Krymsk Boundary", KrymskBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Krymsk.ZoneBoundary = ZONE_POLYGON:New( "Krymsk Boundary", KrymskBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local KrymskRunway1 = GROUP:FindByName( "Krymsk Runway 1" )
-- self.Airbases.Krymsk.ZoneRunways[1] = ZONE_POLYGON:New( "Krymsk Runway 1", KrymskRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Krymsk.ZoneRunways[1] = ZONE_POLYGON:New( "Krymsk Runway 1", KrymskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Kutaisi
-- local KutaisiBoundary = GROUP:FindByName( "Kutaisi Boundary" )
-- self.Airbases.Kutaisi.ZoneBoundary = ZONE_POLYGON:New( "Kutaisi Boundary", KutaisiBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Kutaisi.ZoneBoundary = ZONE_POLYGON:New( "Kutaisi Boundary", KutaisiBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local KutaisiRunway1 = GROUP:FindByName( "Kutaisi Runway 1" )
-- self.Airbases.Kutaisi.ZoneRunways[1] = ZONE_POLYGON:New( "Kutaisi Runway 1", KutaisiRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Kutaisi.ZoneRunways[1] = ZONE_POLYGON:New( "Kutaisi Runway 1", KutaisiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- MaykopKhanskaya
-- local MaykopKhanskayaBoundary = GROUP:FindByName( "MaykopKhanskaya Boundary" )
-- self.Airbases.MaykopKhanskaya.ZoneBoundary = ZONE_POLYGON:New( "MaykopKhanskaya Boundary", MaykopKhanskayaBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.MaykopKhanskaya.ZoneBoundary = ZONE_POLYGON:New( "MaykopKhanskaya Boundary", MaykopKhanskayaBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local MaykopKhanskayaRunway1 = GROUP:FindByName( "MaykopKhanskaya Runway 1" )
-- self.Airbases.MaykopKhanskaya.ZoneRunways[1] = ZONE_POLYGON:New( "MaykopKhanskaya Runway 1", MaykopKhanskayaRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.MaykopKhanskaya.ZoneRunways[1] = ZONE_POLYGON:New( "MaykopKhanskaya Runway 1", MaykopKhanskayaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- MineralnyeVody
-- local MineralnyeVodyBoundary = GROUP:FindByName( "MineralnyeVody Boundary" )
-- self.Airbases.MineralnyeVody.ZoneBoundary = ZONE_POLYGON:New( "MineralnyeVody Boundary", MineralnyeVodyBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.MineralnyeVody.ZoneBoundary = ZONE_POLYGON:New( "MineralnyeVody Boundary", MineralnyeVodyBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local MineralnyeVodyRunway1 = GROUP:FindByName( "MineralnyeVody Runway 1" )
-- self.Airbases.MineralnyeVody.ZoneRunways[1] = ZONE_POLYGON:New( "MineralnyeVody Runway 1", MineralnyeVodyRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.MineralnyeVody.ZoneRunways[1] = ZONE_POLYGON:New( "MineralnyeVody Runway 1", MineralnyeVodyRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Mozdok
-- local MozdokBoundary = GROUP:FindByName( "Mozdok Boundary" )
-- self.Airbases.Mozdok.ZoneBoundary = ZONE_POLYGON:New( "Mozdok Boundary", MozdokBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Mozdok.ZoneBoundary = ZONE_POLYGON:New( "Mozdok Boundary", MozdokBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local MozdokRunway1 = GROUP:FindByName( "Mozdok Runway 1" )
-- self.Airbases.Mozdok.ZoneRunways[1] = ZONE_POLYGON:New( "Mozdok Runway 1", MozdokRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Mozdok.ZoneRunways[1] = ZONE_POLYGON:New( "Mozdok Runway 1", MozdokRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Nalchik
-- local NalchikBoundary = GROUP:FindByName( "Nalchik Boundary" )
-- self.Airbases.Nalchik.ZoneBoundary = ZONE_POLYGON:New( "Nalchik Boundary", NalchikBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Nalchik.ZoneBoundary = ZONE_POLYGON:New( "Nalchik Boundary", NalchikBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local NalchikRunway1 = GROUP:FindByName( "Nalchik Runway 1" )
-- self.Airbases.Nalchik.ZoneRunways[1] = ZONE_POLYGON:New( "Nalchik Runway 1", NalchikRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Nalchik.ZoneRunways[1] = ZONE_POLYGON:New( "Nalchik Runway 1", NalchikRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Novorossiysk
-- local NovorossiyskBoundary = GROUP:FindByName( "Novorossiysk Boundary" )
-- self.Airbases.Novorossiysk.ZoneBoundary = ZONE_POLYGON:New( "Novorossiysk Boundary", NovorossiyskBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Novorossiysk.ZoneBoundary = ZONE_POLYGON:New( "Novorossiysk Boundary", NovorossiyskBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local NovorossiyskRunway1 = GROUP:FindByName( "Novorossiysk Runway 1" )
-- self.Airbases.Novorossiysk.ZoneRunways[1] = ZONE_POLYGON:New( "Novorossiysk Runway 1", NovorossiyskRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Novorossiysk.ZoneRunways[1] = ZONE_POLYGON:New( "Novorossiysk Runway 1", NovorossiyskRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- SenakiKolkhi
-- local SenakiKolkhiBoundary = GROUP:FindByName( "SenakiKolkhi Boundary" )
-- self.Airbases.SenakiKolkhi.ZoneBoundary = ZONE_POLYGON:New( "SenakiKolkhi Boundary", SenakiKolkhiBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.SenakiKolkhi.ZoneBoundary = ZONE_POLYGON:New( "SenakiKolkhi Boundary", SenakiKolkhiBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local SenakiKolkhiRunway1 = GROUP:FindByName( "SenakiKolkhi Runway 1" )
-- self.Airbases.SenakiKolkhi.ZoneRunways[1] = ZONE_POLYGON:New( "SenakiKolkhi Runway 1", SenakiKolkhiRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.SenakiKolkhi.ZoneRunways[1] = ZONE_POLYGON:New( "SenakiKolkhi Runway 1", SenakiKolkhiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- SochiAdler
-- local SochiAdlerBoundary = GROUP:FindByName( "SochiAdler Boundary" )
-- self.Airbases.SochiAdler.ZoneBoundary = ZONE_POLYGON:New( "SochiAdler Boundary", SochiAdlerBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.SochiAdler.ZoneBoundary = ZONE_POLYGON:New( "SochiAdler Boundary", SochiAdlerBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local SochiAdlerRunway1 = GROUP:FindByName( "SochiAdler Runway 1" )
-- self.Airbases.SochiAdler.ZoneRunways[1] = ZONE_POLYGON:New( "SochiAdler Runway 1", SochiAdlerRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.SochiAdler.ZoneRunways[1] = ZONE_POLYGON:New( "SochiAdler Runway 1", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
-- local SochiAdlerRunway2 = GROUP:FindByName( "SochiAdler Runway 2" )
-- self.Airbases.SochiAdler.ZoneRunways[2] = ZONE_POLYGON:New( "SochiAdler Runway 2", SochiAdlerRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.SochiAdler.ZoneRunways[2] = ZONE_POLYGON:New( "SochiAdler Runway 2", SochiAdlerRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Soganlug
-- local SoganlugBoundary = GROUP:FindByName( "Soganlug Boundary" )
-- self.Airbases.Soganlug.ZoneBoundary = ZONE_POLYGON:New( "Soganlug Boundary", SoganlugBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Soganlug.ZoneBoundary = ZONE_POLYGON:New( "Soganlug Boundary", SoganlugBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local SoganlugRunway1 = GROUP:FindByName( "Soganlug Runway 1" )
-- self.Airbases.Soganlug.ZoneRunways[1] = ZONE_POLYGON:New( "Soganlug Runway 1", SoganlugRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Soganlug.ZoneRunways[1] = ZONE_POLYGON:New( "Soganlug Runway 1", SoganlugRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- SukhumiBabushara
-- local SukhumiBabusharaBoundary = GROUP:FindByName( "SukhumiBabushara Boundary" )
-- self.Airbases.SukhumiBabushara.ZoneBoundary = ZONE_POLYGON:New( "SukhumiBabushara Boundary", SukhumiBabusharaBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.SukhumiBabushara.ZoneBoundary = ZONE_POLYGON:New( "SukhumiBabushara Boundary", SukhumiBabusharaBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local SukhumiBabusharaRunway1 = GROUP:FindByName( "SukhumiBabushara Runway 1" )
-- self.Airbases.SukhumiBabushara.ZoneRunways[1] = ZONE_POLYGON:New( "SukhumiBabushara Runway 1", SukhumiBabusharaRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.SukhumiBabushara.ZoneRunways[1] = ZONE_POLYGON:New( "SukhumiBabushara Runway 1", SukhumiBabusharaRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- TbilisiLochini
-- local TbilisiLochiniBoundary = GROUP:FindByName( "TbilisiLochini Boundary" )
-- self.Airbases.TbilisiLochini.ZoneBoundary = ZONE_POLYGON:New( "TbilisiLochini Boundary", TbilisiLochiniBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.TbilisiLochini.ZoneBoundary = ZONE_POLYGON:New( "TbilisiLochini Boundary", TbilisiLochiniBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local TbilisiLochiniRunway1 = GROUP:FindByName( "TbilisiLochini Runway 1" )
-- self.Airbases.TbilisiLochini.ZoneRunways[1] = ZONE_POLYGON:New( "TbilisiLochini Runway 1", TbilisiLochiniRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.TbilisiLochini.ZoneRunways[1] = ZONE_POLYGON:New( "TbilisiLochini Runway 1", TbilisiLochiniRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- local TbilisiLochiniRunway2 = GROUP:FindByName( "TbilisiLochini Runway 2" )
-- self.Airbases.TbilisiLochini.ZoneRunways[2] = ZONE_POLYGON:New( "TbilisiLochini Runway 2", TbilisiLochiniRunway2 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.TbilisiLochini.ZoneRunways[2] = ZONE_POLYGON:New( "TbilisiLochini Runway 2", TbilisiLochiniRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
-- -- Vaziani
-- local VazianiBoundary = GROUP:FindByName( "Vaziani Boundary" )
-- self.Airbases.Vaziani.ZoneBoundary = ZONE_POLYGON:New( "Vaziani Boundary", VazianiBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Vaziani.ZoneBoundary = ZONE_POLYGON:New( "Vaziani Boundary", VazianiBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local VazianiRunway1 = GROUP:FindByName( "Vaziani Runway 1" )
-- self.Airbases.Vaziani.ZoneRunways[1] = ZONE_POLYGON:New( "Vaziani Runway 1", VazianiRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Vaziani.ZoneRunways[1] = ZONE_POLYGON:New( "Vaziani Runway 1", VazianiRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
--
--
@ -947,10 +947,10 @@ function AIRBASEPOLICE_CAUCASUS:New( SetClient )
-- Template
-- local TemplateBoundary = GROUP:FindByName( "Template Boundary" )
-- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Template.ZoneBoundary = ZONE_POLYGON:New( "Template Boundary", TemplateBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local TemplateRunway1 = GROUP:FindByName( "Template Runway 1" )
-- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Template.ZoneRunways[1] = ZONE_POLYGON:New( "Template Runway 1", TemplateRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
return self
@ -1143,49 +1143,49 @@ function AIRBASEPOLICE_NEVADA:New( SetClient )
-- -- Nellis
-- local NellisBoundary = GROUP:FindByName( "Nellis Boundary" )
-- self.Airbases.Nellis.ZoneBoundary = ZONE_POLYGON:New( "Nellis Boundary", NellisBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Nellis.ZoneBoundary = ZONE_POLYGON:New( "Nellis Boundary", NellisBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local NellisRunway1 = GROUP:FindByName( "Nellis Runway 1" )
-- self.Airbases.Nellis.ZoneRunways[1] = ZONE_POLYGON:New( "Nellis Runway 1", NellisRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Nellis.ZoneRunways[1] = ZONE_POLYGON:New( "Nellis Runway 1", NellisRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- local NellisRunway2 = GROUP:FindByName( "Nellis Runway 2" )
-- self.Airbases.Nellis.ZoneRunways[2] = ZONE_POLYGON:New( "Nellis Runway 2", NellisRunway2 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Nellis.ZoneRunways[2] = ZONE_POLYGON:New( "Nellis Runway 2", NellisRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- -- McCarran
-- local McCarranBoundary = GROUP:FindByName( "McCarran Boundary" )
-- self.Airbases.McCarran.ZoneBoundary = ZONE_POLYGON:New( "McCarran Boundary", McCarranBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.McCarran.ZoneBoundary = ZONE_POLYGON:New( "McCarran Boundary", McCarranBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local McCarranRunway1 = GROUP:FindByName( "McCarran Runway 1" )
-- self.Airbases.McCarran.ZoneRunways[1] = ZONE_POLYGON:New( "McCarran Runway 1", McCarranRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.McCarran.ZoneRunways[1] = ZONE_POLYGON:New( "McCarran Runway 1", McCarranRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- local McCarranRunway2 = GROUP:FindByName( "McCarran Runway 2" )
-- self.Airbases.McCarran.ZoneRunways[2] = ZONE_POLYGON:New( "McCarran Runway 2", McCarranRunway2 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.McCarran.ZoneRunways[2] = ZONE_POLYGON:New( "McCarran Runway 2", McCarranRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- local McCarranRunway3 = GROUP:FindByName( "McCarran Runway 3" )
-- self.Airbases.McCarran.ZoneRunways[3] = ZONE_POLYGON:New( "McCarran Runway 3", McCarranRunway3 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.McCarran.ZoneRunways[3] = ZONE_POLYGON:New( "McCarran Runway 3", McCarranRunway3 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- local McCarranRunway4 = GROUP:FindByName( "McCarran Runway 4" )
-- self.Airbases.McCarran.ZoneRunways[4] = ZONE_POLYGON:New( "McCarran Runway 4", McCarranRunway4 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.McCarran.ZoneRunways[4] = ZONE_POLYGON:New( "McCarran Runway 4", McCarranRunway4 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- -- Creech
-- local CreechBoundary = GROUP:FindByName( "Creech Boundary" )
-- self.Airbases.Creech.ZoneBoundary = ZONE_POLYGON:New( "Creech Boundary", CreechBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.Creech.ZoneBoundary = ZONE_POLYGON:New( "Creech Boundary", CreechBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local CreechRunway1 = GROUP:FindByName( "Creech Runway 1" )
-- self.Airbases.Creech.ZoneRunways[1] = ZONE_POLYGON:New( "Creech Runway 1", CreechRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Creech.ZoneRunways[1] = ZONE_POLYGON:New( "Creech Runway 1", CreechRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- local CreechRunway2 = GROUP:FindByName( "Creech Runway 2" )
-- self.Airbases.Creech.ZoneRunways[2] = ZONE_POLYGON:New( "Creech Runway 2", CreechRunway2 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.Creech.ZoneRunways[2] = ZONE_POLYGON:New( "Creech Runway 2", CreechRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- -- Groom Lake
-- local GroomLakeBoundary = GROUP:FindByName( "GroomLake Boundary" )
-- self.Airbases.GroomLake.ZoneBoundary = ZONE_POLYGON:New( "GroomLake Boundary", GroomLakeBoundary ):SmokeZone(POINT_VEC3.SmokeColor.White):Flush()
-- self.Airbases.GroomLake.ZoneBoundary = ZONE_POLYGON:New( "GroomLake Boundary", GroomLakeBoundary ):SmokeZone(SMOKECOLOR.White):Flush()
--
-- local GroomLakeRunway1 = GROUP:FindByName( "GroomLake Runway 1" )
-- self.Airbases.GroomLake.ZoneRunways[1] = ZONE_POLYGON:New( "GroomLake Runway 1", GroomLakeRunway1 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.GroomLake.ZoneRunways[1] = ZONE_POLYGON:New( "GroomLake Runway 1", GroomLakeRunway1 ):SmokeZone(SMOKECOLOR.Red):Flush()
--
-- local GroomLakeRunway2 = GROUP:FindByName( "GroomLake Runway 2" )
-- self.Airbases.GroomLake.ZoneRunways[2] = ZONE_POLYGON:New( "GroomLake Runway 2", GroomLakeRunway2 ):SmokeZone(POINT_VEC3.SmokeColor.Red):Flush()
-- self.Airbases.GroomLake.ZoneRunways[2] = ZONE_POLYGON:New( "GroomLake Runway 2", GroomLakeRunway2 ):SmokeZone(SMOKECOLOR.Red):Flush()
end

View File

@ -973,10 +973,10 @@ function DETECTION_AREAS:CreateDetectionSets()
end
)
if DETECTION_AREAS._FlareDetectedZones or self._FlareDetectedZones then
DetectedZone:FlareZone( POINT_VEC3.SmokeColor.White, 30, math.random( 0,90 ) )
DetectedZone:FlareZone( SMOKECOLOR.White, 30, math.random( 0,90 ) )
end
if DETECTION_AREAS._SmokeDetectedZones or self._SmokeDetectedZones then
DetectedZone:SmokeZone( POINT_VEC3.SmokeColor.White, 30 )
DetectedZone:SmokeZone( SMOKECOLOR.White, 30 )
end
end

View File

@ -494,10 +494,10 @@ function ESCORT:MenuFlare( MenuTextFormat )
if not self.EscortMenuFlare then
self.EscortMenuFlare = MENU_CLIENT:New( self.EscortClient, MenuText, self.EscortMenuReportNavigation, ESCORT._Flare, { ParamSelf = self } )
self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Green, ParamMessage = "Released a green flare!" } )
self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Red, ParamMessage = "Released a red flare!" } )
self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.White, ParamMessage = "Released a white flare!" } )
self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = UNIT.FlareColor.Yellow, ParamMessage = "Released a yellow flare!" } )
self.EscortMenuFlareGreen = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release green flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Green, ParamMessage = "Released a green flare!" } )
self.EscortMenuFlareRed = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release red flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Red, ParamMessage = "Released a red flare!" } )
self.EscortMenuFlareWhite = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release white flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.White, ParamMessage = "Released a white flare!" } )
self.EscortMenuFlareYellow = MENU_CLIENT_COMMAND:New( self.EscortClient, "Release yellow flare", self.EscortMenuFlare, ESCORT._Flare, { ParamSelf = self, ParamColor = FLARECOLOR.Yellow, ParamMessage = "Released a yellow flare!" } )
end
return self

View File

@ -7,6 +7,7 @@ Include.File( "Utilities/Utils" )
--- Core Classes
Include.File( "Core/Base" )
Include.File( "Core/Scheduler" )
Include.File( "Core/ScheduleDispatcher")
Include.File( "Core/Event" )
Include.File( "Core/Menu" )
Include.File( "Core/Zone" )
@ -63,6 +64,11 @@ Include.File( "Tasking/Task_A2G" )
--- Declare the event dispatcher based on the EVENT class
_EVENTDISPATCHER = EVENT:New() -- Core.Event#EVENT
--- Declare the timer dispatcher based on the SCHEDULEDISPATCHER class
_SCHEDULEDISPATCHER = SCHEDULEDISPATCHER:New() -- Core.Timer#SCHEDULEDISPATCHER
--- Declare the main database object, which is used internally by the MOOSE classes.
_DATABASE = DATABASE:New() -- Database#DATABASE

View File

@ -64,8 +64,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
self.CommandCenterName = CommandCenterName or CommandCenterPositionable:GetName()
self.CommandCenterCoalition = CommandCenterPositionable:GetCoalition()
self.Missions = {}
setmetatable( self.Missions, { __mode = "v" } )
self.Missions = setmetatable( {}, { __mode = "v" } )
self:EventOnBirth(
--- @param #COMMANDCENTER self
@ -155,6 +154,13 @@ function COMMANDCENTER:HasGroup( MissionGroup )
return Has
end
--- Send a CC message to a GROUP.
-- @param #COMMANDCENTER self
function COMMANDCENTER:MessageToGroup( Message, TaskGroup )
self:GetPositionable():MessageToGroup( Message , 20, TaskGroup )
end
--- Report the status of all MISSIONs to a GROUP.
-- @param #COMMANDCENTER self
@ -172,3 +178,19 @@ function COMMANDCENTER:ReportMissions( ReportGroup )
end
--- Report the status of a Task to a Group.
-- @param #COMMANDCENTER self
function COMMANDCENTER:ReportTaskStatus( ReportGroup, Task )
self:E( ReportGroup )
local Report = REPORT:New()
for MissionID, Mission in pairs( self.Missions ) do
local Mission = Mission -- Tasking.Mission#MISSION
Report:Add( " - " .. Mission:ReportStatus() )
end
self:GetPositionable():MessageToGroup( Report:Text(), 30, ReportGroup )
end

View File

@ -59,7 +59,6 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
self.MissionCoalition = MissionCoalition
self.Tasks = {}
setmetatable( self.Tasks, { __mode = "v" } )
-- Build the Fsm for the mission.
@ -202,8 +201,9 @@ function MISSION:AddTask( Task )
local TaskName = Task:GetTaskName()
self:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
self.Tasks[TaskName] = Task
return Task
@ -222,8 +222,6 @@ function MISSION:RemoveTask( Task )
self:F( TaskName )
self.Tasks[TaskName] = self.Tasks[TaskName] or { n = 0 }
Task:CleanUp() -- Cleans all events and sets task to nil to get Garbage Collected
-- Ensure everything gets garbarge collected.
self.Tasks[TaskName] = nil
Task = nil

View File

@ -55,6 +55,8 @@
-- @field Tasking.Mission#MISSION Mission
-- @field Core.Set#SET_GROUP SetGroup The Set of Groups assigned to the Task
-- @field Fsm.Fsm#FSM_PROCESS FsmTemplate
-- @field Tasking.Mission#MISSION Mission
-- @field Tasking.CommandCenter#COMMANDCENTER CommandCenter
-- @extends Fsm.Fsm#FSM_TASK
TASK_BASE = {
ClassName = "TASK_BASE",
@ -66,6 +68,8 @@ TASK_BASE = {
Menu = {},
SetGroup = nil,
FsmTemplate = nil,
Mission = nil,
CommandCenter = nil,
}
--- Instantiates a new TASK_BASE. Should never be used. Interface Class.
@ -81,6 +85,7 @@ function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType )
self:SetStartState( "Planned" )
self:AddTransition( "Planned", "Assign", "Assigned" )
self:AddTransition( "Assigned", "AssignUnit", "Assigned" )
self:AddTransition( "Assigned", "Success", "Success" )
self:AddTransition( "Assigned", "Fail", "Failed" )
self:AddTransition( "Assigned", "Abort", "Aborted" )
@ -93,6 +98,7 @@ function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType )
self.Fsm = {}
self.Mission = Mission
self.CommandCenter = Mission:GetCommandCenter()
self.SetGroup = SetGroupAssign
@ -105,20 +111,23 @@ function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType )
self.FsmTemplate = self.FsmTemplate or FSM_PROCESS:New()
-- Handle the birth of new planes within the assigned set.
self:EventOnPlayerEnterUnit(
--- @param #TASK_BASE self
-- @param Core.Event#EVENTDATA EventData
function( self, EventData )
self:E( "In EnterUnit" )
self:E( EventData )
self:E( { "State", self:GetState() } )
local TaskUnit = EventData.IniUnit
local TaskGroup = EventData.IniUnit:GetGroup()
self:SetMenuForGroup(TaskGroup)
if self:IsStateAssigned() then
local TaskUnit = EventData.IniUnit
local TaskGroup = EventData.IniUnit:GetGroup()
self:E( self.SetGroup:IsIncludeObject( TaskGroup ) )
if self.SetGroup:IsIncludeObject( TaskGroup ) then
self:E( self:IsAssignedToGroup( TaskGroup ) )
if self:IsAssignedToGroup( TaskGroup ) then
self:AssignToUnit( TaskUnit )
end
end
self:MessageToGroups( TaskUnit:GetPlayerName() .. " joined Task " .. self:GetName() )
end
)
@ -134,10 +143,12 @@ function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType )
if self:IsStateAssigned() then
local TaskUnit = EventData.IniUnit
local TaskGroup = EventData.IniUnit:GetGroup()
self:E( self.SetGroup:IsIncludeObject( TaskGroup ) )
if self.SetGroup:IsIncludeObject( TaskGroup ) then
self:E( self:IsAssignedToGroup( TaskGroup ) )
if self:IsAssignedToGroup( TaskGroup ) then
self:UnAssignFromUnit( TaskUnit )
self:MessageToGroups( TaskUnit:GetPlayerName() .. " aborted Task " .. self:GetName() )
end
self:__Abort( 1 )
end
end
)
@ -158,10 +169,12 @@ function TASK_BASE:New( Mission, SetGroupAssign, TaskName, TaskType )
if self.SetGroup:IsIncludeObject( TaskGroup ) then
self:UnAssignFromUnit( TaskUnit )
end
self:MessageToGroups( TaskUnit:GetPlayerName() .. " crashed!, and has aborted Task " .. self:GetName() )
end
end
)
Mission:AddTask( self )
return self
@ -250,14 +263,6 @@ function TASK_BASE:AssignToUnit( TaskUnit )
local FsmUnit = self:SetStateMachine( TaskUnit, FsmTemplate:Copy( TaskUnit, self ) ) -- Fsm.Fsm#FSM_PROCESS
self:E({"Address FsmUnit", tostring( FsmUnit ) } )
-- Set the events
FsmUnit:EventOnPilotDead(
--- @param Core.Event#EVENTDATA EventData
function( self, EventData )
self:__Fail( 1 )
end
)
FsmUnit:SetStartState( "Planned" )
FsmUnit:Accept() -- Each Task needs to start with an Accept event to start the flow.
@ -276,7 +281,18 @@ function TASK_BASE:UnAssignFromUnit( TaskUnit )
return self
end
--- Send a message of the @{Task} to the assigned @{Group}s.
-- @param #TASK_BASE self
function TASK_BASE:MessageToGroups( Message )
self:F( { Message = Message } )
local Mission = self:GetMission()
local CC = Mission:GetCommandCenter()
for TaskGroupName, TaskGroup in pairs( self.SetGroup:GetSet() ) do
CC:MessageToGroup( Message, TaskGroup )
end
end
--- Send the briefng message of the @{Task} to the assigned @{Group}s.
-- @param #TASK_BASE self
@ -331,6 +347,29 @@ function TASK_BASE:IsAssignedToGroup( TaskGroup )
return false
end
--- Returns if the @{Task} has still alive and assigned Units.
-- @param #TASK_BASE self
-- @return #boolean
function TASK_BASE:HasAliveUnits()
self:F()
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
if self:IsStateAssigned() then
if self:IsAssignedToGroup( TaskGroup ) then
for TaskUnitID, TaskUnit in pairs( TaskGroup:GetUnits() ) do
if TaskUnit:IsAlive() then
self:T( { HasAliveUnits = true } )
return true
end
end
end
end
end
self:T( { HasAliveUnits = true } )
return false
end
--- Set the menu options of the @{Task} to all the groups in the SetGroup.
-- @param #TASK_BASE self
function TASK_BASE:SetMenu()
@ -500,6 +539,7 @@ function TASK_BASE:RemoveStateMachine( TaskUnit )
self.Fsm[TaskUnit] = nil
collectgarbage()
self:T( "Garbage Collected, Processes should be finalized now ...")
end
--- Checks if there is a FiniteStateMachine assigned to Task@{Unit} for @{Task}
@ -752,24 +792,29 @@ function TASK_BASE:SetBriefing( TaskBriefing )
return self
end
--- StateMachine callback function for a TASK
-- @param #TASK_BASE self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Event#EVENTDATA Event
function TASK_BASE:onbeforeAbort( Event, From, To )
self:E("Abort")
--- Adds a score for the TASK to be achieved.
-- @param #FSM_TEMPLATE self
-- @param #string TaskStatus is the status of the TASK when the score needs to be given.
-- @param #string ScoreText is a text describing the score that is given according the status.
-- @param #number Score is a number providing the score of the status.
-- @return #FSM_TEMPLATE self
function TASK_BASE:AddScoreTask( TaskStatus, ScoreText, Score )
self:F2( { TaskStatus, ScoreText, Score } )
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
if self:HasAliveUnits() then
return false
end
end
self.Scores[TaskStatus] = self.Scores[TaskStatus] or {}
self.Scores[TaskStatus].ScoreText = ScoreText
self.Scores[TaskStatus].Score = Score
return self
self:MessageToGroups( "Task " .. self:GetName() .. " has been aborted! Task will be replanned." )
return true
end
--- StateMachine callback function for a TASK
-- @param #TASK_BASE self
-- @param #string Event

View File

@ -92,6 +92,7 @@ end
-- @param #CLIENT self
-- @param #string ClientName Name of the DCS **Unit** as defined within the Mission Editor.
-- @param #string ClientBriefing Text that describes the briefing of the mission when a Player logs into the Client.
-- @param #boolean Error A flag that indicates whether an error should be raised if the CLIENT cannot be found. By default an error will be raised.
-- @return #CLIENT
-- @usage
-- -- Create new Clients.
@ -102,7 +103,7 @@ end
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 3' ):Transport() )
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*HOT-Deploy Troops 2' ):Transport() )
-- Mission:AddClient( CLIENT:FindByName( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() )
function CLIENT:FindByName( ClientName, ClientBriefing )
function CLIENT:FindByName( ClientName, ClientBriefing, Error )
local ClientFound = _DATABASE:FindClient( ClientName )
if ClientFound then
@ -113,7 +114,9 @@ function CLIENT:FindByName( ClientName, ClientBriefing )
return ClientFound
end
error( "CLIENT not found for: " .. ClientName )
if not Error then
error( "CLIENT not found for: " .. ClientName )
end
end
function CLIENT:Register( ClientName )

View File

@ -75,39 +75,10 @@
--- The UNIT class
-- @type UNIT
-- @extends Wrapper.Controllable#CONTROLLABLE
-- @field #UNIT.FlareColor FlareColor
-- @field #UNIT.SmokeColor SmokeColor
UNIT = {
ClassName="UNIT",
FlareColor = {
Green = trigger.flareColor.Green,
Red = trigger.flareColor.Red,
White = trigger.flareColor.White,
Yellow = trigger.flareColor.Yellow
},
SmokeColor = {
Green = trigger.smokeColor.Green,
Red = trigger.smokeColor.Red,
White = trigger.smokeColor.White,
Orange = trigger.smokeColor.Orange,
Blue = trigger.smokeColor.Blue
},
}
}
--- FlareColor
-- @type UNIT.FlareColor
-- @field Green
-- @field Red
-- @field White
-- @field Yellow
--- SmokeColor
-- @type UNIT.SmokeColor
-- @field Green
-- @field Red
-- @field White
-- @field Orange
-- @field Blue
--- Unit.SensorType
-- @type Unit.SensorType
@ -655,6 +626,7 @@ end
--- Signal a flare at the position of the UNIT.
-- @param #UNIT self
-- @param Utilities.Utils#FLARECOLOR FlareColor
function UNIT:Flare( FlareColor )
self:F2()
trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 )

View File

@ -1,5 +1,5 @@
env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' )
env.info( 'Moose Generation Timestamp: 20161209_1052' )
env.info( 'Moose Generation Timestamp: 20161213_1239' )
local base = _G

View File

@ -1,5 +1,5 @@
env.info( '*** MOOSE DYNAMIC INCLUDE START *** ' )
env.info( 'Moose Generation Timestamp: 20161209_1052' )
env.info( 'Moose Generation Timestamp: 20161213_1239' )
local base = _G

View File

@ -83,18 +83,18 @@ COPY /b Moose.lua + %1\Fsm\Process.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\Process_JTAC.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\Patrol.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\Cargo.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmTAssign.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmTRoute.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmTAccount.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmTSmoke.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmAssign.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmRoute.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmAccount.lua Moose.lua
COPY /b Moose.lua + %1\Fsm\FsmSmoke.lua Moose.lua
rem Task Handling Classes
COPY /b Moose.lua + %1\Tasking\CommandCenter.lua Moose.lua Moose.lua
COPY /b Moose.lua + %1\Mission.lua Moose.lua
COPY /b Moose.lua + %1\Task.lua Moose.lua
COPY /b Moose.lua + %1\DetectionManager.lua Moose.lua
COPY /b Moose.lua + %1\Task_SEAD.lua Moose.lua
COPY /b Moose.lua + %1\Task_A2G.lua Moose.lua
COPY /b Moose.lua + %1\Tasking\CommandCenter.lua Moose.lua
COPY /b Moose.lua + %1\Tasking\Mission.lua Moose.lua
COPY /b Moose.lua + %1\Tasking\Task.lua Moose.lua
COPY /b Moose.lua + %1\Tasking\DetectionManager.lua Moose.lua
COPY /b Moose.lua + %1\Tasking\Task_SEAD.lua Moose.lua
COPY /b Moose.lua + %1\Tasking\Task_A2G.lua Moose.lua
COPY /b Moose.lua + %1\Moose.lua Moose.lua

View File

@ -0,0 +1,33 @@
--- Simple function scheduling
--
-- ===
--
-- Author: FlightControl
-- Date Created: 12 Dec 2016
--
-- # Situation
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
-- # Test cases:
--
-- 1. The log should contain a "Hello World" line that is fired off 10 seconds after mission start.
--
--
-- # Status: TESTED - 12 Dec 2016
local TestScheduler = SCHEDULER:New( nil,
function()
BASE:E( "Hello World 1")
end, {}, 1
)
SCHEDULER:New( nil,
function()
BASE:E( "Hello World 2")
end, {}, 2
)
collectgarbage()

View File

@ -0,0 +1,34 @@
--- Simple Object Scheduling
--
-- ===
--
-- Author: FlightControl
-- Date Created: 12 Dec 2016
--
-- # Situation
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
-- # Test cases:
--
-- 1. Tracing of a scheduler in an Object.
-- The log should contain a "Hello World" line of the object, that is fired off 1 seconds after mission start.
--
-- # Status: TESTED - 12 Dec 2016
local TEST_BASE = {
ClassName = "TEST_BASE",
}
function TEST_BASE:New( Message )
self = BASE:Inherit( self, BASE:New() )
local TestScheduler = SCHEDULER:New( self,
function( Object, Message )
Object:E( Message )
end, { Message }, 1
)
end
local Test = TEST_BASE:New( "Hello World" )

View File

@ -1,8 +0,0 @@
GroupTest = GROUP:FindByName("Test")
TestScheduler = SCHEDULER:New( nil,
function()
MESSAGE:New("Hello World", 5 ):ToAll()
end, {}, 10, 10 )

View File

@ -1,28 +0,0 @@
-- This test will schedule the same function 2 times.
SpawnTest = SPAWN:New( "Test" )
TestZone = ZONE:New( "TestZone" )
local function MessageTest2()
SpawnTest:SpawnInZone( TestZone, true )
end
local function MessageTest1()
SpawnTest:SpawnInZone( TestZone, true )
-- The second after 10 seconds
SCHEDULER:New( nil, MessageTest2, {}, 5 )
-- The third after 15 seconds
SCHEDULER:New( nil, MessageTest2, {}, 10 )
end
-- The first after 5 seconds
SCHEDULER:New( nil, MessageTest1, {}, 5 )
-- The fourth after 20 seconds
SCHEDULER:New( nil, MessageTest1, {}, 20 )

View File

@ -1,16 +0,0 @@
-- This test will schedule the same function 2 times.
SpawnTest = SPAWN:New( "Test" )
TestZone = ZONE:New( "TestZone" )
local function MessageTest()
SpawnTest:SpawnInZone( TestZone, true )
end
-- The first after 5 seconds
TestScheduler1 = SCHEDULER:New( nil, MessageTest, {}, 5 )
-- The second after 10 seconds
TestScheduler2 = SCHEDULER:New( nil, MessageTest, {}, 10 )

View File

@ -0,0 +1,24 @@
--- Simple repeat scheduling of a function.
--
-- ===
--
-- Author: FlightControl
-- Date Created: 13 Dec 2016
--
-- # Situation
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
-- # Test cases:
--
-- 1. The log should contain "Hello World Repeat" lines that is fired off 1 second after mission start and is repeated every 1 seconds.
--
--
-- # Status: TESTED - 13 Dec 2016
local TestScheduler = SCHEDULER:New( nil,
function()
BASE:E( "Hello World Repeat")
end, {}, 1, 1
)

View File

@ -0,0 +1,44 @@
--- Object Repeat Scheduling.
--
-- ===
--
-- Author: FlightControl
-- Date Created: 13 Dec 2016
--
-- # Situation
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
-- Three Test objects are created.
--
-- # Test cases:
--
-- 1. Object Test1 should start after 1 seconds showing every second "Hello World Repeat 1".
-- 2. Object Test2 should start after 2 seconds showing every 2 seconds "Hello World Repeat 2" and stop after one minute.
-- 3. Object Test3 should start after 10 seconds showing with a 10 seconds randomized interval of 10 seconds "Hello World Repeat 3" and stop after one minute.
--
-- # Status: TESTED - 13 Dec 2016
local TEST_BASE = {
ClassName = "TEST_BASE",
}
function TEST_BASE:New( Message, Start, Repeat, Randomize, Stop )
self = BASE:Inherit( self, BASE:New() )
self.TestScheduler = SCHEDULER:New( self,
function( Object, Message )
Object:E( Message )
end, { Message }, Start, Repeat, Randomize, Stop
)
return self
end
do
local Test1 = TEST_BASE:New( "Hello World Repeat 1", 1, 1 )
end
local Test2 = TEST_BASE:New( "Hello World Repeat 2", 2, 2, 0, 60 )
local Test3 = TEST_BASE:New( "Hello World Repeat 3", 10, 10, 1.0, 60 )

View File

@ -0,0 +1,41 @@
--- Simple repeat scheduling of a function.
--
-- ===
--
-- Author: FlightControl
-- Date Created: 14 Dec 2016
--
-- # Situation
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
-- Start a schedule called TestScheduler. TestScheduler will repeat the words "Hello World Repeat" every second in the log.
-- After 10 seconds, TestScheduler will stop the scheduler.
-- After 20 seconds, TestScheduler will restart the scheduler.
--
-- # Test cases:
--
-- 1. Check that the "Hello World Repeat" lines are consistent with the scheduling timing. They should stop showing after 10 seconds, and restart after 20 seconds.
--
--
-- # Status: TESTED - 14 Dec 2016
local TestScheduler = SCHEDULER:New( nil,
function()
BASE:E( timer.getTime() .. " - Hello World Repeat")
end, {}, 1, 1
)
SCHEDULER:New( nil,
function()
TestScheduler:Stop()
end, {}, 10
)
SCHEDULER:New( nil,
function()
TestScheduler:Start()
end, {}, 20
)

View File

@ -0,0 +1,60 @@
--- No Object Scheduling because of garbage collect and Object nillification.
--
-- ===
--
-- Author: FlightControl
-- Date Created: 12 Dec 2016
--
-- # Situation
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
-- A Test object is created.
-- It is nillified directly after the Schedule has been planned.
-- There should be no schedule fired.
-- The Test object should be garbage collected!
--
-- THIS IS A VERY IMPORTANT TEST!
--
-- # Test cases:
--
-- 1. No schedule should be fired! The destructors of the Test object should be shown.
-- 2. Commend the nillification of the Test object in the source, and test again.
-- The schedule should now be fired and Hello World should be logged through the Test object.
--
-- # Status: STARTED - 12 Dec 2016
local TEST_BASE = {
ClassName = "TEST_BASE",
}
function TEST_BASE:New( Message )
self = BASE:Inherit( self, BASE:New() )
self.TestScheduler = SCHEDULER:New( self,
function( Object, Message )
Object:E( Message )
end, { Message }, 1
)
return self
end
do
local Test1 = TEST_BASE:New( "Hello World Test 1" )
Test1 = nil
BASE:E( Test1 )
end
local Test2 = TEST_BASE:New( "Hello World Test 2" )
BASE:E( Test2 )
local Test3 = TEST_BASE:New( "Hello World Test 3" )
Test3 = nil
BASE:E( Test3 )
collectgarbage()
BASE:E( "Collect Garbage executed." )
BASE:E( "You should only see a Hello Worlld message for Test 2!" )
BASE:E( "Check if Test 1 and Test 3 are garbage collected!" )

View File

@ -0,0 +1,80 @@
--- Object Repeat Scheduling.
--
-- ===
--
-- Author: FlightControl
-- Date Created: 13 Dec 2016
--
-- # Situation
-- Three objects Test1, Test2, Test 3 are created with schedule a function.
-- After 15 seconds, Test1 is nillified and Garbage Collect is done.
-- After 30 seconds, Test2 is nillified and Garbage Collect is done.
-- After 45 seconds, Test3 is nillified and Garbage Collect is done.
-- Uses the Tracing functions from BASE within the DCS.log file. Check the DCS.log file for the results.
-- Create a new SCHEDULER object.
-- Check the DCS.log.
--
--
-- Three Test objects are created.
--
-- # Test cases:
--
-- 1. Object Test1 should start after 1 seconds showing every second "Hello World Repeat 1".
-- 2. Object Test2 should start after 2 seconds showing every 2 seconds "Hello World Repeat 2" and stop after one minute.
-- 3. Object Test3 should start after 10 seconds showing with a 10 seconds randomized interval of 10 seconds "Hello World Repeat 3" and stop after one minute.
-- 4. After 15 seconds, Test1 should stop working. No "Hello World Repeat 1" may be shown after 15 seconds.
-- 5. After 30 seconds, Test2 should stop working. No "Hello World Repeat 2" may be shown after 30 seconds.
-- 6. After 45 seconds, Test3 should stop working. No "Hello World Repeat 3" may be shown after 45 seconds.
--
-- # Status: TESTED - 13 Dec 2016
local TEST_BASE = {
ClassName = "TEST_BASE",
}
function TEST_BASE:New( Message, Start, Repeat, Randomize, Stop )
self = BASE:Inherit( self, BASE:New() )
self.TestScheduler = SCHEDULER:New( self,
function( Object, Message )
Object:E( Message )
end, { Message }, Start, Repeat, Randomize, Stop
)
return self
end
do
local Test1 = TEST_BASE:New( "Hello World Repeat 1", 1, 1 )
-- Nillify Test1 after 15 seconds and garbage collect.
local Nil1 = SCHEDULER:New( nil,
function()
BASE:E( "Nillify Test1 and Garbage Collect" )
Test1 = nil
collectgarbage()
end, {}, 15 )
end
local Test2 = TEST_BASE:New( "Hello World Repeat 2", 2, 2, 0, 60 )
local Test3 = TEST_BASE:New( "Hello World Repeat 3", 10, 10, 1.0, 60 )
-- Nillify Test2 after 30 seconds and garbage collect.
local Nil2 = SCHEDULER:New( nil,
function()
BASE:E( "Nillify Test2 and Garbage Collect" )
Test2 = nil
collectgarbage()
end, {}, 30 )
-- Nillify Test3 after 45 seconds and garbage collect.
local Nil3 = SCHEDULER:New( nil,
function()
BASE:E( "Nillify Test3 and Garbage Collect" )
Test3 = nil
collectgarbage()
end, {}, 45 )
collectgarbage()

View File

@ -121,9 +121,9 @@ GroupZoneCompletely = GROUP:FindByName( "Zone Completely" )
GroupZonePartly = GROUP:FindByName( "Zone Partly" )
GroupZoneNot = GROUP:FindByName( "Zone Not" )
ZoneCompletely = ZONE_POLYGON:New( "Zone Completely", GroupZoneCompletely ):SmokeZone( POINT_VEC3.SmokeColor.White )
ZonePartly = ZONE_POLYGON:New( "Zone Partly", GroupZonePartly ):SmokeZone( POINT_VEC3.SmokeColor.White )
ZoneNot = ZONE_POLYGON:New( "Zone Not", GroupZoneNot ):SmokeZone( POINT_VEC3.SmokeColor.White )
ZoneCompletely = ZONE_POLYGON:New( "Zone Completely", GroupZoneCompletely ):SmokeZone( SMOKECOLOR.White )
ZonePartly = ZONE_POLYGON:New( "Zone Partly", GroupZonePartly ):SmokeZone( SMOKECOLOR.White )
ZoneNot = ZONE_POLYGON:New( "Zone Not", GroupZoneNot ):SmokeZone( SMOKECOLOR.White )
SetVehicleCompletely:ForEachGroupCompletelyInZone( ZoneCompletely,
--- @param Wrapper.Group#GROUP MooseGroup

View File

@ -1,3 +1,4 @@
-- This test mission is a test bed for the TASKING framework.
-- It creates an head quarters (HQ), which contains one mission with one task to be accomplished.
-- When the pilot joins the plane, it will need to accept the task using the HQ menu.
@ -30,6 +31,7 @@ Mission:AddScoring( Scoring )
-- Define the set of group of planes that can be assigned to the Mission object.
local SEADSet = SET_GROUP:New():FilterPrefixes( "Test SEAD"):FilterStart()
SEADSet:Flush()
-- Define the set of units that are the targets.
-- Note that I use FilterOnce, which means that the set will be defined only once,
@ -102,8 +104,27 @@ FsmSEADTemplate:AddScoreProcess( "Updated", "Account", "Failed", "failed to dest
FsmSEADTemplate:AddScore( "Success", "Destroyed all target radars", 250 )
FsmSEADTemplate:AddScore( "Failed", "Failed to destroy all target radars", -100 )
--local TestTask = TASK_BASE:New( Mission, SEADSet, "TEST TASK", "TEST" )
--TestTask:E("Clean TestTask")
--TestTask = nil
--collectgarbage()
--
--local TestUnit = GROUP:FindByName( "HQ" ):GetUnit(1)
--
--local fsm = FSM_PROCESS:New( TestUnit, TaskSEAD )
--
--fsm:AddProcess("test","test",FSM_ACCOUNT_DEADS:New( TargetSet, "SEAD" ))
--
----Mission:AddTask(fsm)
--
--fsm:E("CLEAN fsm")
--fsm = nil
--collectgarbage()
--
--
--TaskSEAD:E("CLEAN TASK")
--TaskSEAD = nil
--collectgarbage()
function FsmSEADTemplate:onenterUpdated( TaskUnit )
self:E( { self } )
@ -114,7 +135,13 @@ end
local TaskSEAD2 = TASK_BASE:New( Mission, SEADSet, "SEAD Radars Vector 2", "SEAD" ) -- Tasking.Task#TASK_BASE
TaskSEAD2:SetFsmTemplate( TaskSEAD:GetFsmTemplate():Copy() )
--Mission:AddTask( TaskSEAD2 )
Mission:AddTask( TaskSEAD2 )
Mission:RemoveTask(TaskSEAD)
TaskSEAD = nil
FsmSEADTemplate = nil
HQ:SetMenu()
collectgarbage()

View File

@ -6,7 +6,7 @@
local GroupInside = GROUP:FindByName( "Test Inside Polygon" )
local GroupOutside = GROUP:FindByName( "Test Outside Polygon" )
local ZoneA = ZONE:New( "Zone A" ):SmokeZone( POINT_VEC3.SmokeColor.White, 90 )
local ZoneA = ZONE:New( "Zone A" ):SmokeZone( SMOKECOLOR.White, 90 )
Messager = SCHEDULER:New( nil,
function()

View File

@ -7,7 +7,7 @@ local GroupInside = GROUP:FindByName( "Test Inside Polygon" )
local GroupOutside = GROUP:FindByName( "Test Outside Polygon" )
local House = STATIC:FindByName( "House" )
local ZoneA = ZONE_RADIUS:New( "Zone A", House:GetPointVec2(), 300 ):SmokeZone( POINT_VEC3.SmokeColor.White, 90 )
local ZoneA = ZONE_RADIUS:New( "Zone A", House:GetPointVec2(), 300 ):SmokeZone( SMOKECOLOR.White, 90 )
Messager = SCHEDULER:New( nil,
function()

View File

@ -8,7 +8,7 @@ local GroupOutside = GROUP:FindByName( "Test Outside Polygon" )
local GroupPolygon = GROUP:FindByName( "Polygon A" )
local PolygonZone = ZONE_POLYGON:New( "Polygon A", GroupPolygon ):SmokeZone( POINT_VEC3.SmokeColor.White, 20 )
local PolygonZone = ZONE_POLYGON:New( "Polygon A", GroupPolygon ):SmokeZone( SMOKECOLOR.White, 20 )
Messager = SCHEDULER:New( nil,
function()