Merge pull request #6 from svenvandevelde/Implement-cargo-initialization-upon-start-of-a-mission

Implement cargo initialization upon start of a mission
This commit is contained in:
Sven Van de Velde 2016-03-02 22:17:32 +01:00
commit effc400a46
28 changed files with 3377 additions and 1386 deletions

View File

@ -1,42 +1,43 @@
local base = _G
env.info("Loading MOOSE " .. base.timer.getAbsTime() )
function script_path()
local str = debug.getinfo(2, "S").source
return str:match("(.*/)"):sub(1,-2)
end
Include = {}
Include.MissionPath = script_path() .. "Mission\\"
Include.ProgramPath = "Scripts\\Moose\\Moose\\"
env.info( "Include.MissionPath = " .. Include.MissionPath)
env.info( "Include.ProgramPath = " .. Include.ProgramPath)
Include.Files = {}
Include.Path = function()
local str = debug.getinfo(2, "S").source
return str:match("(.*/)"):sub(1,-2):gsub("\\","/")
end
Include.File = function( IncludeFile )
if not Include.Files[ IncludeFile ] then
Include.Files[IncludeFile] = IncludeFile
local f = base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" )
env.info( "Include:" .. IncludeFile .. " from " .. Include.ProgramPath )
local f = assert( base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" ) )
if f == nil then
local f = base.loadfile( Include.MissionPath .. IncludeFile .. ".lua" )
env.info( "Include:" .. IncludeFile .. " from " .. Include.MissionPath )
local f = assert( base.loadfile( Include.MissionPath .. IncludeFile .. ".lua" ) )
if f == nil then
error ("Could not load MOOSE file " .. IncludeFile .. ".lua" )
else
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath )
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.MissionPath )
return f()
end
else
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.MissionPath )
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath )
return f()
end
end
end
Include.ProgramPath = "Scripts/Moose/Moose/"
Include.MissionPath = Include.Path()
env.info( "Include.ProgramPath = " .. Include.ProgramPath)
env.info( "Include.MissionPath = " .. Include.MissionPath)
Include.Files = {}
Include.File( "Database" )
env.info("Loaded MOOSE Include Engine")

View File

@ -0,0 +1,23 @@
local base = _G
env.info("Loading MOOSE " .. base.timer.getAbsTime() )
Include = {}
Include.Path = function()
local str = debug.getinfo(2, "S").source
return str:match("(.*/)"):sub(1,-2):gsub("\\","/")
end
Include.File = function( IncludeFile )
end
Include.ProgramPath = "Scripts/Moose/Moose/"
Include.MissionPath = Include.Path()
env.info( "Include.ProgramPath = " .. Include.ProgramPath)
env.info( "Include.MissionPath = " .. Include.MissionPath)
Include.Files = {}
env.info("Loaded MOOSE Include Engine")

159
Loaders/Moose_Test.lua Normal file
View File

@ -0,0 +1,159 @@
local base = _G
local MOOSE_Version = "0.1.1.1"
env.info("Loading MOOSE " .. base.timer.getAbsTime() )
function script_path()
local str = debug.getinfo(2, "S").source
return str:match("(.*/)"):sub(1,-2):gsub("\\","/")
end
Include = {}
Include.ProgramPath = "Scripts/Moose/Moose/"
Include.MissionPath = script_path()
env.info( "Include.ProgramPath = " .. Include.ProgramPath)
env.info( "Include.MissionPath = " .. Include.MissionPath)
Include.Files = {}
Include.FileIn = function(fileName, table)
-- env.info( fileName )
local chunk, errMsg = base.loadfile(fileName)
if chunk ~= nil then
env.info( "chunk assigned " )
env.info( Include.oneLineSerialize( chunk ) )
base.setfenv(chunk, table)
chunk()
if table.MOOSE_Version then
env.info( table.MOOSE_Version )
end
return chunk
else
return nil, errMsg
end
end
Include.MisFiles = {}
Include.FileName = function( num )
local hexstr = '0123456789ABCDEF'
local s = ''
while num > 0 do
local mod = math.fmod(num, 16)
s = string.sub(hexstr, mod+1, mod+1) .. s
num = math.floor(num / 16)
end
if s == '' then s = '0' end
-- env.info( string.format( "~mis" .. "%8s", "00000000" .. s ) )
return string.format( "~mis" .. "%s", string.sub( "00000000" .. s, -8 ) )
end
Include.ScanFiles = function()
local i = 0
while i <= 32767 do
local FileName = Include.FileName( i )
local FileChunk = {}
local FileChunk = Include.FileIn( Include.MissionPath .. FileName, FileChunk )
if FileChunk then
end
i = i + 1
end
end
Include.File = function( IncludeFile )
if not Include.Files[ IncludeFile ] then
Include.Files[IncludeFile] = IncludeFile
env.info( "Include:" .. IncludeFile .. " from " .. Include.ProgramPath )
local f = base.loadfile( Include.ProgramPath .. IncludeFile .. ".lua" )
if f == nil then
env.info( "Include:" .. IncludeFile .. " from " .. Include.MissionPath )
local f = base.loadfile( Include.MissionPath .. IncludeFile .. ".lua" )
if f == nil then
error ("Could not load MOOSE file " .. IncludeFile .. ".lua" )
else
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.MissionPath )
return f()
end
else
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath )
return f()
end
end
end
--porting in Slmod's "safestring" basic serialize
Include.basicSerialize = function(s)
if s == nil then
return "\"\""
else
if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then
return tostring(s)
elseif type(s) == 'string' then
s = string.format('%q', s)
return s
end
end
end
-- porting in Slmod's serialize_slmod2
Include.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
if type(tbl) == 'table' then --function only works for tables!
local tbl_str = {}
tbl_str[#tbl_str + 1] = '{'
for ind,val in pairs(tbl) do -- serialize its fields
if type(ind) == "number" then
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = tostring(ind)
tbl_str[#tbl_str + 1] = ']='
else --must be a string
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = Include.basicSerialize(ind)
tbl_str[#tbl_str + 1] = ']='
end
if ((type(val) == 'number') or (type(val) == 'boolean')) then
tbl_str[#tbl_str + 1] = tostring(val)
tbl_str[#tbl_str + 1] = ','
elseif type(val) == 'string' then
tbl_str[#tbl_str + 1] = Include.basicSerialize(val)
tbl_str[#tbl_str + 1] = ','
elseif type(val) == 'nil' then -- won't ever happen, right?
tbl_str[#tbl_str + 1] = 'nil,'
elseif type(val) == 'table' then
if ind == "__index" then
tbl_str[#tbl_str + 1] = "__index"
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
tbl_str[#tbl_str + 1] = Include.oneLineSerialize(val)
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
end
elseif type(val) == 'function' then
tbl_str[#tbl_str + 1] = "function " .. tostring(ind)
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
env.info('unable to serialize value type ' .. Include.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
env.info( debug.traceback() )
end
end
tbl_str[#tbl_str + 1] = '}'
return table.concat(tbl_str)
else
return tostring(tbl)
end
end
Include.ScanFiles( )
Include.File( "Database" )
env.info("Loaded MOOSE Include Engine")

View File

@ -4,12 +4,22 @@
Include.File( "Routines" )
_TraceOn = true
_TraceClass = {
DATABASE = true,
--SEAD = true,
--DESTROYBASETASK = true,
--MOVEMENT = true,
--SPAWN = true,
--GROUP = true,
--UNIT = true,
}
BASE = {
ClassName = "BASE",
ClassID = 0,
Events = {}
}
--- The base constructor. This is the top top class of all classed defined within the MOOSE.
@ -53,7 +63,7 @@ function BASE:Inherit( Child, Parent )
Child.__index = Child
end
--Child.ClassName = Child.ClassName .. '.' .. Child.ClassID
trace.i( Child.ClassName, 'Inherited from ' .. Parent.ClassName )
self:T( 'Inherited from ' .. Parent.ClassName )
return Child
end
@ -104,6 +114,7 @@ trace.f( self.ClassName )
return self
end
BaseEventCodes = {
"S_EVENT_SHOT",
"S_EVENT_HIT",
@ -129,7 +140,46 @@ BaseEventCodes = {
"S_EVENT_SHOOTING_START",
"S_EVENT_SHOOTING_END",
"S_EVENT_MAX",
}
}
--onEvent( {[1]="S_EVENT_BIRTH",[2]={["subPlace"]=5,["time"]=0,["initiator"]={["id_"]=16884480,},["place"]={["id_"]=5000040,},["id"]=15,["IniUnitName"]="US F-15C@RAMP-Air Support Mountains#001-01",},}
-- Event = {
-- id = enum world.event,
-- time = Time,
-- initiator = Unit,
-- target = Unit,
-- place = Unit,
-- subPlace = enum world.BirthPlace,
-- weapon = Weapon
-- }
function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace )
trace.f( self.ClassName, { EventTime, Initiator, IniUnitName, place, subplace } )
local Event = {
id = world.event.S_EVENT_BIRTH,
time = EventTime,
initiator = Initiator,
IniUnitName = IniUnitName,
place = place,
subplace = subplace
}
world.onEvent( Event )
end
function BASE:CreateEventCrash( EventTime, Initiator )
trace.f( self.ClassName, { EventTime, Initiator } )
local Event = {
id = world.event.S_EVENT_CRASH,
time = EventTime,
initiator = Initiator,
}
world.onEvent( Event )
end
function BASE:onEvent(event)
--trace.f(self.ClassName, event )
@ -159,3 +209,22 @@ function BASE:onEvent(event)
end
-- Trace section
function BASE:T( Arguments )
if _TraceOn and _TraceClass[self.ClassName] then
local DebugInfo = debug.getinfo( 2, "nl" )
local Function = "function"
if DebugInfo.name then
Function = DebugInfo.name
end
local Line = DebugInfo.currentline
env.info( string.format( "%6d/%1s:%20s%05d.%s\(%s\)" , Line, "T", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
end
end

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,6 @@ CLIENT = {
ClientTransport = false,
ClientBriefingShown = false,
_Menus = {},
_Cargos = {},
_Tasks = {},
Messages = {
}
@ -45,10 +44,9 @@ CLIENT = {
-- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() )
function CLIENT:New( ClientName, ClientBriefing )
trace.f(self.ClassName)
-- Arrange meta tables
local self = BASE:Inherit( self, BASE:New() )
self:T()
self.ClientName = ClientName
self:AddBriefing( ClientBriefing )
self.MessageSwitch = true
@ -59,29 +57,162 @@ end
--- Resets a CLIENT.
-- @tparam string ClientName Name of the Group as defined within the Mission Editor. The Group must have a Unit with the type Client.
function CLIENT:Reset( ClientName )
trace.f(self.ClassName)
self:T()
self._Menus = {}
self._Cargos = {}
end
--- ClientGroup returns the Group of a Client.
-- This function is modified to deal with a couple of bugs in DCS 1.5.3
-- @treturn Group
function CLIENT:ClientGroup()
--trace.f(self.ClassName)
local ClientData = Group.getByName( self.ClientName )
if ClientData and ClientData:isExist() then
trace.i( self.ClassName, self.ClientName .. " : group found!" )
return ClientData
else
-- trace.x( self.ClassName, self.ClientName .. " : no group found!" )
return nil
--self:T()
-- local ClientData = Group.getByName( self.ClientName )
-- if ClientData and ClientData:isExist() then
-- self:T( self.ClientName .. " : group found!" )
-- return ClientData
-- else
-- return nil
-- end
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ) }
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
--self:T( { "CoalitionData:", CoalitionData } )
for UnitId, UnitData in pairs( CoalitionData ) do
--self:T( { "UnitData:", UnitData } )
if UnitData and UnitData:isExist() then
local ClientGroup = Group.getByName( self.ClientName )
if ClientGroup then
self:T( "ClientGroup = " .. self.ClientName )
if ClientGroup:isExist() then
if ClientGroup:getID() == UnitData:getGroup():getID() then
self:T( "Normal logic" )
self:T( self.ClientName .. " : group found!" )
return ClientGroup
end
else
-- Now we need to resolve the bugs in DCS 1.5 ...
-- Consult the database for the units of the Client Group. (ClientGroup:getUnits() returns nil)
self:T( "Bug 1.5 logic" )
local ClientUnits = _Database.Groups[self.ClientName].Units
self:T( { ClientUnits[1].name, env.getValueDictByKey(ClientUnits[1].name) } )
for ClientUnitID, ClientUnitData in pairs( ClientUnits ) do
self:T( { tonumber(UnitData:getID()), ClientUnitData.unitId } )
if tonumber(UnitData:getID()) == ClientUnitData.unitId then
local ClientGroupTemplate = _Database.Groups[self.ClientName].Template
self.ClientGroupID = ClientGroupTemplate.groupId
self.ClientGroupUnit = UnitData
self:T( self.ClientName .. " : group found in bug 1.5 resolvement logic!" )
return ClientGroup
end
end
end
-- else
-- error( "Client " .. self.ClientName .. " not found!" )
end
end
end
end
-- For non player clients
local ClientGroup = Group.getByName( self.ClientName )
if ClientGroup then
self:T( "ClientGroup = " .. self.ClientName )
if ClientGroup:isExist() then
self:T( "Normal logic" )
self:T( self.ClientName .. " : group found!" )
return ClientGroup
end
end
self.ClientGroupID = nil
self.ClientGroupUnit = nil
return nil
end
function CLIENT:GetClientGroupID()
self:T()
ClientGroup = self:ClientGroup()
if ClientGroup then
if ClientGroup:isExist() then
return ClientGroup:getID()
else
return self.ClientGroupID
end
end
return nil
end
function CLIENT:GetClientGroupName()
self:T()
ClientGroup = self:ClientGroup()
if ClientGroup then
if ClientGroup:isExist() then
self:T( ClientGroup:getName() )
return ClientGroup:getName()
else
self:T( self.ClientName )
return self.ClientName
end
end
return nil
end
--- Returns the Unit of the @{CLIENT}.
-- @treturn Unit
function CLIENT:GetClientGroupUnit()
self:T()
local ClientGroup = self:ClientGroup()
if ClientGroup then
if ClientGroup:isExist() then
return ClientGroup:getUnits()[1]
else
return self.ClientGroupUnit
end
end
return nil
end
function CLIENT:GetUnit()
self:T()
return UNIT:New( self:GetClientGroupUnit() )
end
--- Returns the Position of the @{CLIENT}.
-- @treturn Position
function CLIENT:ClientPosition()
--self:T()
ClientGroupUnit = self:GetClientGroupUnit()
if ClientGroupUnit then
if ClientGroupUnit:isExist() then
return ClientGroupUnit:getPosition()
end
end
return nil
end
--- Transport defines that the Client is a Transport.
-- @treturn CLIENT
function CLIENT:Transport()
trace.f(self.ClassName)
self:T()
self.ClientTransport = true
return self
@ -91,7 +222,7 @@ end
-- @tparam string ClientBriefing is the text defining the Mission briefing.
-- @treturn CLIENT
function CLIENT:AddBriefing( ClientBriefing )
trace.f(self.ClassName)
self:T()
self.ClientBriefing = ClientBriefing
return self
end
@ -99,114 +230,29 @@ end
--- IsTransport returns if a Client is a transport.
-- @treturn bool
function CLIENT:IsTransport()
trace.f(self.ClassName)
self:T()
return self.ClientTransport
end
--- FindCargo finds loaded Cargo within a CLIENT instance.
-- Cargo is loaded when certain PICK-UP or DEPLOY Tasks are properly executed.
-- @tparam string CargoName is the name of the cargo.
-- @treturn CARGO_TYPE
function CLIENT:FindCargo( CargoName )
trace.f(self.ClassName)
return self._Cargos[CargoName]
end
--- ShowCargo shows the @{CARGO} within the CLIENT to the Player.
-- The @{CARGO} is shown throught the MESSAGE system of DCS World.
function CLIENT:ShowCargo()
trace.f(self.ClassName)
self:T()
local CargoMsg = ""
local CargoMsg = ""
for CargoName, Cargo in pairs( self._Cargos ) do
if CargoMsg ~= "" then
CargoMsg = CargoMsg .. "\n"
end
CargoMsg = CargoMsg .. Cargo.CargoName .. " Type:" .. Cargo.CargoType.TEXT .. " Weight: " .. Cargo.CargoWeight
end
if CargoMsg == '' then
CargoMsg = "empty"
end
self:Message( CargoMsg, 15, self.ClientName .. "/Cargo", "Co-Pilot: Cargo Status", 30 )
end
--- InitCargo allows to initialize @{CARGO} on the CLIENT when the client initializes.
-- @tparam string InitCargoNames is a string or a table containing the names of the @{CARGO}s initialized in the Mission.
-- @treturn CLIENT
function CLIENT:InitCargo( InitCargoNames )
trace.f(self.ClassName, { InitCargoNames } )
local Valid = true
if Valid then
if type( InitCargoNames ) == "table" then
self.InitCargoNames = InitCargoNames
else
self.InitCargoNames = { InitCargoNames }
for CargoName, Cargo in pairs( CARGOS ) do
if self == Cargo:IsLoadedInClient() then
CargoMsg = CargoMsg .. Cargo.CargoName .. " Type:" .. Cargo.CargoType .. " Weight: " .. Cargo.CargoWeight .. "\n"
end
end
end
return self
end
--- AddCargo allows to add @{CARGO} on the CLIENT.
-- @tparam string CargoName is the name of the @{CARGO}.
-- @tparam string CargoGroupName is the name of an active Group defined within the Mission Editor or Dynamically Spawned. Note that this is only applicable for Unit @{CARGO} Types.
-- @tparam CARGO_TYPE CargoType is the Type of the @{CARGO}.
-- @tparam number CargoWeight is the weight of the cargo in Kg.
-- @tparam string CargoGroupTemplate is the name of an active Group defined within the Mission Editor with "Late Activation".
-- @treturn CLIENT
function CLIENT:AddCargo( CargoName, CargoGroupName, CargoType, CargoWeight, CargoGroupTemplate )
trace.f(self.ClassName, { CargoName, CargoGroupName, CargoType, CargoWeight, CargoGroupTemplate } )
local Valid = true
Valid = routines.ValidateString( CargoName, "CargoName", Valid )
Valid = routines.ValidateEnumeration( CargoType, "CargoType", CARGO_TYPE, Valid )
Valid = routines.ValidateNumber( CargoWeight, "CargoWeight", Valid )
if Valid then
local Cargo = {}
Cargo.CargoName = CargoName
Cargo.CargoGroupName = CargoGroupName
Cargo.CargoType = CargoType
Cargo.CargoWeight = CargoWeight
if CargoGroupTemplate then
Cargo.CargoGroupTemplate = CargoGroupTemplate
if CargoMsg == "" then
CargoMsg = "empty"
end
self._Cargos[CargoName] = Cargo
self:ShowCargo()
end
return self
end
self:Message( CargoMsg, 15, self.ClientName .. "/Cargo", "Co-Pilot: Cargo Status", 30 )
--- RemoveCargo removes @{CARGO} from the CLIENT.
-- @tparam string CargoName is the name of the @{CARGO}.
-- @treturn Cargo
function CLIENT:RemoveCargo( CargoName )
trace.f(self.ClassName, { CargoName } )
local Valid = true
local Cargo = nil
Valid = routines.ValidateString( CargoName, "CargoName", Valid )
if Valid then
trace.i( "CLIENT", "RemoveCargo: CargoName = " .. CargoName )
Cargo = routines.utils.deepCopy( self._Cargos[CargoName] )
self._Cargos[CargoName] = nil
end
return Cargo
end
--- SwitchMessages is a local function called by the DCS World Menu system to switch off messages.
@ -222,13 +268,13 @@ end
-- @tparam string MessageCategory is the category of the message (the title).
-- @tparam number MessageInterval is the interval in seconds between the display of the Message when the CLIENT is in the air.
function CLIENT:Message( Message, MessageDuration, MessageId, MessageCategory, MessageInterval )
trace.f( self.ClassName, { Message, MessageDuration, MessageId, MessageCategory, MessageInterval } )
self:T()
if not self.MenuMessages then
if self:ClientGroup() and self:ClientGroup():getID() then
self.MenuMessages = MENU_SUB_GROUP:New( self:ClientGroup():getID(), 'Messages' )
self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:ClientGroup():getID(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } )
self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:ClientGroup():getID(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } )
if self:GetClientGroupID() then
self.MenuMessages = MENU_SUB_GROUP:New( self:GetClientGroupID(), 'Messages' )
self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetClientGroupID(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } )
self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetClientGroupID(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } )
end
end
@ -248,7 +294,7 @@ trace.f( self.ClassName, { Message, MessageDuration, MessageId, MessageCategory,
end
MESSAGE:New( Message, MessageCategory, MessageDuration, MessageId ):ToClient( self )
else
if self:ClientGroup() and self:ClientGroup():getUnits() and self:ClientGroup():getUnits()[1] and not self:ClientGroup():getUnits()[1]:inAir() then
if self:GetClientGroupUnit() and not self:GetClientGroupUnit():inAir() then
if timer.getTime() - self.Messages[MessageId].MessageTime >= self.Messages[MessageId].MessageDuration + 10 then
MESSAGE:New( Message, MessageCategory, MessageDuration, MessageId ):ToClient( self )
self.Messages[MessageId].MessageTime = timer.getTime()

View File

@ -13,6 +13,7 @@ DATABASE = {
NavPoints = {},
Statics = {},
Players = {},
ActivePlayers = {},
ClientsByName = {},
ClientsByID = {},
}
@ -27,7 +28,7 @@ DATABASECategory =
{
[Unit.Category.AIRPLANE] = "Plane",
[Unit.Category.HELICOPTER] = "Helicopter",
[Unit.Category.GROUND_UNIT] = "Ground",
[Unit.Category.GROUND_UNIT] = "Vehicle",
[Unit.Category.SHIP] = "Ship",
[Unit.Category.STRUCTURE] = "Structure",
}
@ -39,7 +40,6 @@ DATABASECategory =
-- -- Define a new DATABASE Object. This DBObject will contain a reference to all Group and Unit Templates defined within the ME and the DCSRTE.
-- DBObject = DATABASE:New()
function DATABASE:New()
trace.f(self.ClassName )
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
@ -120,14 +120,14 @@ trace.f(self.ClassName )
return self
end
--- Instantiate new Groups within the DCSRTE.
-- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined:
-- SpawnCountryID, SpawnCategoryID
-- This method is used by the SPAWN class.
function DATABASE:Spawn( SpawnTemplate )
trace.f( self.ClassName, SpawnTemplate )
trace.i( self.ClassName, { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID, SpawnTemplate.name } )
self:T( { SpawnTemplate.SpawnCountryID, SpawnTemplate.SpawnCategoryID, SpawnTemplate.name } )
local SpawnCountryID = SpawnTemplate.SpawnCountryID
local SpawnCategoryID = SpawnTemplate.SpawnCategoryID
@ -140,16 +140,18 @@ trace.f( self.ClassName, SpawnTemplate )
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
end
--- Set a status to a Group within the Database, this to check crossing events for example.
function DATABASE:SetStatusGroup( GroupName, Status )
trace.f( self.ClassName, Status )
self:T( Status )
self.Groups[GroupName].Status = Status
end
--- Get a status to a Group within the Database, this to check crossing events for example.
function DATABASE:GetStatusGroup( GroupName )
trace.f( self.ClassName, Status )
self:T( Status )
if self.Groups[GroupName] then
return self.Groups[GroupName].Status
@ -162,6 +164,7 @@ end
--- Private
-- @section Private
--- Registers new Group Templates within the DATABASE Object.
function DATABASE:_RegisterGroup( GroupTemplate )
@ -175,7 +178,9 @@ function DATABASE:_RegisterGroup( GroupTemplate )
self.Groups[GroupTemplateName].Template = GroupTemplate
self.Groups[GroupTemplateName].groupId = GroupTemplate.groupId
self.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units
trace.i( self.ClassName, { "Group", self.Groups[GroupTemplateName].GroupName, self.Groups[GroupTemplateName].UnitCount } )
self.Groups[GroupTemplateName].Units = GroupTemplate.units
self:T( { "Group", self.Groups[GroupTemplateName].GroupName, self.Groups[GroupTemplateName].UnitCount } )
for unit_num, UnitTemplate in pairs(GroupTemplate.units) do
@ -190,20 +195,24 @@ function DATABASE:_RegisterGroup( GroupTemplate )
self.ClientsByName[UnitTemplateName] = UnitTemplate
self.ClientsByID[UnitTemplate.unitId] = UnitTemplate
end
trace.i( self.ClassName, { "Unit", self.Units[UnitTemplateName].UnitName } )
self:T( { "Unit", self.Units[UnitTemplateName].UnitName } )
end
end
--- Events
-- @section Events
--- Track DCSRTE DEAD or CRASH events for the internal scoring.
function DATABASE:OnDeadOrCrash( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
local TargetUnitName = nil
local TargetGroupName = nil
local TargetPlayerName = nil
local TargetUnit = nil
local TargetGroup = nil
local TargetUnitName = ""
local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil
local TargetCategory = nil
local TargetType = nil
@ -212,30 +221,42 @@ trace.f( self.ClassName, { event } )
local TargetUnitType = nil
if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
TargetUnitName = event.initiator:getName()
TargetGroupName = Unit.getGroup(event.initiator):getName()
TargetPlayerName = event.initiator:getPlayerName()
TargetUnit = event.initiator
TargetGroup = Unit.getGroup( TargetUnit )
TargetUnitDesc = TargetUnit:getDesc()
TargetUnitName = TargetUnit:getName()
if TargetGroup and TargetGroup:isExist() then
TargetGroupName = TargetGroup:getName()
end
TargetPlayerName = TargetUnit:getPlayerName()
TargetCoalition = Unit.getGroup(event.initiator):getCoalition()
TargetCategory = Unit.getGroup(event.initiator):getCategory()
TargetType = event.initiator:getTypeName()
TargetCoalition = TargetUnit:getCoalition()
--TargetCategory = TargetUnit:getCategory()
TargetCategory = TargetUnitDesc.category -- Workaround
TargetType = TargetUnit:getTypeName()
TargetUnitCoalition = DATABASECoalition[TargetCoalition]
TargetUnitCategory = DATABASECategory[TargetCategory]
TargetUnitType = TargetType
trace.i( self.ClassName, { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
end
for PlayerName, PlayerData in pairs( self.Players ) do
if PlayerData then -- This should normally not happen, but i'll test it anyway.
trace.i( self.ClassName, "Something got killed" )
self:T( "Something got killed" )
-- Some variables
local InitUnitCoalition = DATABASECoalition[PlayerData.UnitCoalition]
local InitUnitCategory = DATABASECategory[PlayerData.UnitCategory]
local InitUnitType = PlayerData.UnitType
local InitUnitName = PlayerData.UnitName
local InitUnitType = PlayerData.UnitType
local InitCoalition = PlayerData.UnitCoalition
local InitCategory = PlayerData.UnitCategory
local InitUnitCoalition = DATABASECoalition[InitCoalition]
local InitUnitCategory = DATABASECategory[InitCategory]
self:T( { InitUnitName, InitUnitType, InitUnitCoalition, InitCoalition, InitUnitCategory, InitCategory } )
-- What is he hitting?
if TargetCategory then
@ -251,17 +272,17 @@ trace.f( self.ClassName, { event } )
PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = 0
end
if PlayerData.UnitCoalition == TargetCoalition then
if InitCoalition == TargetCoalition then
PlayerData.Kill[TargetCategory][TargetType].Penalty = PlayerData.Kill[TargetCategory][TargetType].Penalty + 25
PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = PlayerData.Kill[TargetCategory][TargetType].PenaltyKill + 1
MESSAGE:New( "Player '" .. PlayerName .. "' killed a target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
PlayerData.Kill[TargetCategory][TargetType].PenaltyKill .. " times. Score: " .. PlayerData.Kill[TargetCategory][TargetType].Penalty,
"Game Status: Score", 20, "/PENALTY" .. PlayerName .. "/" .. InitUnitName ):ToAll()
MESSAGE:New( "Player '" .. PlayerName .. "' killed a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
PlayerData.Kill[TargetCategory][TargetType].PenaltyKill .. " times. Penalty: -" .. PlayerData.Kill[TargetCategory][TargetType].Penalty,
"Game Status: Penalty", 20, "/PENALTY" .. PlayerName .. "/" .. InitUnitName ):ToAll()
self:ScoreAdd( PlayerName, "KILL_PENALTY", 1, -125, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
else
PlayerData.Kill[TargetCategory][TargetType].Score = PlayerData.Kill[TargetCategory][TargetType].Score + 10
PlayerData.Kill[TargetCategory][TargetType].ScoreKill = PlayerData.Kill[TargetCategory][TargetType].ScoreKill + 1
MESSAGE:New( "Player '" .. PlayerName .. "' killed a target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
MESSAGE:New( "Player '" .. PlayerName .. "' killed an enemy " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
PlayerData.Kill[TargetCategory][TargetType].ScoreKill .. " times. Score: " .. PlayerData.Kill[TargetCategory][TargetType].Score,
"Game Status: Score", 20, "/SCORE" .. PlayerName .. "/" .. InitUnitName ):ToAll()
self:ScoreAdd( PlayerName, "KILL_SCORE", 1, 10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
@ -272,12 +293,14 @@ trace.f( self.ClassName, { event } )
end
end
--- Scheduled
-- @section Scheduled
--- Follows new players entering Clients within the DCSRTE.
function DATABASE:_FollowPlayers()
trace.scheduled( self.ClassName, "_FollowPlayers" )
self:T( "_FollowPlayers" )
local ClientUnit = 0
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers(coalition.side.RED), AlivePlayersBlue = coalition.getPlayers(coalition.side.BLUE) }
@ -286,73 +309,73 @@ trace.scheduled( self.ClassName, "_FollowPlayers" )
local AlivePlayerUnits = {}
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
trace.l( self.ClassName, "_FollowPlayers", CoalitionData )
self:T( { "_FollowPlayers", CoalitionData } )
for UnitId, UnitData in pairs( CoalitionData ) do
self:_AddPlayerFromUnit( UnitData )
end
end
end
--- Private
-- @section Private
--- Add a new player entering a Unit.
function DATABASE:_AddPlayerFromUnit( UnitData )
trace.f( self.ClassName, UnitData )
self:T( UnitData )
if UnitData:isExist() then
local UnitName = UnitData:getName()
local GroupData = UnitData:getGroup()
local PlayerName = UnitData:getPlayerName()
local UnitDesc = UnitData:getDesc()
local UnitCategory = UnitDesc.category
local UnitCoalition = UnitData:getCoalition()
local UnitTypeName = UnitData:getTypeName()
if GroupData and GroupData:isExist() then
local GroupName = GroupData:getName()
local PlayerName = UnitData:getPlayerName()
self:T( { PlayerName, UnitName, UnitCategory, UnitCoalition, UnitTypeName } )
trace.i(self.ClassName, "Player : " .. PlayerName .. " Unit : " .. UnitName .. " Group : " .. GroupName )
if self.Players[PlayerName] == nil then -- I believe this is the place where a Player gets a life in a mission when he enters a unit ...
self.Players[PlayerName] = {}
self.Players[PlayerName].Hit = {}
self.Players[PlayerName].Kill = {}
self.Players[PlayerName].Mission = {}
-- for CategoryID, CategoryName in pairs( DATABASECategory ) do
-- self.Players[PlayerName].Hit[CategoryID] = {}
-- self.Players[PlayerName].Kill[CategoryID] = {}
-- end
self.Players[PlayerName].HitPlayers = {}
self.Players[PlayerName].HitUnits = {}
self.Players[PlayerName].Penalty = 0
self.Players[PlayerName].PenaltyCoalition = 0
end
if not self.Players[PlayerName].UnitCoalition then
self.Players[PlayerName].UnitCoalition = Unit.getGroup(UnitData):getCoalition()
else
if self.Players[PlayerName].UnitCoalition ~= Unit.getGroup(UnitData):getCoalition() then
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
MESSAGE:New( "Player '" .. PlayerName .. "' changed coalition from " .. DATABASECoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. DATABASECoalition[Unit.getGroup(UnitData):getCoalition()] ..
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.",
"Game Status: Penalty", 20, "/PENALTYCOALITION" .. PlayerName ):ToAll()
self:ScoreAdd( PlayerName, "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, DATABASECoalition[self.Players[PlayerName].UnitCoalition], DATABASECategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
UnitName, DATABASECategory[Unit.getGroup(UnitData):getCoalition()], DATABASECategory[Unit.getGroup(UnitData):getCategory()], UnitData:getTypeName() )
end
end
self.Players[PlayerName].UnitName = UnitName
self.Players[PlayerName].GroupName = GroupName
self.Players[PlayerName].UnitCoalition = Unit.getGroup(UnitData):getCoalition()
self.Players[PlayerName].UnitCategory = Unit.getGroup(UnitData):getCategory()
self.Players[PlayerName].UnitType = UnitData:getTypeName()
if self.Players[PlayerName] == nil then -- I believe this is the place where a Player gets a life in a mission when he enters a unit ...
self.Players[PlayerName] = {}
self.Players[PlayerName].Hit = {}
self.Players[PlayerName].Kill = {}
self.Players[PlayerName].Mission = {}
-- for CategoryID, CategoryName in pairs( DATABASECategory ) do
-- self.Players[PlayerName].Hit[CategoryID] = {}
-- self.Players[PlayerName].Kill[CategoryID] = {}
-- end
self.Players[PlayerName].HitPlayers = {}
self.Players[PlayerName].HitUnits = {}
self.Players[PlayerName].Penalty = 0
self.Players[PlayerName].PenaltyCoalition = 0
end
if not self.Players[PlayerName].UnitCoalition then
self.Players[PlayerName].UnitCoalition = UnitCoalition
else
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
MESSAGE:New( "Player '" .. PlayerName .. "' changed coalition from " .. DATABASECoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. DATABASECoalition[UnitCoalition] ..
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.",
"Game Status: Penalty", 20, "/PENALTYCOALITION" .. PlayerName ):ToAll()
self:ScoreAdd( PlayerName, "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, DATABASECoalition[self.Players[PlayerName].UnitCoalition], DATABASECategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
UnitName, DATABASECoalition[UnitCoalition], DATABASECategory[UnitCategory], UnitData:getTypeName() )
end
end
self.Players[PlayerName].UnitName = UnitName
self.Players[PlayerName].UnitCoalition = UnitCoalition
self.Players[PlayerName].UnitCategory = UnitCategory
self.Players[PlayerName].UnitType = UnitTypeName
end
end
--- Registers Scores the players completing a Mission Task.
function DATABASE:_AddMissionTaskScore( PlayerUnit, MissionName, Score )
trace.f( self.ClassName, { PlayerUnit, MissionName, Score } )
self:T( { PlayerUnit, MissionName, Score } )
local PlayerName = PlayerUnit:getPlayerName()
@ -361,6 +384,9 @@ trace.f( self.ClassName, { PlayerUnit, MissionName, Score } )
self.Players[PlayerName].Mission[MissionName].ScoreTask = 0
self.Players[PlayerName].Mission[MissionName].ScoreMission = 0
end
self:T( PlayerName )
self:T( self.Players[PlayerName].Mission[MissionName] )
self.Players[PlayerName].Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
@ -374,7 +400,7 @@ end
--- Registers Mission Scores for possible multiple players that contributed in the Mission.
function DATABASE:_AddMissionScore( MissionName, Score )
trace.f( self.ClassName, { PlayerUnit, MissionName, Score } )
self:T( { PlayerUnit, MissionName, Score } )
for PlayerName, PlayerData in pairs( self.Players ) do
@ -388,15 +414,18 @@ trace.f( self.ClassName, { PlayerUnit, MissionName, Score } )
end
end
--- Events
-- @section Events
function DATABASE:OnHit( event )
trace.f( self.ClassName, { event } )
local InitUnitName = nil
local InitGroupName = nil
local InitPlayerName = nil
function DATABASE:OnHit( event )
self:T( { event } )
local InitUnit = nil
local InitUnitName = ""
local InitGroupName = ""
local InitPlayerName = "dummy"
local InitCoalition = nil
local InitCategory = nil
@ -405,9 +434,10 @@ trace.f( self.ClassName, { event } )
local InitUnitCategory = nil
local InitUnitType = nil
local TargetUnitName = nil
local TargetGroupName = nil
local TargetPlayerName = nil
local TargetUnit = nil
local TargetUnitName = ""
local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil
local TargetCategory = nil
@ -419,49 +449,65 @@ trace.f( self.ClassName, { event } )
if event.initiator and event.initiator:getName() then
if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
InitUnit = event.initiator
InitGroup = Unit.getGroup( InitUnit )
InitUnitDesc = InitUnit:getDesc()
InitUnitName = event.initiator:getName()
InitGroupName = Unit.getGroup(event.initiator):getName()
InitPlayerName = event.initiator:getPlayerName()
InitUnitName = InitUnit:getName()
if InitGroup and InitGroup:isExist() then
InitGroupName = InitGroup:getName()
end
InitPlayerName = InitUnit:getPlayerName()
InitCoalition = Unit.getGroup(event.initiator):getCoalition()
InitCategory = Unit.getGroup(event.initiator):getCategory()
InitType = event.initiator:getTypeName()
InitCoalition = InitUnit:getCoalition()
--InitCategory = InitUnit:getCategory()
InitCategory = InitUnitDesc.category -- Workaround
InitType = InitUnit:getTypeName()
InitUnitCoalition = DATABASECoalition[InitCoalition]
InitUnitCategory = DATABASECategory[InitCategory]
InitUnitType = InitType
trace.i( self.ClassName, { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType , InitUnitCoalition, InitUnitCategory, InitUnitType } )
self:T( { InitUnitName, InitGroupName, InitPlayerName, InitCoalition, InitCategory, InitType , InitUnitCoalition, InitUnitCategory, InitUnitType } )
self:T( { InitUnitDesc } )
end
if event.target and Object.getCategory(event.target) == Object.Category.UNIT then
TargetUnit = event.target
TargetGroup = Unit.getGroup( TargetUnit )
TargetUnitDesc = TargetUnit:getDesc()
TargetUnitName = event.target:getName()
TargetGroupName = Unit.getGroup(event.target):getName()
TargetPlayerName = event.target:getPlayerName()
TargetUnitName = TargetUnit:getName()
if TargetGroup and TargetGroup:isExist() then
TargetGroupName = TargetGroup:getName()
end
TargetPlayerName = TargetUnit:getPlayerName()
TargetCoalition = Unit.getGroup(event.target):getCoalition()
TargetCategory = Unit.getGroup(event.target):getCategory()
TargetType = event.target:getTypeName()
TargetCoalition = TargetUnit:getCoalition()
--TargetCategory = TargetUnit:getCategory()
TargetCategory = TargetUnitDesc.category -- Workaround
TargetType = TargetUnit:getTypeName()
TargetUnitCoalition = DATABASECoalition[TargetCoalition]
TargetUnitCategory = DATABASECategory[TargetCategory]
TargetUnitType = TargetType
trace.i( self.ClassName, { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType, TargetUnitCoalition, TargetUnitCategory, TargetUnitType } )
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType, TargetUnitCoalition, TargetUnitCategory, TargetUnitType } )
self:T( { TargetUnitDesc } )
end
if InitPlayerName ~= nil then -- It is a player that is hitting something
self:_AddPlayerFromUnit( event.initiator )
self:_AddPlayerFromUnit( InitUnit )
if self.Players[InitPlayerName] then -- This should normally not happen, but i'll test it anyway.
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
self:_AddPlayerFromUnit( event.target )
self:_AddPlayerFromUnit( TargetUnit )
self.Players[InitPlayerName].HitPlayers = self.Players[InitPlayerName].HitPlayers + 1
end
trace.i( self.ClassName, "Hitting Something" )
self:T( "Hitting Something" )
-- What is he hitting?
if TargetCategory then
if not self.Players[InitPlayerName].Hit[TargetCategory] then
@ -479,7 +525,7 @@ trace.f( self.ClassName, { event } )
self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty + 10
self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit + 1
MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit .. " times. Penalty: " .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty,
self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit .. " times. Penalty: -" .. self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty,
"Game Status: Penalty", 20, "/PENALTY" .. InitPlayerName .. "/" .. InitUnitName ):ToAll()
self:ScoreAdd( InitPlayerName, "HIT_PENALTY", 1, -25, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
else
@ -498,14 +544,132 @@ trace.f( self.ClassName, { event } )
end
end
function DATABASE:ReportScoreAll()
env.info( "Hello World " )
local ScoreMessage = ""
local PlayerMessage = ""
self:T( "Score Report" )
for PlayerName, PlayerData in pairs( self.Players ) do
if PlayerData then -- This should normally not happen, but i'll test it anyway.
trace.i( self.ClassName, "Score" )
self:T( "Score Player: " .. PlayerName )
-- Some variables
local InitUnitCoalition = DATABASECoalition[PlayerData.UnitCoalition]
local InitUnitCategory = DATABASECategory[PlayerData.UnitCategory]
local InitUnitType = PlayerData.UnitType
local InitUnitName = PlayerData.UnitName
local PlayerScore = 0
local PlayerPenalty = 0
ScoreMessage = ":\n"
local ScoreMessageHits = ""
for CategoryID, CategoryName in pairs( DATABASECategory ) do
self:T( CategoryName )
if PlayerData.Hit[CategoryID] then
local Score = 0
local ScoreHit = 0
local Penalty = 0
local PenaltyHit = 0
self:T( "Hit scores exist for player " .. PlayerName )
for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do
Score = Score + UnitData.Score
ScoreHit = ScoreHit + UnitData.ScoreHit
Penalty = Penalty + UnitData.Penalty
PenaltyHit = UnitData.PenaltyHit
end
local ScoreMessageHit = string.format( "%s:%d ", CategoryName, Score - Penalty )
self:T( ScoreMessageHit )
ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit
PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty
else
--ScoreMessageHits = ScoreMessageHits .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 )
end
end
if ScoreMessageHits ~= "" then
ScoreMessage = ScoreMessage .. " Hits: " .. ScoreMessageHits .. "\n"
end
local ScoreMessageKills = ""
for CategoryID, CategoryName in pairs( DATABASECategory ) do
self:T( "Kill scores exist for player " .. PlayerName )
if PlayerData.Kill[CategoryID] then
local Score = 0
local ScoreKill = 0
local Penalty = 0
local PenaltyKill = 0
for UnitName, UnitData in pairs( PlayerData.Kill[CategoryID] ) do
Score = Score + UnitData.Score
ScoreKill = ScoreKill + UnitData.ScoreKill
Penalty = Penalty + UnitData.Penalty
PenaltyKill = PenaltyKill + UnitData.PenaltyKill
end
local ScoreMessageKill = string.format( " %s:%d ", CategoryName, Score - Penalty )
self:T( ScoreMessageKill )
ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill
PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty
else
--ScoreMessageKills = ScoreMessageKills .. string.format( "%s:%d ", string.format(CategoryName, 1, 1), 0 )
end
end
if ScoreMessageKills ~= "" then
ScoreMessage = ScoreMessage .. " Kills: " .. ScoreMessageKills .. "\n"
end
local ScoreMessageCoalitionChangePenalties = ""
if PlayerData.PenaltyCoalition ~= 0 then
ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition )
PlayerPenalty = PlayerPenalty + PlayerData.Penalty
end
if ScoreMessageCoalitionChangePenalties ~= "" then
ScoreMessage = ScoreMessage .. " Coalition Penalties: " .. ScoreMessageCoalitionChangePenalties .. "\n"
end
local ScoreMessageMission = ""
local ScoreMission = 0
local ScoreTask = 0
for MissionName, MissionData in pairs( PlayerData.Mission ) do
ScoreMission = ScoreMission + MissionData.ScoreMission
ScoreTask = ScoreTask + MissionData.ScoreTask
ScoreMessageMission = ScoreMessageMission .. "'" .. MissionName .. "'; "
end
PlayerScore = PlayerScore + ScoreMission + ScoreTask
if ScoreMessageMission ~= "" then
ScoreMessage = ScoreMessage .. " Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ")\n"
end
PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score:%d (%d Score -%d Penalties)%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage )
end
end
MESSAGE:New( PlayerMessage, "Player Scores", 30, "AllPlayerScores"):ToAll()
end
function DATABASE:ReportScorePlayer()
env.info( "Hello World " )
local ScoreMessage = ""
local PlayerMessage = ""
self:T( "Score Report" )
for PlayerName, PlayerData in pairs( self.Players ) do
if PlayerData then -- This should normally not happen, but i'll test it anyway.
self:T( "Score Player: " .. PlayerName )
-- Some variables
local InitUnitCoalition = DATABASECoalition[PlayerData.UnitCoalition]
@ -521,18 +685,22 @@ function DATABASE:ReportScoreAll()
local ScoreMessageHits = ""
for CategoryID, CategoryName in pairs( DATABASECategory ) do
self:T( CategoryName )
if PlayerData.Hit[CategoryID] then
local Score = 0
local ScoreHit = 0
local Penalty = 0
local PenaltyHit = 0
self:T( "Hit scores exist for player " .. PlayerName )
for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do
Score = Score + UnitData.Score
ScoreHit = ScoreHit + UnitData.ScoreHit
Penalty = Penalty + UnitData.Penalty
PenaltyHit = UnitData.PenaltyHit
end
ScoreMessageHits = ScoreMessageHits .. string.format( " %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreHit, PenaltyHit )
local ScoreMessageHit = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreHit, PenaltyHit )
self:T( ScoreMessageHit )
ScoreMessageHits = ScoreMessageHits .. ScoreMessageHit
PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty
else
@ -540,11 +708,12 @@ function DATABASE:ReportScoreAll()
end
end
if ScoreMessageHits ~= "" then
ScoreMessage = ScoreMessage .. " Hits: " .. ScoreMessageHits .. " "
ScoreMessage = ScoreMessage .. "\n Hits: " .. ScoreMessageHits .. " "
end
local ScoreMessageKills = ""
for CategoryID, CategoryName in pairs( DATABASECategory ) do
self:T( "Kill scores exist for player " .. PlayerName )
if PlayerData.Kill[CategoryID] then
local Score = 0
local ScoreKill = 0
@ -557,8 +726,10 @@ function DATABASE:ReportScoreAll()
Penalty = Penalty + UnitData.Penalty
PenaltyKill = PenaltyKill + UnitData.PenaltyKill
end
ScoreMessageKills = ScoreMessageKills .. string.format( " %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreKill, PenaltyKill )
local ScoreMessageKill = string.format( "\n %s = %d score(%d;-%d) hits(#%d;#-%d)", CategoryName, Score - Penalty, Score, Penalty, ScoreKill, PenaltyKill )
self:T( ScoreMessageKill )
ScoreMessageKills = ScoreMessageKills .. ScoreMessageKill
PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty
@ -567,16 +738,16 @@ function DATABASE:ReportScoreAll()
end
end
if ScoreMessageKills ~= "" then
ScoreMessage = ScoreMessage .. " Kills: " .. ScoreMessageKills .. " "
ScoreMessage = ScoreMessage .. "\n Kills: " .. ScoreMessageKills .. " "
end
local ScoreMessageCoalitionChangePenalties = ""
if PlayerData.PenaltyCoalition ~= 0 then
ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( "-%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition )
ScoreMessageCoalitionChangePenalties = ScoreMessageCoalitionChangePenalties .. string.format( " -%d (%d changed)", PlayerData.Penalty, PlayerData.PenaltyCoalition )
PlayerPenalty = PlayerPenalty + PlayerData.Penalty
end
if ScoreMessageCoalitionChangePenalties ~= "" then
ScoreMessage = ScoreMessage .. " Coalition: " .. ScoreMessageCoalitionChangePenalties .. " "
ScoreMessage = ScoreMessage .. "\n Coalition: " .. ScoreMessageCoalitionChangePenalties .. " "
end
local ScoreMessageMission = ""
@ -590,26 +761,26 @@ function DATABASE:ReportScoreAll()
PlayerScore = PlayerScore + ScoreMission + ScoreTask
if ScoreMessageMission ~= "" then
ScoreMessage = ScoreMessage .. " Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ") "
ScoreMessage = ScoreMessage .. "\n Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ") "
end
PlayerMessage = string.format( " Player '%s' Score = %d ( %d Score, -%d Penalties ):", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty )
MESSAGE:New( PlayerMessage .. ScoreMessage, "Player Scores", 30, "/SCORE/" .. PlayerName ):ToAll()
PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties ):%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage )
end
end
end
function DATABASE:ReportScorePlayer()
MESSAGE:New( PlayerMessage, "Player Scores", 30, "AllPlayerScores"):ToAll()
end
function DATABASE:ScoreMenu()
local ReportScore = SUBMENU:New( 'Scoring' )
local ReportAllScores = COMMANDMENU:New( 'Score All Active Players', ReportScore, DATABASE.ReportScoreAll, self )
local ReportPlayerScores = COMMANDMENU:New('Your Current Score', ReportScore, DATABASE.ReportScorePlayer, self )
end
-- File Logic for tracking the scores
function DATABASE:SecondsToClock(sSeconds)
@ -625,6 +796,7 @@ local nSeconds = sSeconds
end
end
function DATABASE:ScoreOpen()
if lfs then
local fdir = lfs.writedir() .. [[Logs\]] .. "Player_Scores_" .. os.date( "%Y-%m-%d_%H-%M-%S" ) .. ".csv"
@ -632,12 +804,13 @@ function DATABASE:ScoreOpen()
if not self.StatFile then
error( "Error: Cannot open 'Player Scores.csv' file in " .. lfs.writedir() )
end
self.StatFile:write( '"Run-ID";Time;"PlayerName";"ScoreType";"PlayerUnitCoaltion";"PlayerUnitCategory";"PlayerUnitType"; "PlayerUnitName";"TargetUnitCoalition";"TargetUnitCategory";"TargetUnitType";"TargetUnitName";Times;Score\n' )
self.StatFile:write( '"RunID";"Time";"PlayerName";"ScoreType";"PlayerUnitCoaltion";"PlayerUnitCategory";"PlayerUnitType";"PlayerUnitName";"TargetUnitCoalition";"TargetUnitCategory";"TargetUnitType";"TargetUnitName";"Times";"Score"\n' )
self.RunID = os.date("%y-%m-%d_%H-%M-%S")
end
end
function DATABASE:ScoreAdd( PlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
--write statistic information to file
local ScoreTime = self:SecondsToClock(timer.getTime())
@ -648,11 +821,12 @@ function DATABASE:ScoreAdd( PlayerName, ScoreType, ScoreTimes, ScoreAmount, Play
if PlayerUnit then
if not PlayerUnitCategory then
PlayerUnitCategory = DATABASECategory[Unit.getGroup(PlayerUnit):getCategory()]
--PlayerUnitCategory = DATABASECategory[PlayerUnit:getCategory()]
PlayerUnitCategory = DATABASECategory[PlayerUnit:getDesc().category]
end
if not PlayerUnitCoalition then
PlayerUnitCoalition = DATABASECoalition[Unit.getGroup(PlayerUnit):getCoalition()]
PlayerUnitCoalition = DATABASECoalition[PlayerUnit:getCoalition()]
end
if not PlayerUnitType then
@ -695,6 +869,7 @@ function DATABASE:ScoreAdd( PlayerName, ScoreType, ScoreTimes, ScoreAmount, Play
self.StatFile:write( "\n" )
end
end
function LogClose()
if lfs then

View File

@ -13,39 +13,64 @@ DEPLOYTASK = {
--- Creates a new DEPLOYTASK object, which models the sequence of STAGEs to unload a cargo.
-- @tparam table{string,...}|string LandingZones Table or name of the zone(s) where Cargo is to be unloaded.
-- @tparam CARGO_TYPE CargoType Type of the Cargo.
function DEPLOYTASK:New( LandingZones, CargoType )
trace.f(self.ClassName)
function DEPLOYTASK:New( CargoType )
local self = BASE:Inherit( self, TASK:New() )
self:T()
-- Child holds the inherited instance of the DEPLOYTASK Class to the BASE class.
local Child = BASE:Inherit( self, TASK:New() )
local Valid = true
Valid = routines.ValidateZone( LandingZones, "LandingZones", Valid )
Valid = routines.ValidateEnumeration( CargoType, "CargoType", CARGO_TYPE, Valid )
if Valid then
Child.Name = 'Deploy Cargo'
Child.TaskBriefing = "Fly to one of the indicated landing zones and deploy " .. CargoType.TEXT .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the deployment zone."
if type( LandingZones ) == "table" then
Child.LandingZones = LandingZones
else
Child.LandingZones = { LandingZones }
end
Child.CargoType = CargoType
Child.GoalVerb = CargoType.TEXT .. " " .. self.GoalVerb
Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGEUNLOAD:New(), STAGEDONE:New() }
Child.SetStage( Child, 1 )
self.Name = 'Deploy Cargo'
self.TaskBriefing = "Fly to one of the indicated landing zones and deploy " .. CargoType .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the deployment zone."
self.CargoType = CargoType
self.GoalVerb = CargoType .. " " .. self.GoalVerb
self.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGEUNLOAD:New(), STAGEDONE:New() }
self.SetStage( self, 1 )
end
return Child
return self
end
function DEPLOYTASK:ToZone( LandingZone )
self:T()
self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName
self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone
return self
end
function DEPLOYTASK:InitCargo( InitCargos )
self:T( { InitCargos } )
if type( InitCargos ) == "table" then
self.Cargos.InitCargos = InitCargos
else
self.Cargos.InitCargos = { InitCargos }
end
return self
end
function DEPLOYTASK:LoadCargo( LoadCargos )
self:T( { LoadCargos } )
if type( LoadCargos ) == "table" then
self.Cargos.LoadCargos = LoadCargos
else
self.Cargos.LoadCargos = { LoadCargos }
end
return self
end
--- When the cargo is unloaded, it will move to the target zone name.
-- @tparam string TargetZoneName Name of the Zone to where the Cargo should move after unloading.
function DEPLOYTASK:SetCargoTargetZoneName( TargetZoneName )
trace.f(self.ClassName)
self:T()
local Valid = true
@ -60,57 +85,68 @@ trace.f(self.ClassName)
end
function DEPLOYTASK:AddCargoMenus( Client, Cargos, TransportRadius )
trace.f(self.ClassName, {Client, Cargos, TransportRadius})
self:T()
for CargoID, CargoData in pairs( Client._Cargos ) do
local ClientGroupID = Client:GetClientGroupID()
trace.i( self.ClassName, ClientGroupID )
for CargoID, Cargo in pairs( Cargos ) do
trace.i( self.ClassName, { CargoData.CargoName } )
if Client._Menus[CargoData.CargoType] == nil then
Client._Menus[CargoData.CargoType] = {}
end
trace.i( self.ClassName, { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo.CargoWeight } )
if not Client._Menus[CargoData.CargoType].DeployMenu then
Client._Menus[CargoData.CargoType].DeployMenu = missionCommands.addSubMenuForGroup(
Client:ClientGroup():getID(),
self.TEXT[1],
nil
if Cargo:IsStatusLoaded() and Client == Cargo:IsLoadedInClient() then
if Client._Menus[Cargo.CargoType] == nil then
Client._Menus[Cargo.CargoType] = {}
end
if not Client._Menus[Cargo.CargoType].DeployMenu then
Client._Menus[Cargo.CargoType].DeployMenu = missionCommands.addSubMenuForGroup(
ClientGroupID,
self.TEXT[1] .. " " .. Cargo.CargoType,
nil
)
trace.i( self.ClassName, 'Added DeployMenu ' .. self.TEXT[1] )
end
if Client._Menus[Cargo.CargoType].DeploySubMenus == nil then
Client._Menus[Cargo.CargoType].DeploySubMenus = {}
end
if Client._Menus[Cargo.CargoType].DeployMenu == nil then
trace.i( self.ClassName, 'deploymenu is nil' )
end
Client._Menus[Cargo.CargoType].DeploySubMenus[ #Client._Menus[Cargo.CargoType].DeploySubMenus + 1 ] = missionCommands.addCommandForGroup(
ClientGroupID,
Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )",
Client._Menus[Cargo.CargoType].DeployMenu,
self.MenuAction,
{ ReferenceTask = self, CargoTask = Cargo }
)
trace.i( self.ClassName, 'Added DeployMenu ' .. self.TEXT[1] )
trace.i( self.ClassName, 'Added DeploySubMenu ' .. Cargo.CargoType .. ":" .. Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )" )
end
if Client._Menus[CargoData.CargoType].DeploySubMenus == nil then
Client._Menus[CargoData.CargoType].DeploySubMenus = {}
end
if Client._Menus[CargoData.CargoType].DeployMenu == nil then
trace.i( self.ClassName, 'deploymenu is nil' )
end
Client._Menus[CargoData.CargoType].DeploySubMenus[ #Client._Menus[CargoData.CargoType].DeploySubMenus + 1 ].MenuPath = missionCommands.addCommandForGroup(
Client:ClientGroup():getID(),
CargoData.CargoName .. " ( " .. CargoData.CargoWeight .. "kg )",
Client._Menus[CargoData.CargoType].DeployMenu,
self.MenuAction,
{ ReferenceTask = self, CargoName = CargoData.CargoName }
)
trace.i( self.ClassName, 'Added DeploySubMenu ' .. CargoData.CargoType.TEXT .. ":" .. CargoData.CargoName .. " ( " .. CargoData.CargoWeight .. "kg )" )
end
end
function DEPLOYTASK:RemoveCargoMenus( Client )
trace.f(self.ClassName, { Client } )
self:T()
local ClientGroupID = Client:GetClientGroupID()
trace.i( self.ClassName, ClientGroupID )
for MenuID, MenuData in pairs( Client._Menus ) do
if MenuData.DeploySubMenus ~= nil then
for SubMenuID, SubMenuData in pairs( MenuData.DeploySubMenus ) do
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), SubMenuData )
missionCommands.removeItemForGroup( ClientGroupID, SubMenuData )
trace.i( self.ClassName, "Removed DeploySubMenu " )
SubMenuData = nil
end
end
if MenuData.DeployMenu then
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), MenuData.DeployMenu )
missionCommands.removeItemForGroup( ClientGroupID, MenuData.DeployMenu )
trace.i( self.ClassName, "Removed DeployMenu " )
MenuData.DeployMenu = nil
end

View File

@ -20,51 +20,52 @@ DESTROYBASETASK = {
-- @tparam ?number DestroyPercentage defines the %-tage that needs to be destroyed to achieve mission success. eg. If in the Group there are 10 units, then a value of 75 would require 8 units to be destroyed from the Group to complete the @{TASK}.
-- @treturn DESTROYBASETASK
function DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupPrefixes, DestroyPercentage )
trace.f(self.ClassName)
-- Inheritance
local Child = BASE:Inherit( self, TASK:New() )
local self = BASE:Inherit( self, TASK:New() )
self:T()
Child.Name = 'Destroy'
Child.Destroyed = 0
Child.DestroyGroupPrefixes = DestroyGroupPrefixes
Child.DestroyGroupType = DestroyGroupType
Child.DestroyUnitType = DestroyUnitType
Child.TaskBriefing = "Task: Destroy " .. DestroyGroupType .. "."
Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEGROUPSDESTROYED:New(), STAGEDONE:New() }
Child.SetStage( Child, 1 )
self.Name = 'Destroy'
self.Destroyed = 0
self.DestroyGroupPrefixes = DestroyGroupPrefixes
self.DestroyGroupType = DestroyGroupType
self.DestroyUnitType = DestroyUnitType
self.TaskBriefing = "Task: Destroy " .. DestroyGroupType .. "."
self.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEGROUPSDESTROYED:New(), STAGEDONE:New() }
self.SetStage( self, 1 )
--Child.AddEvent( Child, world.event.S_EVENT_DEAD, Child.EventDead )
--self.AddEvent( self, world.event.S_EVENT_DEAD, self.EventDead )
--env.info( 'New Table Child = ' .. tostring(Child) )
--env.info( 'New Table self = ' .. tostring(self) )
--env.info( 'New Table self = ' .. tostring(self) )
return Child
return self
end
--- Handle the S_EVENT_DEAD events to validate the destruction of units for the task monitoring.
-- @param event Event structure of DCS world.
function DESTROYBASETASK:EventDead( event )
trace.f( self.ClassName, { 'EventDead', event } )
self:T( { 'EventDead', event } )
if event.initiator then
local DestroyGroup = Unit.getGroup( event.initiator )
local DestroyGroupName = DestroyGroup:getName()
if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
local DestroyUnit = event.initiator
local DestroyUnitName = DestroyUnit:getName()
local DestroyGroup = Unit.getGroup( DestroyUnit )
local DestroyGroupName = ""
if DestroyGroup and DestroyGroup:isExist() then
local DestroyGroupName = DestroyGroup:getName()
end
local UnitsDestroyed = 0
trace.i( self.ClassName, DestroyGroupName )
trace.i( self.ClassName, DestroyUnitName )
self:T( DestroyGroupName )
self:T( DestroyUnitName )
for DestroyGroupPrefixID, DestroyGroupPrefix in pairs( self.DestroyGroupPrefixes ) do
trace.i( self.ClassName, DestroyGroupPrefix )
self:T( DestroyGroupPrefix )
if string.find( DestroyGroupName, DestroyGroupPrefix, 1, true ) then
trace.i( self.ClassName, BASE:Inherited(self).ClassName )
self:T( BASE:Inherited(self).ClassName )
UnitsDestroyed = self:ReportGoalProgress( DestroyGroup, DestroyUnit )
trace.i( self.ClassName, UnitsDestroyed )
self:T( UnitsDestroyed )
end
end
trace.i( self.ClassName, { UnitsDestroyed } )
self:T( { UnitsDestroyed } )
self:IncreaseGoalCount( UnitsDestroyed, self.GoalVerb )
end
end
@ -73,7 +74,7 @@ end
-- @param DestroyGroup Group structure describing the group to be evaluated.
-- @param DestroyUnit Unit structure describing the Unit to be evaluated.
function DESTROYBASETASK:ReportGoalProgress( DestroyGroup, DestroyUnit )
trace.f(self.ClassName)
self:T()
return 0
end

177
Moose/Group.lua Normal file
View File

@ -0,0 +1,177 @@
--- GROUP Classes
-- @classmod GROUP
Include.File( "Routines" )
Include.File( "Base" )
Include.File( "Message" )
Include.File( "Unit" )
GROUPS = {}
GROUP = {
ClassName="GROUP",
}
function GROUP:New( _Group )
local self = BASE:Inherit( self, BASE:New() )
self:T( _Group:getName() )
self._Group = _Group
self.GroupName = _Group:getName()
self.GroupID = _Group:getID()
return self
end
function GROUP:NewFromName( GroupName )
local self = BASE:Inherit( self, BASE:New() )
self:T( GroupName )
self._Group = Group.getByName( GroupName )
self.GroupName = self._Group:getName()
self.GroupID = self._Group:getID()
return self
end
function GROUP:GetName()
self:T( self.GroupName )
return self.GroupName
end
function GROUP:Destroy()
self:T( self.GroupName )
for Index, UnitData in pairs( self._Group:getUnits() ) do
self:CreateEventCrash( timer.getTime(), UnitData )
end
self._Group:destroy()
end
function GROUP:GetUnit( UnitNumber )
self:T( self.GroupName )
return UNIT:New( self._Group:getUnit( UnitNumber ) )
end
function GROUP:IsAir()
self:T()
local IsAirResult = self._Group:getCategory() == Group.Category.AIRPLANE or self._Group:getCategory() == Group.Category.HELICOPTER
self:T( IsAirResult )
return IsAirResult
end
function GROUP:AllOnGround()
self:T()
local AllOnGroundResult = true
for Index, UnitData in pairs( self._Group:getUnits() ) do
if UnitData:inAir() then
AllOnGroundResult = false
end
end
self:T( AllOnGroundResult )
return AllOnGroundResult
end
function GROUP:GetMaxVelocity()
self:T()
local MaxVelocity = 0
for Index, UnitData in pairs( self._Group:getUnits() ) do
local Velocity = UnitData:getVelocity()
local VelocityTotal = math.abs( Velocity.x ) + math.abs( Velocity.y ) + math.abs( Velocity.z )
if VelocityTotal < MaxVelocity then
MaxVelocity = VelocityTotal
end
end
return MaxVelocity
end
function GROUP:GetHeight()
self:T()
end
function GROUP:Land( Point, Duration )
trace.f( self.ClassName, { self.GroupName, Point, Duration } )
local Controller = self:_GetController()
if Duration and Duration > 0 then
Controller:pushTask( { id = 'Land', params = { point = Point, durationFlag = true, duration = Duration } } )
else
Controller:pushTask( { id = 'Land', params = { point = Point, durationFlag = false } } )
end
return self
end
function GROUP:Embarking( Point, Duration, EmbarkingGroup )
trace.f( self.ClassName, { self.GroupName, Point, Duration, EmbarkingGroup._Group } )
local Controller = self:_GetController()
trace.i( self.ClassName, EmbarkingGroup.GroupID )
trace.i( self.ClassName, EmbarkingGroup._Group:getID() )
trace.i( self.ClassName, EmbarkingGroup._Group.id )
Controller:pushTask( { id = 'Embarking',
params = { x = Point.x,
y = Point.y,
duration = Duration,
groupsForEmbarking = { EmbarkingGroup.GroupID },
durationFlag = true,
distributionFlag = false,
distribution = {},
}
}
)
return self
end
function GROUP:EmbarkToTransport( Point, Radius )
trace.f( self.ClassName, { self.GroupName, Point, Radius } )
local Controller = self:_GetController()
Controller:pushTask( { id = 'EmbarkToTransport',
params = { x = Point.x,
y = Point.y,
zoneRadius = Radius,
}
}
)
return self
end
function GROUP:_GetController()
return self._Group:getController()
end

View File

@ -74,16 +74,52 @@ end
function MESSAGE:ToClient( Client )
trace.f(self.ClassName )
if Client and Client:ClientGroup() then
if Client and Client:GetClientGroupID() then
local ClientGroup = Client:ClientGroup()
local ClientGroupID = Client:GetClientGroupID()
trace.i( self.ClassName, self.MessageCategory .. '\n' .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
trigger.action.outTextForGroup( ClientGroup:getID(), self.MessageCategory .. '\n' .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. '\n' .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
end
return self
end
--- Sends a MESSAGE to the Blue coalition.
-- @treturn MESSAGE
-- @usage
-- -- Send a message created with the @{New} method to the BLUE coalition.
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- or
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
-- or
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageBLUE:ToBlue()
function MESSAGE:ToBlue()
trace.f(self.ClassName )
self:ToCoalition( coalition.side.BLUE )
return self
end
--- Sends a MESSAGE to the Red Coalition.
-- @treturn MESSAGE
-- @usage
-- -- Send a message created with the @{New} method to the RED coalition.
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- or
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
-- or
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
-- MessageRED:ToRed()
function MESSAGE:ToRed( )
trace.f(self.ClassName )
self:ToCoalition( coalition.side.RED )
return self
end
--- Sends a MESSAGE to a Coalition.
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
-- @treturn MESSAGE

View File

@ -4,7 +4,6 @@
Include.File( "Routines" )
Include.File( "Base" )
Include.File( "Mission" )
Include.File( "Client" )
Include.File( "Task" )
@ -16,7 +15,6 @@ MISSION = {
_Clients = {},
_Tasks = {},
_ActiveTasks = {},
_Cargos = {},
GoalFunction = nil,
MissionReportTrigger = 0,
MissionProgressTrigger = 0,
@ -30,23 +28,13 @@ MISSION = {
_GoalTasks = {}
}
CARGOSTATUS = {
NONE = 0,
LOADED = 1,
UNLOADED = 2,
LOADING = 3,
LoadCount= 0,
UnloadCount = 0
}
function MISSION:Meta()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, BASE:New() )
trace.r( self.ClassName, "", { Child } )
return Child
local self = BASE:Inherit( self, BASE:New() )
self:T()
return self
end
--- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc.
@ -66,8 +54,9 @@ end
-- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Sling Load', 'Operational', 'Fly to the cargo pickup zone at Dzegvi or Kaspi, and sling the cargo to Soganlug airbase.', 'NATO' )
-- local Mission = MISSIONSCHEDULER.AddMission( 'Rescue secret agent', 'Tactical', 'In order to be in full control of the situation, we need you to rescue a secret agent from the woods behind enemy lines. Avoid the Russian defenses and rescue the agent. Keep south until Khasuri, and keep your eyes open for any SAM presence. The agent is located at waypoint 4 on your kneeboard.', 'NATO' )
function MISSION:New( MissionName, MissionPriority, MissionBriefing, MissionCoalition )
trace.f(self.ClassName, { MissionName, MissionPriority, MissionBriefing, MissionCoalition } )
self = MISSION:Meta()
self:T({ MissionName, MissionPriority, MissionBriefing, MissionCoalition })
local Valid = true
@ -83,20 +72,19 @@ trace.f(self.ClassName, { MissionName, MissionPriority, MissionBriefing, Mission
self.MissionCoalition = MissionCoalition
end
trace.r( self.ClassName, "" )
return self
end
--- Returns if a Mission has completed.
-- @treturn bool
function MISSION:IsCompleted()
trace.f(self.ClassName)
self:T()
return self.MissionStatus == "ACCOMPLISHED"
end
--- Set a Mission to completed.
function MISSION:Completed()
trace.f(self.ClassName)
self:T()
self.MissionStatus = "ACCOMPLISHED"
self:StatusToClients()
end
@ -104,27 +92,27 @@ end
--- Returns if a Mission is ongoing.
-- treturn bool
function MISSION:IsOngoing()
trace.f(self.ClassName)
self:T()
return self.MissionStatus == "ONGOING"
end
--- Set a Mission to ongoing.
function MISSION:Ongoing()
trace.f(self.ClassName)
self:T()
self.MissionStatus = "ONGOING"
self:StatusToClients()
--self:StatusToClients()
end
--- Returns if a Mission is pending.
-- treturn bool
function MISSION:IsPending()
trace.f(self.ClassName)
self:T()
return self.MissionStatus == "PENDING"
end
--- Set a Mission to pending.
function MISSION:Pending()
trace.f(self.ClassName)
self:T()
self.MissionStatus = "PENDING"
self:StatusToClients()
end
@ -132,31 +120,31 @@ end
--- Returns if a Mission has failed.
-- treturn bool
function MISSION:IsFailed()
trace.f(self.ClassName)
self:T()
return self.MissionStatus == "FAILED"
end
--- Set a Mission to failed.
function MISSION:Failed()
trace.f(self.ClassName)
self:T()
self.MissionStatus = "FAILED"
self:StatusToClients()
end
--- Send the status of the MISSION to all Clients.
function MISSION:StatusToClients()
trace.f(self.ClassName)
if timer.getTime() >= self.MissionReportTrigger then
self:T()
if self.MissionReportFlash then
for ClientID, Client in pairs( self._Clients ) do
Client:Message( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. '! ( ' .. self.MissionPriority .. ' mission ) ', 10, self.Name .. '/Status', "Mission Command: Mission Status")
end
end
trace.e()
end
--- Handles the reporting. After certain time intervals, a MISSION report MESSAGE will be shown to All Players.
function MISSION:ReportTrigger()
trace.f(self.ClassName)
self:T()
if self.MissionReportShow == true then
self.MissionReportShow = false
trace.r( "MISSION", "1", { true } )
@ -181,16 +169,17 @@ end
--- Report the status of all MISSIONs to all active Clients.
function MISSION:ReportToAll()
trace.f(self.ClassName)
self:T()
local AlivePlayers = ''
for ClientID, Client in pairs( self._Clients ) do
if Client:ClientGroup() then
if Client:ClientGroup():getUnit(1) then
if Client:ClientGroup():getUnit(1):getLife() > 0.0 then
if Client:GetClientGroupUnit() then
if Client:GetClientGroupUnit():getLife() > 0.0 then
if AlivePlayers == '' then
AlivePlayers = ' Players: ' .. Client:ClientGroup():getUnit(1):getPlayerName()
AlivePlayers = ' Players: ' .. Client:GetClientGroupUnit():getPlayerName()
else
AlivePlayers = AlivePlayers .. ' / ' .. Client:ClientGroup():getUnit(1):getPlayerName()
AlivePlayers = AlivePlayers .. ' / ' .. Client:GetClientGroupUnit():getPlayerName()
end
end
end
@ -202,7 +191,6 @@ trace.f(self.ClassName)
TaskText = TaskText .. " - Task " .. TaskID .. ": " .. TaskData.Name .. ": " .. TaskData:GetGoalProgress() .. "\n"
end
MESSAGE:New( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. ' ( ' .. self.MissionPriority .. ' mission )' .. AlivePlayers .. "\n" .. TaskText:gsub("\n$",""), "Mission Command: Mission Report", 10, self.Name .. '/Status'):ToAll()
trace.e()
end
@ -243,27 +231,26 @@ end
-- local Mission = MISSIONSCHEDULER.AddMission( 'NATO Transport Troops', 'Operational', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.', 'NATO' )
-- Mission:AddGoalFunction( DeployPatriotTroopsGoal )
function MISSION:AddGoalFunction( GoalFunction )
trace.f(self.ClassName)
self:T()
self.GoalFunction = GoalFunction
trace.e()
end
--- Show the briefing of the MISSION to the CLIENT.
-- @tparam CLIENT Client to show briefing to.
-- @treturn CLIENT
function MISSION:ShowBriefing( Client )
trace.f(self.ClassName, { Client } )
self:T( { Client.ClientName } )
if not Client.ClientBriefingShown then
Client.ClientBriefingShown = true
Client:Message( '(Press the keys [LEFT ALT]+[B] to view the briefing pages. Browse through the graphical briefing.)\n' ..
self.MissionBriefing, 40, self.Name .. '/MissionBriefing', "Mission Command: Mission Briefing" )
local Briefing = self.MissionBriefing
if Client.ClientBriefing then
Client:Message( Client.ClientBriefing, 40, self.Name .. '/ClientBriefing', "Mission Command: Mission Briefing" )
Briefing = Briefing .. "\n" .. Client.ClientBriefing
end
Briefing = Briefing .. "\n (Press [LEFT ALT]+[B] to view the graphical documentation.)"
Client:Message( Briefing, 30, self.Name .. '/MissionBriefing', "Command: Mission Briefing" )
end
trace.r( "", "", { Client } )
return Client
end
@ -277,7 +264,7 @@ end
-- Mission:AddClient( CLIENT:New( 'US UH-1H*HOT-Deploy Troops 2', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() )
-- Mission:AddClient( CLIENT:New( 'US UH-1H*RAMP-Deploy Troops 4', 'Transport 3 groups of air defense engineers from our barracks "Gold" and "Titan" to each patriot battery control center to activate our air defenses.' ):Transport() )
function MISSION:AddClient( Client )
trace.f(self.ClassName, { Client } )
self:T( { Client } )
local Valid = true
@ -296,8 +283,7 @@ end
-- -- Seach for Client "Bomber" within the Mission.
-- local BomberClient = Mission:FindClient( "Bomber" )
function MISSION:FindClient( ClientName )
trace.f(self.ClassName)
trace.r( "", "", { self._Clients[ClientName] } )
self:T( { self._Clients[ClientName] } )
return self._Clients[ClientName]
end
@ -328,13 +314,12 @@ end
-- Mission:AddTask( DeployTask, 2 )
function MISSION:AddTask( Task, TaskNumber )
trace.f(self.ClassName)
self:T()
self._Tasks[TaskNumber] = Task
self._Tasks[TaskNumber]:EnableEvents()
self._Tasks[TaskNumber].ID = TaskNumber
trace.r( self.ClassName, "" )
return Task
end
@ -346,7 +331,7 @@ trace.r( self.ClassName, "" )
-- Task2 = Mission:GetTask( 2 )
function MISSION:GetTask( TaskNumber )
trace.f(self.ClassName)
self:T()
local Valid = true
@ -370,51 +355,11 @@ end
-- Tasks = Mission:GetTasks()
-- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" )
function MISSION:GetTasks()
trace.f(self.ClassName)
self:T()
return self._Tasks
end
--- 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...
SpawnCargo = {}
function MISSION:AddCargo( CargoName, CargoType, CargoWeight, CargoGroupControlCenter, CargoGroupTemplate, CargoZone )
trace.f(self.ClassName, { CargoName, CargoType, CargoWeight, CargoGroupControlCenter, CargoGroupTemplate, CargoZone } )
local Cargo = {}
Cargo.CargoName = CargoName
if CargoType.TRANSPORT == CARGO_TRANSPORT.UNIT then
if not SpawnCargo[CargoGroupTemplate] then
SpawnCargo[CargoGroupTemplate] = SPAWN:New( CargoGroupTemplate )
end
if CargoGroupControlCenter == nil then
--- @todo check this
Cargo.CargoGroupName = SpawnCargo[CargoGroupTemplate]:InZone( CargoZone ).name
else
--- @todo check this
env.info( "SpawnFromCarrier")
Cargo.CargoGroupName = SpawnCargo[CargoGroupTemplate]:FromCarrier( Group.getByName( CargoGroupControlCenter ), CargoZone, nil, true ).name
--trigger.action.activateGroup( Group.getByName( Cargo.CargoGroupName ) )
--trigger.action.setGroupAIOff( Cargo.CargoGroupName )
trace.i( self.ClassName, Cargo.CargoGroupName )
end
else
Cargo.CargoGroupName = CargoGroupControlCenter
end
Cargo.CargoType = CargoType
Cargo.CargoWeight = CargoWeight
Cargo.CargoGroupControlCenter = CargoGroupControlCenter
Cargo.CargoGroupTemplate = CargoGroupTemplate
Cargo.CargoZone = CargoZone
Cargo.Status = CARGOSTATUS.NONE
self._Cargos[CargoName] = Cargo
trace.r( self.ClassName, "AddCargo", { Cargo.CargoGroupName } )
return Cargo.CargoGroupName
end
--[[
_TransportExecuteStage: Defines the different stages of Transport unload/load execution. This table is internal and is used to control the validity of Transport load/unload timing.
@ -450,6 +395,8 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
-- loop through the missions in the TransportTasks
for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do
trace.i( "MISSIONSCHEDULER", MissionName )
if not Mission:IsCompleted() then
@ -457,8 +404,10 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
local ClientsAlive = false
for ClientID, Client in pairs( Mission._Clients ) do
trace.i( "MISSIONSCHEDULER", "Client: " .. Client.ClientName )
if Client:ClientGroup() and Client:ClientGroup():getUnits() and Client:ClientGroup():getUnits()[1] and Client:ClientGroup():getUnits()[1]:getLife() > 0.0 then
if Client:ClientGroup() then
-- There is at least one Client that is alive... So the Mission status is set to Ongoing.
ClientsAlive = true
@ -476,13 +425,10 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
Client._Tasks[TaskNumber] = routines.utils.deepCopy( Mission._Tasks[TaskNumber] )
-- Each MissionTask must point to the original Mission.
Client._Tasks[TaskNumber].MissionTask = Mission._Tasks[TaskNumber]
Client._Tasks[TaskNumber].Cargos = Mission._Tasks[TaskNumber].Cargos
Client._Tasks[TaskNumber].LandingZones = Mission._Tasks[TaskNumber].LandingZones
end
Client._Cargos = {}
if Client.InitCargoNames then
for InitCargoID, InitCargoName in pairs( Client.InitCargoNames ) do
Client._Cargos[InitCargoName] = Mission._Cargos[InitCargoName]
end
end
Mission:Ongoing()
end
@ -524,6 +470,7 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
end
if Task:IsDone() then
trace.i( "MISSIONSCHEDULER", "Task " .. Task.Name .. " is Done." )
--env.info( 'Scheduler: Mission '.. Mission.Name .. ' Task ' .. Task.Name .. ' Stage ' .. Task.Stage.Name .. ' done. TaskComplete = ' .. string.format ( "%s", TaskComplete and "true" or "false" ) )
TaskComplete = true -- when a task is not yet completed, a mission cannot be completed
@ -539,7 +486,7 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
if Mission.GoalFunction ~= nil then
Mission.GoalFunction( Mission, Client )
end
_Database:_AddMissionTaskScore( Client:ClientGroup():getUnit(1), Mission.Name, 25 )
_Database:_AddMissionTaskScore( Client:GetClientGroupUnit(), Mission.Name, 25 )
-- if not Mission:IsCompleted() then
-- end
@ -580,9 +527,6 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
-- So first sanitize Client._Tasks[TaskNumber].MissionTask, after that, sanitize only the whole _Tasks structure...
--Client._Tasks[TaskNumber].MissionTask = nil
--Client._Tasks = nil
-- Sanitize the Client._Cargos. Any cargo within the Client will be lost when the client crashes. This is an important statement.
Client._Cargos = nil
end
end
end

View File

@ -20,61 +20,61 @@ MOVEMENT = {
-- Movement_US_Platoons = MOVEMENT:New( { 'US Tank Platoon Left', 'US Tank Platoon Middle', 'US Tank Platoon Right', 'US CH-47D Troops' }, 15 )
function MOVEMENT:New( MovePrefixes, MoveMaximum )
trace.f(self.ClassName, { MovePrefixes, MoveMaximum } )
-- Inherits from BASE
local Child = BASE:Inherit( self, BASE:New() )
local self = BASE:Inherit( self, BASE:New() )
self:T( { MovePrefixes, MoveMaximum } )
if type( MovePrefixes ) == 'table' then
Child.MovePrefixes = MovePrefixes
self.MovePrefixes = MovePrefixes
else
Child.MovePrefixes = { MovePrefixes }
self.MovePrefixes = { MovePrefixes }
end
Child.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart.
Child.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move...
Child.AliveUnits = 0 -- Contains the counter how many units are currently alive
Child.MoveGroups = {} -- Reflects if the Moveing for this MovePrefixes is going to be scheduled or not.
self.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart.
self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move...
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not.
Child.AddEvent( Child, world.event.S_EVENT_BIRTH, Child.OnBirth )
Child.AddEvent( Child, world.event.S_EVENT_DEAD, Child.OnDeadOrCrash )
Child.AddEvent( Child, world.event.S_EVENT_CRASH, Child.OnDeadOrCrash )
self.AddEvent( self, world.event.S_EVENT_BIRTH, self.OnBirth )
self.AddEvent( self, world.event.S_EVENT_DEAD, self.OnDeadOrCrash )
self.AddEvent( self, world.event.S_EVENT_CRASH, self.OnDeadOrCrash )
Child.EnableEvents( Child )
self.EnableEvents( self )
Child.ScheduleStart( Child )
self.ScheduleStart( self )
return Child
return self
end
--- Call this function to start the MOVEMENT scheduling.
function MOVEMENT:ScheduleStart()
trace.f( self.ClassName )
self:T()
self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 )
end
--- Call this function to stop the MOVEMENT scheduling.
-- @todo need to implement it ... Forgot.
function MOVEMENT:ScheduleStop()
trace.f( self.ClassName )
self:T()
end
--- Captures the birth events when new Units were spawned.
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
function MOVEMENT:OnBirth( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line
if event.initiator and event.initiator:getName() then
trace.l(self.ClassName, "OnBirth", "Birth object : " .. event.initiator:getName() )
local GroupData = Unit.getGroup(event.initiator)
if GroupData and GroupData:isExist() then
local EventGroupName = GroupData:getName()
if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
local MovementUnit = event.initiator
local MovementUnitName = MovementUnit:getName()
self:T( "Birth object : " .. MovementUnitName )
local MovementGroup = MovementUnit:getGroup()
if MovementGroup and MovementGroup:isExist() then
local MovementGroupName = MovementGroup:getName()
for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do
if string.find( EventGroupName, MovePrefix, 1, true ) then
if string.find( MovementUnitName, MovePrefix, 1, true ) then
self.AliveUnits = self.AliveUnits + 1
self.MoveGroups[EventGroupName] = EventGroupName
trace.l(self.ClassName, "OnBirth", self.AliveUnits )
self.MoveUnits[MovementUnitName] = MovementGroupName
self:T( self.AliveUnits )
end
end
end
@ -86,16 +86,17 @@ end
--- Captures the Dead or Crash events when Units crash or are destroyed.
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
function MOVEMENT:OnDeadOrCrash( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
if event.initiator and event.initiator:getName() then
trace.l( self.ClassName, "OnDeadOrCrash", "Dead object : " .. event.initiator:getName() )
local EventGroupName = Unit.getGroup(event.initiator):getName()
if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
local MovementUnit = event.initiator
local MovementUnitName = MovementUnit:getName()
self:T( "Dead object : " .. MovementUnitName )
for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do
if string.find( EventGroupName, MovePrefix, 1, true ) then
if string.find( MovementUnitName, MovePrefix, 1, true ) then
self.AliveUnits = self.AliveUnits - 1
self.MoveGroups[EventGroupName] = nil
trace.l( self.ClassName, "OnDeadOrCrash", self.AliveUnits )
self.MoveUnits[MovementUnitName] = nil
self:T( self.AliveUnits )
end
end
end
@ -103,24 +104,26 @@ end
--- This function is called automatically by the MOVEMENT scheduler. A new function is scheduled when MoveScheduled is true.
function MOVEMENT:_Scheduler()
trace.l( self.ClassName, '_Scheduler', { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MoveGroups } )
self:T( { self.MovePrefixes, self.MoveMaximum, self.AliveUnits, self.MovementGroups } )
if self.AliveUnits > 0 then
local MoveProbability = ( self.MoveMaximum * 100 ) / self.AliveUnits
trace.l( self.ClassName, '_Scheduler', 'Move Probability = ' .. MoveProbability )
self:T( 'Move Probability = ' .. MoveProbability )
for MoveGroupID, MoveGroupName in pairs( self.MoveGroups ) do
local MoveGroup = Group.getByName( MoveGroupName )
if MoveGroup then
for MovementUnitName, MovementGroupName in pairs( self.MoveUnits ) do
local MovementGroup = Group.getByName( MovementGroupName )
if MovementGroup and MovementGroup:isExist() then
local MoveOrStop = math.random( 1, 100 )
trace.l( self.ClassName, '_Scheduler', 'MoveOrStop = ' .. MoveOrStop )
self:T( 'MoveOrStop = ' .. MoveOrStop )
if MoveOrStop <= MoveProbability then
trace.l( self.ClassName, '_Scheduler', 'Group continues moving = ' .. MoveGroupName )
trigger.action.groupContinueMoving( MoveGroup )
self:T( 'Group continues moving = ' .. MovementGroupName )
trigger.action.groupContinueMoving( MovementGroup )
else
trace.l( self.ClassName, '_Scheduler', 'Group stops moving = ' .. MoveGroupName )
trigger.action.groupStopMoving( MoveGroup )
self:T( 'Group stops moving = ' .. MovementGroupName )
trigger.action.groupStopMoving( MovementGroup )
end
else
self.MoveUnits[MovementUnitName] = nil
end
end
end

View File

@ -3,6 +3,7 @@
-- @parent TASK
Include.File("Task")
Include.File("Cargo")
PICKUPTASK = {
ClassName = "PICKUPTASK",
@ -14,87 +15,103 @@ PICKUPTASK = {
-- @tparam table{string,...}|string LandingZones Table of Zone names where Cargo is to be loaded.
-- @tparam CARGO_TYPE CargoType Type of the Cargo. The type must be of the following Enumeration:..
-- @tparam number OnBoardSide Reflects from which side the cargo Group will be on-boarded on the Carrier.
function PICKUPTASK:New( LandingZones, CargoType, OnBoardSide )
trace.f(self.ClassName)
function PICKUPTASK:New( CargoType, OnBoardSide )
local self = BASE:Inherit( self, TASK:New() )
self:T()
-- Child holds the inherited instance of the PICKUPTASK Class to the BASE class.
local Child = BASE:Inherit( self, TASK:New() )
-- self holds the inherited instance of the PICKUPTASK Class to the BASE class.
local Valid = true
Valid = routines.ValidateZone( LandingZones, "LandingZones", Valid )
Valid = routines.ValidateEnumeration( CargoType, "CargoType", CARGO_TYPE, Valid )
Valid = routines.ValidateEnumeration( CargoType, "CargoType", CARGO_TYPE, Valid )
--Valid = routines.ValidateEnumeration( OnBoardSide, "OnBoardSide", CLIENT.ONBOARDSIDE, Valid )
if Valid then
Child.Name = 'Pickup Cargo'
Child.TaskBriefing = "Task: Fly to the indicated landing zones and pickup " .. CargoType.TEXT .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the pickup zone."
if type( LandingZones ) == "table" then
Child.LandingZones = LandingZones
else
Child.LandingZones = { LandingZones }
end
Child.CargoType = CargoType
Child.GoalVerb = CargoType.TEXT .. " " .. Child.GoalVerb
Child.OnBoardSide = OnBoardSide
Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGELOAD:New(), STAGEDONE:New() }
Child.SetStage( Child, 1 )
self.Name = 'Pickup Cargo'
self.TaskBriefing = "Task: Fly to the indicated landing zones and pickup " .. CargoType .. ". Your co-pilot will provide you with the directions (required flight angle in degrees) and the distance (in km) to the pickup zone."
self.CargoType = CargoType
self.GoalVerb = CargoType .. " " .. self.GoalVerb
self.OnBoardSide = OnBoardSide
self.IsLandingRequired = false -- required to decide whether the client needs to land or not
self.IsSlingLoad = false -- Indicates whether the cargo is a sling load cargo
self.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGELOAD:New(), STAGEDONE:New() }
self.SetStage( self, 1 )
end
return Child
return self
end
function PICKUPTASK:FromZone( LandingZone )
self:T()
self.LandingZones.LandingZoneNames[LandingZone.CargoZoneName] = LandingZone.CargoZoneName
self.LandingZones.LandingZones[LandingZone.CargoZoneName] = LandingZone
return self
end
function PICKUPTASK:InitCargo( InitCargos )
self:T( { InitCargos } )
if type( InitCargos ) == "table" then
self.Cargos.InitCargos = InitCargos
else
self.Cargos.InitCargos = { InitCargos }
end
return self
end
function PICKUPTASK:LoadCargo( LoadCargos )
self:T( { LoadCargos } )
if type( LoadCargos ) == "table" then
self.Cargos.LoadCargos = LoadCargos
else
self.Cargos.LoadCargos = { LoadCargos }
end
return self
end
function PICKUPTASK:AddCargoMenus( Client, Cargos, TransportRadius )
trace.f(self.ClassName, { Client, Cargos, TransportRadius } )
self:T()
for CargoID, CargoData in pairs( Cargos ) do
for CargoID, Cargo in pairs( Cargos ) do
if CargoData.Status ~= CARGOSTATUS.LOADED and CargoData.Status ~= CARGOSTATUS.LOADING then
self:T( { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo:IsStatusNone(), Cargo:IsStatusLoaded(), Cargo:IsStatusLoading(), Cargo:IsStatusUnLoaded() } )
if Group.getByName( CargoData.CargoGroupName ) then
-- If the Cargo has no status, allow the menu option.
if Cargo:IsStatusNone() or ( Cargo:IsStatusLoading() and Client == Cargo:IsLoadingToClient() ) then
local MenuAdd = false
if Cargo:IsNear( Client, self.CurrentCargoZone ) then
MenuAdd = true
end
if Group.getByName( CargoData.CargoGroupName ):getSize() >= 1 then
if Client._Menus[CargoData.CargoType] == nil then
Client._Menus[CargoData.CargoType] = {}
end
if not Client._Menus[CargoData.CargoType].PickupMenu then
Client._Menus[CargoData.CargoType].PickupMenu = missionCommands.addSubMenuForGroup(
Client:ClientGroup():getID(),
self.TEXT[1],
nil
)
trace.i( self.ClassName, 'Added PickupMenu' .. self.TEXT[1] )
end
if Client._Menus[CargoData.CargoType].PickupSubMenus == nil then
Client._Menus[CargoData.CargoType].PickupSubMenus = {}
end
local MenuAdd = false
if CargoData.CargoType.TRANSPORT == CARGO_TRANSPORT.UNIT then
CargoGroup = Group.getByName( CargoData.CargoGroupName )
if routines.IsPartOfGroupInRadius( CargoGroup, Client:ClientGroup(), TransportRadius ) then
MenuAdd = true
end
else
MenuAdd = true
end
if MenuAdd then
Client._Menus[CargoData.CargoType].PickupSubMenus[ #Client._Menus[CargoData.CargoType].PickupSubMenus + 1 ] = missionCommands.addCommandForGroup(
Client:ClientGroup():getID(),
CargoData.CargoName .. " ( " .. CargoData.CargoWeight .. "kg )",
Client._Menus[CargoData.CargoType].PickupMenu,
self.MenuAction,
{ ReferenceTask = self, CargoName = CargoData.CargoName }
)
trace.i( self.ClassName, 'Added PickupSubMenu' .. CargoData.CargoType.TEXT .. ":" .. CargoData.CargoName .. " ( " .. CargoData.CargoWeight .. "kg )" )
end
if MenuAdd then
if Client._Menus[Cargo.CargoType] == nil then
Client._Menus[Cargo.CargoType] = {}
end
if not Client._Menus[Cargo.CargoType].PickupMenu then
Client._Menus[Cargo.CargoType].PickupMenu = missionCommands.addSubMenuForGroup(
Client:GetClientGroupID(),
self.TEXT[1] .. " " .. Cargo.CargoType,
nil
)
self:T( 'Added PickupMenu: ' .. self.TEXT[1] .. " " .. Cargo.CargoType )
end
if Client._Menus[Cargo.CargoType].PickupSubMenus == nil then
Client._Menus[Cargo.CargoType].PickupSubMenus = {}
end
Client._Menus[Cargo.CargoType].PickupSubMenus[ #Client._Menus[Cargo.CargoType].PickupSubMenus + 1 ] = missionCommands.addCommandForGroup(
Client:GetClientGroupID(),
Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )",
Client._Menus[Cargo.CargoType].PickupMenu,
self.MenuAction,
{ ReferenceTask = self, CargoTask = Cargo }
)
self:T( 'Added PickupSubMenu' .. Cargo.CargoType .. ":" .. Cargo.CargoName .. " ( " .. Cargo.CargoWeight .. "kg )" )
end
end
end
@ -102,103 +119,36 @@ trace.f(self.ClassName, { Client, Cargos, TransportRadius } )
end
function PICKUPTASK:RemoveCargoMenus( Client )
trace.f(self.ClassName, { Client } )
self:T()
for MenuID, MenuData in pairs( Client._Menus ) do
for SubMenuID, SubMenuData in pairs( MenuData.PickupSubMenus ) do
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), SubMenuData )
trace.i( self.ClassName, "Removed PickupSubMenu " )
missionCommands.removeItemForGroup( Client:GetClientGroupID(), SubMenuData )
self:T( "Removed PickupSubMenu " )
SubMenuData = nil
end
if MenuData.PickupMenu then
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), MenuData.PickupMenu )
trace.i( self.ClassName, "Removed PickupMenu " )
missionCommands.removeItemForGroup( Client:GetClientGroupID(), MenuData.PickupMenu )
self:T( "Removed PickupMenu " )
MenuData.PickupMenu = nil
end
end
for CargoID, Cargo in pairs( CARGOS ) do
self:T( { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo:IsStatusNone(), Cargo:IsStatusLoaded(), Cargo:IsStatusLoading(), Cargo:IsStatusUnLoaded() } )
if Cargo:IsStatusLoading() and Client == Cargo:IsLoadingToClient() then
Cargo:StatusNone()
end
end
end
function PICKUPTASK:HasFailed( ClientDead )
trace.f(self.ClassName)
self:T()
local TaskHasFailed = self.TaskFailed
return TaskHasFailed
end
function PICKUPTASK:OnBoardCargo( ClientGroup, Cargos )
trace.f(self.ClassName, { ClientGroup, Cargos } )
local Valid = true
Valid = routines.ValidateGroup( ClientGroup, "ClientGroup", Valid )
if Valid then
local CarrierPos = ClientGroup:getUnits()[1]:getPoint()
local CarrierPosMove = ClientGroup:getUnits()[1]:getPoint()
local CarrierPosOnBoard = ClientGroup:getUnits()[1]:getPoint()
local CargoGroup = Group.getByName( Cargos[ self.CargoName ].CargoGroupName )
trigger.action.activateGroup( CargoGroup )
trigger.action.setGroupAIOn( CargoGroup )
local CargoUnits = CargoGroup:getUnits()
local CargoPos = CargoUnits[1]:getPoint()
local Points = {}
trace.i( self.ClassName, 'CargoPos x = ' .. CargoPos.x .. " z = " .. CargoPos.z )
trace.i( self.ClassName, 'CarrierPosMove x = ' .. CarrierPosMove.x .. " z = " .. CarrierPosMove.z )
Points[#Points+1] = routines.ground.buildWP( CargoPos, "off road", 6 )
trace.i( self.ClassName, 'Points[1] x = ' .. Points[1].x .. " y = " .. Points[1].y )
if self.OnBoardSide == nil then
self.OnBoardSide = CLIENT.ONBOARDSIDE.NONE
end
if self.OnBoardSide == CLIENT.ONBOARDSIDE.LEFT then
trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding LEFT" )
CarrierPosMove.z = CarrierPosMove.z - 50
CarrierPosOnBoard.z = CarrierPosOnBoard.z - 5
Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "diamond", 6 )
Points[#Points+1] = routines.ground.buildWP( CarrierPosOnBoard, "diamond", 6 )
elseif self.OnBoardSide == CLIENT.ONBOARDSIDE.RIGHT then
trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding RIGHT" )
CarrierPosMove.z = CarrierPosMove.z + 50
CarrierPosOnBoard.z = CarrierPosOnBoard.z + 5
Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "diamond", 6 )
Points[#Points+1] = routines.ground.buildWP( CarrierPosOnBoard, "diamond", 6 )
elseif self.OnBoardSide == CLIENT.ONBOARDSIDE.BACK then
trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding BACK" )
CarrierPosMove.x = CarrierPosMove.x - 50
CarrierPosOnBoard.x = CarrierPosOnBoard.x - 5
Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "diamond", 6 )
Points[#Points+1] = routines.ground.buildWP( CarrierPosOnBoard, "diamond", 6 )
elseif self.OnBoardSide == CLIENT.ONBOARDSIDE.FRONT then
trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding FRONT" )
CarrierPosMove.x = CarrierPosMove.x + 50
CarrierPosOnBoard.x = CarrierPosOnBoard.x + 5
Points[#Points+1] = routines.ground.buildWP( CarrierPosMove, "diamond", 6 )
Points[#Points+1] = routines.ground.buildWP( CarrierPosOnBoard, "diamond", 6 )
elseif self.OnBoardSide == CLIENT.ONBOARDSIDE.NONE then
trace.i( self.ClassName, "TransportCargoOnBoard: Onboarding CENTRAL" )
Points[#Points+1] = routines.ground.buildWP( CarrierPos, "diamond", 6 )
end
trace.i( self.ClassName, "TransportCargoOnBoard: Routing " .. Cargos[ self.CargoName ].CargoGroupName )
trace.i( self.ClassName, 'Points[2] x = ' .. Points[2].x .. " y = " .. Points[2].y )
trace.i( self.ClassName, 'Points[3] x = ' .. Points[3].x .. " y = " .. Points[3].y )
routines.scheduleFunction(routines.goRoute, {Cargos[ self.CargoName ].CargoGroupName, Points}, timer.getTime() + 8)
--routines.goRoute( Cargos[ self.CargoName ].CargoGroupName, Points )
end
return Valid
end

View File

@ -25,6 +25,107 @@ routines.build = 22
-- Utils- conversion, Lua utils, etc.
routines.utils = {}
--from http://lua-users.org/wiki/CopyTable
routines.utils.deepCopy = function(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
local objectreturn = _copy(object)
return objectreturn
end
-- porting in Slmod's serialize_slmod2
routines.utils.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
lookup_table = {}
local function _Serialize( tbl )
if type(tbl) == 'table' then --function only works for tables!
if lookup_table[tbl] then
return lookup_table[object]
end
local tbl_str = {}
lookup_table[tbl] = tbl_str
tbl_str[#tbl_str + 1] = '{'
for ind,val in pairs(tbl) do -- serialize its fields
if type(ind) == "number" then
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = tostring(ind)
tbl_str[#tbl_str + 1] = ']='
else --must be a string
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(ind)
tbl_str[#tbl_str + 1] = ']='
end
if ((type(val) == 'number') or (type(val) == 'boolean')) then
tbl_str[#tbl_str + 1] = tostring(val)
tbl_str[#tbl_str + 1] = ','
elseif type(val) == 'string' then
tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(val)
tbl_str[#tbl_str + 1] = ','
elseif type(val) == 'nil' then -- won't ever happen, right?
tbl_str[#tbl_str + 1] = 'nil,'
elseif type(val) == 'table' then
if ind == "__index" then
tbl_str[#tbl_str + 1] = "__index"
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
tbl_str[#tbl_str + 1] = _Serialize(val)
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
end
elseif type(val) == 'function' then
tbl_str[#tbl_str + 1] = "function " .. tostring(ind)
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
env.info( debug.traceback() )
end
end
tbl_str[#tbl_str + 1] = '}'
return table.concat(tbl_str)
else
return tostring(tbl)
end
end
local objectreturn = _Serialize(tbl)
return objectreturn
end
--porting in Slmod's "safestring" basic serialize
routines.utils.basicSerialize = function(s)
if s == nil then
return "\"\""
else
if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then
return tostring(s)
elseif type(s) == 'string' then
s = string.format('%q', s)
return s
end
end
end
routines.utils.toDegree = function(angle)
@ -137,91 +238,6 @@ function routines.utils.get3DDist(point1, point2)
end
--from http://lua-users.org/wiki/CopyTable
routines.utils.deepCopy = function(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
local objectreturn = _copy(object)
return objectreturn
end
-- porting in Slmod's serialize_slmod2
routines.utils.oneLineSerialize = function(tbl) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
if type(tbl) == 'table' then --function only works for tables!
local tbl_str = {}
tbl_str[#tbl_str + 1] = '{'
for ind,val in pairs(tbl) do -- serialize its fields
if type(ind) == "number" then
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = tostring(ind)
tbl_str[#tbl_str + 1] = ']='
else --must be a string
tbl_str[#tbl_str + 1] = '['
tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(ind)
tbl_str[#tbl_str + 1] = ']='
end
if ((type(val) == 'number') or (type(val) == 'boolean')) then
tbl_str[#tbl_str + 1] = tostring(val)
tbl_str[#tbl_str + 1] = ','
elseif type(val) == 'string' then
tbl_str[#tbl_str + 1] = routines.utils.basicSerialize(val)
tbl_str[#tbl_str + 1] = ','
elseif type(val) == 'nil' then -- won't ever happen, right?
tbl_str[#tbl_str + 1] = 'nil,'
elseif type(val) == 'table' then
if ind == "__index" then
tbl_str[#tbl_str + 1] = "__index"
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
tbl_str[#tbl_str + 1] = routines.utils.oneLineSerialize(val)
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
end
elseif type(val) == 'function' then
tbl_str[#tbl_str + 1] = "function " .. tostring(ind)
tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
env.info( debug.traceback() )
end
end
tbl_str[#tbl_str + 1] = '}'
return table.concat(tbl_str)
else
return tostring(tbl)
end
end
--porting in Slmod's "safestring" basic serialize
routines.utils.basicSerialize = function(s)
if s == nil then
return "\"\""
else
if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then
return tostring(s)
elseif type(s) == 'string' then
s = string.format('%q', s)
return s
end
end
end
-- From http://lua-users.org/wiki/SimpleRound
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
@ -280,6 +296,9 @@ routines.vec.rotateVec2 = function(vec2, theta)
end
---------------------------------------------------------------------------------------------------------------------------
-- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5.
routines.tostringMGRS = function(MGRS, acc)
if acc == 0 then
@ -1521,85 +1540,48 @@ trace.r( "", "", { TransportZoneResult } )
end
function routines.IsUnitInRadius( CargoUnit, ReferenceGroup, Radius )
function routines.IsUnitInRadius( CargoUnit, ReferencePosition, Radius )
trace.f()
local Valid = true
-- fill-up some local variables to support further calculations to determine location of units within the zone.
local CargoPos = CargoUnit:getPosition().p
local ReferenceGroupPos = ReferenceGroup:getUnits()[1]:getPosition().p
local ReferenceP = ReferencePosition.p
if (((CargoPos.x - ReferenceGroupPos.x)^2 + (CargoPos.z - ReferenceGroupPos.z)^2)^0.5 <= Radius) then
if (((CargoPos.x - ReferenceP.x)^2 + (CargoPos.z - ReferenceP.z)^2)^0.5 <= Radius) then
else
Valid = false
end
trace.r( "", "", { Valid } )
return Valid
end
function routines.IsPartOfGroupInRadius( CargoGroup, ReferenceGroup, Radius )
function routines.IsPartOfGroupInRadius( CargoGroup, ReferencePosition, Radius )
trace.f()
local Valid = true
Valid = routines.ValidateGroup( CargoGroup, "CargoGroup", Valid )
Valid = routines.ValidateGroup( ReferenceGroup, "ReferenceGroup", Valid )
-- fill-up some local variables to support further calculations to determine location of units within the zone
local CargoUnits = CargoGroup:getUnits()
for CargoUnitId, CargoUnit in pairs( CargoUnits ) do
local CargoUnitPos = CargoUnit:getPosition().p
-- env.info( 'routines.IsPartOfGroupInRadius: CargoUnitPos.x = ' .. CargoUnitPos.x .. ' CargoUnitPos.z = ' .. CargoUnitPos.z )
local ReferenceGroupPos = ReferenceGroup:getUnits()[1]:getPosition().p
local ReferenceP = ReferencePosition.p
-- env.info( 'routines.IsPartOfGroupInRadius: ReferenceGroupPos.x = ' .. ReferenceGroupPos.x .. ' ReferenceGroupPos.z = ' .. ReferenceGroupPos.z )
if ((( CargoUnitPos.x - ReferenceGroupPos.x)^2 + (CargoUnitPos.z - ReferenceGroupPos.z)^2)^0.5 <= Radius) then
if ((( CargoUnitPos.x - ReferenceP.x)^2 + (CargoUnitPos.z - ReferenceP.z)^2)^0.5 <= Radius) then
else
Valid = false
break
end
end
trace.r( "", "", { Valid } )
return Valid
end
function routines.DestroyGroupInRadiusFromGroup( CargoGroup, ReferenceGroup, Radius )
trace.f()
local Valid = true
Valid = routines.ValidateGroup( CargoGroup, "CargoGroup", Valid )
Valid = routines.ValidateGroup( ReferenceGroup, "ReferenceGroup", Valid )
if Valid then
-- fill-up some local variables to support further calculations to determine location of units within the zone
local CargoUnits = CargoGroup:getUnits()
local AliveCargoUnits = #CargoUnits
for CargoUnitId, CargoUnit in pairs( CargoUnits ) do
local CargoUnitPos = CargoUnit:getPosition().p
-- env.info( 'routines.DestroyGroupInRadiusFromGroup: CargoUnitPos.x = ' .. CargoUnitPos.x .. ' CargoUnitPos.z = ' .. CargoUnitPos.z )
local ReferenceGroupPos = ReferenceGroup:getUnits()[1]:getPosition().p
-- env.info( 'routines.DestroyGroupInRadiusFromGroup: ReferenceGroupPos.x = ' .. ReferenceGroupPos.x .. ' ReferenceGroupPos.z = ' .. ReferenceGroupPos.z )
if ((( CargoUnitPos.x - ReferenceGroupPos.x)^2 + (CargoUnitPos.z - ReferenceGroupPos.z)^2)^0.5 <= Radius) then
CargoUnit:destroy()
AliveCargoUnits = AliveCargoUnits - 1
else
Valid = false
break
end
end
else
AliveCargoUnits = -1
end
trace.r( "", "", { AliveCargoUnits } )
return AliveCargoUnits
end
function routines.ValidateString( Variable, VariableName, Valid )
trace.f()
@ -1866,6 +1848,23 @@ routines.ground.patrol = function(gpData, pType, form, speed)
return
end
function routines.GetUnitHeight( CheckUnit )
trace.f( "routines" )
local UnitPoint = CheckUnit:getPoint()
local UnitPosition = { x = UnitPoint.x, y = UnitPoint.z }
local UnitHeight = UnitPoint.y
local LandHeight = land.getHeight( UnitPosition )
--env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight ))
trace.f( "routines", "Unit Height = " .. UnitHeight - LandHeight )
return UnitHeight - LandHeight
end
Su34Status = { status = {} }
@ -2399,7 +2398,7 @@ trace.f()
--env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight ))
return CarrierHeight - LandHeight
return UnitHeight - LandHeight
end

View File

@ -30,51 +30,48 @@ SEAD = {
-- -- Defends the Russian SA installations from SEAD attacks.
-- SEAD_RU_SAM_Defenses = SEAD:New( { 'RU SA-6 Kub', 'RU SA-6 Defenses', 'RU MI-26 Troops', 'RU Attack Gori' } )
function SEAD:New( SEADGroupPrefixes )
trace.f(self.ClassName, SEADGroupPrefixes )
-- Arrange meta tables
local Child = BASE:Inherit( self, BASE:New() )
local self = BASE:Inherit( self, BASE:New() )
self:T( SEADGroupPrefixes )
if type( SEADGroupPrefixes ) == 'table' then
for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do
Child.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix
self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix
end
else
Child.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes
self.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes
end
Child.AddEvent( Child, world.event.S_EVENT_SHOT, Child.EventShot )
Child.EnableEvents( Child )
self.AddEvent( self, world.event.S_EVENT_SHOT, self.EventShot )
self.EnableEvents( self )
return Child
return self
end
--- Detects if an SA site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
-- @see SEAD
function SEAD:EventShot( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired
local _groupname = _grp:getName() -- return the name of the group
local _unittable = {event.initiator:getName()} -- return the name of the units in the group
local _SEADmissile = event.weapon -- Identify the weapon fired
local _SEADmissileName = _SEADmissile:getTypeName() -- return weapon type
--trigger.action.outText( string.format("Alerte, depart missile " ..string.format(_SEADmissileName)), 20) --debug message
local SEADUnit = event.initiator
local SEADUnitName = SEADUnit:getName()
local SEADWeapon = event.weapon -- Identify the weapon fired
local SEADWeaponName = SEADWeapon:getTypeName() -- return weapon type
--trigger.action.outText( string.format("Alerte, depart missile " ..string.format(SEADWeaponName)), 20) --debug message
-- Start of the 2nd loop
trace.i( self.ClassName, "Missile Launched = " .. _SEADmissileName )
if _SEADmissileName == "KH-58" or _SEADmissileName == "KH-25MPU" or _SEADmissileName == "AGM-88" or _SEADmissileName == "KH-31A" or _SEADmissileName == "KH-31P" then -- Check if the missile is a SEAD
self:T( "Missile Launched = " .. SEADWeaponName )
if SEADWeaponName == "KH-58" or SEADWeaponName == "KH-25MPU" or SEADWeaponName == "AGM-88" or SEADWeaponName == "KH-31A" or SEADWeaponName == "KH-31P" then -- Check if the missile is a SEAD
local _evade = math.random (1,100) -- random number for chance of evading action
local _targetMim = Weapon.getTarget(_SEADmissile) -- Identify target
local _targetMim = Weapon.getTarget(SEADWeapon) -- Identify target
local _targetMimname = Unit.getName(_targetMim)
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(_SEADmissile))
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
local _targetMimgroupName = _targetMimgroup:getName()
local _targetMimcont= _targetMimgroup:getController()
local _targetskill = _Database.Units[_targetMimname].Template.skill
trace.i( self.ClassName, self.SEADGroupPrefixes )
trace.i( self.ClassName, _targetMimgroupName )
self:T( self.SEADGroupPrefixes )
self:T( _targetMimgroupName )
local SEADGroupFound = false
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then
SEADGroupFound = true
trace.i( self.ClassName, 'Group Found' )
self:T( 'Group Found' )
break
end
end
@ -83,15 +80,15 @@ trace.f( self.ClassName, { event } )
local Skills = { "Average", "Good", "High", "Excellent" }
_targetskill = Skills[ math.random(1,4) ]
end
trace.i( self.ClassName, _targetskill ) -- debug message for skill check
self:T( _targetskill ) -- debug message for skill check
if self.TargetSkill[_targetskill] then
if (_evade > self.TargetSkill[_targetskill].Evade) then
trace.i( self.ClassName, string.format("Evading, target skill " ..string.format(_targetskill)) ) --debug message
local _targetMim = Weapon.getTarget(_SEADmissile)
self:T( string.format("Evading, target skill " ..string.format(_targetskill)) ) --debug message
local _targetMim = Weapon.getTarget(SEADWeapon)
local _targetMimname = Unit.getName(_targetMim)
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(_SEADmissile))
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
local _targetMimcont= _targetMimgroup:getController()
routines.groupRandomDistSelf(_targetMimgroup,300,'Rank',250,20) -- move randomly
routines.groupRandomDistSelf(_targetMimgroup,300,'Diamond',250,20) -- move randomly
local SuppressedGroups1 = {} -- unit suppressed radar off for a random time
local function SuppressionEnd1(id)
id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN)

View File

@ -1,39 +0,0 @@
--- A SLINGLOADHOOKTASK will orchestrate the sling-load hook activity to slingload a CARGO from a specific landing zone(s).
-- @classmod SLINGLOADHOOKTASK
Include.File("Task")
SLINGLOADHOOKTASK = {
ClassName = "SLINGLOADHOOKTASK",
GoalVerb = "Hook and Sling Cargo"
}
--- Creates a new SLINGLOADHOOKTASK.
-- @tparam table{string,...}|string LandingZones Table or name of the zone(s) where Cargo is to be loaded.
-- @tparam table{string,...)|string CargoPrefixes is the name or prefix of the name of the Cargo objects defined within the DCS ME.
-- @treturn SLINGLOADHOOKTASK
function SLINGLOADHOOKTASK:New( LandingZones, CargoPrefixes )
trace.f(self.ClassName)
local self = BASE:Inherit( self, TASK:New() )
self.Name = 'Hook and Sling Cargo'
self.TaskBriefing = "Task: Hook"
if type( LandingZones ) == "table" then
self.LandingZones = LandingZones
else
self.LandingZones = { LandingZones }
end
if type( CargoPrefixes ) == "table" then
self.CargoPrefixes = CargoPrefixes
else
self.CargoPrefixes = { CargoPrefixes }
end
self.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGE_SLINGLOAD_HOOK:New(), STAGEDONE:New() }
self:SetStage( 1 )
return self
end

View File

@ -1,38 +0,0 @@
--- A SLINGLOADUNHOOKTASK will orchestrate the sling-load unhook activity to (sling)load a CARGO and deploy it in a specific landing zone(s).
-- @classmod SLINGLOADUNHOOKTASK
Include.File("Task")
SLINGLOADUNHOOKTASK = {
ClassName = "SLINGLOADUNHOOKTASK",
GoalVerb = "Sling and UnHook Cargo"
}
--- Creates a new SLINGLOADUNHOOKTASK.
-- @tparam table{string,...}|string LandingZones Table or name of the zone(s) where Cargo is to be loaded.
-- @tparam table{string,...}|string CargoPrefixes is the name or prefix of the name of the Cargo objects defined within the DCS ME.
function SLINGLOADUNHOOKTASK:New( LandingZones, CargoPrefixes )
trace.f(self.ClassName)
local self = BASE:Inherit( self, TASK:New() )
self.Name = 'Sling and Unhook Cargo'
self.TaskBriefing = "Task: UnHook"
if type( LandingZones ) == "table" then
self.LandingZones = LandingZones
else
self.LandingZones = { LandingZones }
end
if type( CargoPrefixes ) == "table" then
self.CargoPrefixes = CargoPrefixes
else
self.CargoPrefixes = { CargoPrefixes }
end
self.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGE_SLINGLOAD_UNHOOK:New(), STAGEDONE:New() }
self:SetStage( 1 )
return self
end

View File

@ -2,9 +2,13 @@
-- @classmod SPAWN
-- @author Flightcontrol
MOOSE_Version = "0.1.1.1"
Include.File( "Routines" )
Include.File( "Base" )
Include.File( "Database" )
Include.File( "Group" )
SPAWN = {
ClassName = "SPAWN",
@ -23,10 +27,8 @@ SPAWN = {
-- -- NATO helicopters engaging in the battle field.
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' )
function SPAWN:New( SpawnPrefix )
trace.f(self.ClassName, SpawnPrefix)
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
self:T( SpawnPrefix)
local TemplateGroup = Group.getByName( SpawnPrefix )
if TemplateGroup then
@ -39,6 +41,7 @@ trace.f(self.ClassName, SpawnPrefix)
self.UnControlled = false -- When working in UnControlled mode, all planes are Spawned in UnControlled mode before the scheduler starts.
self.SpawnMaxGroupsAlive = 0 -- The maximum amount of groups that can be alive of SpawnPrefix at the same time.
self.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned.
self.SpawnRandomize = false
else
error( "SPAWN:New: There is no group declared in the mission editor with SpawnPrefix = '" .. SpawnPrefix .. "'" )
end
@ -65,11 +68,12 @@ end
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):RandomizeRoute( 2, 2, 2000 )
function SPAWN:RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius )
trace.f( self.ClassName, { SpawnStartPoint, SpawnEndPoint, SpawnRadius } )
self:T( { SpawnStartPoint, SpawnEndPoint, SpawnRadius } )
self.SpawnStartPoint = SpawnStartPoint -- When the spawning occurs, randomize the route points from SpawnStartPoint.
self.SpawnEndPoint = SpawnEndPoint -- When the spawning occurs, randomize the route points till SpawnEndPoint.
self.SpawnRadius = SpawnRadius -- The Radius of randomization of the route points from SpawnStartPoint till SpawnEndPoint.
self.SpawnRandomize = true
return self
end
@ -89,7 +93,7 @@ end
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
function SPAWN:Schedule( SpawnTime, SpawnTimeVariation )
trace.f( self.ClassName, { SpawnTime, SpawnTimeVariation } )
self:T( { SpawnTime, SpawnTimeVariation } )
self.SpawnCurrentTimer = 0 -- The internal timer counter to trigger a scheduled spawning of SpawnPrefix.
self.SpawnSetTimer = 0 -- The internal timer value when a scheduled spawning of SpawnPrefix occurs.
@ -103,7 +107,7 @@ trace.f( self.ClassName, { SpawnTime, SpawnTimeVariation } )
self:ScheduleStart()
end
trace.i( self.ClassName, { self.SpawnLowTimer, self.SpawnHighTimer } )
self:T( { self.SpawnLowTimer, self.SpawnHighTimer } )
return self
end
@ -111,7 +115,7 @@ end
--- Will start the SPAWNing timers.
-- This function is called automatically when @{Schedule} is called.
function SPAWN:ScheduleStart()
trace.f( self.ClassName )
self:T()
--local ClientUnit = #AlivePlayerUnits()
@ -128,7 +132,7 @@ end
--- Will stop the scheduled SPAWNing activity.
function SPAWN:ScheduleStop()
trace.f( self.ClassName )
self:T()
self.SpawnScheduled = false
end
@ -146,7 +150,7 @@ end
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Limit( 2, 24 )
function SPAWN:Limit( SpawnMaxGroupsAlive, SpawnMaxGroups )
trace.f( self.ClassName, { SpawnMaxGroupsAlive, SpawnMaxGroups } )
self:T( { SpawnMaxGroupsAlive, SpawnMaxGroups } )
self.SpawnMaxGroupsAlive = SpawnMaxGroupsAlive -- The maximum amount of groups that can be alive of SpawnPrefix at the same time.
self.SpawnMaxGroups = SpawnMaxGroups -- The maximum amount of groups that can be spawned.
@ -173,7 +177,7 @@ end
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):Limit( 12, 150 ):Schedule( 200, 0.4 ):RandomizeTemplate( Spawn_US_Platoon ):RandomizeRoute( 3, 3, 2000 )
function SPAWN:RandomizeTemplate( SpawnPrefixTable )
trace.f( self.ClassName, { SpawnPrefix, SpawnPrefixTable } )
self:T( { SpawnPrefix, SpawnPrefixTable } )
self.SpawnPrefixTable = SpawnPrefixTable
@ -190,7 +194,7 @@ end
-- SpawnRU_SU34 = SPAWN:New( 'TF1 RU Su-34 Krymsk@AI - Attack Ships' ):Schedule( 2, 3, 1800, 0.4 ):SpawnUncontrolled():RandomizeRoute( 1, 1, 3000 ):RepeatOnEngineShutDown()
function SPAWN:Repeat()
trace.f( self.ClassName )
self:T()
self.SpawnRepeat = true
self.RepeatOnEngineShutDown = false
@ -209,7 +213,7 @@ end
-- @see Repeat
function SPAWN:RepeatOnLanding()
trace.f( self.ClassName )
self:T()
self:Repeat()
self.RepeatOnEngineShutDown = false
@ -223,7 +227,7 @@ end
-- @see Repeat
function SPAWN:RepeatOnEngineShutDown()
trace.f( self.ClassName )
self:T()
self:Repeat()
self.RepeatOnEngineShutDown = true
@ -232,15 +236,64 @@ trace.f( self.ClassName )
return self
end
function SPAWN:CleanUp( SpawnCleanUpInterval )
self:T()
self.SpawnCleanUpInterval = SpawnCleanUpInterval
self.SpawnCleanUpTimeStamps = {}
self.CleanUpFunction = routines.scheduleFunction( self._SpawnCleanUpScheduler, { self }, timer.getTime() + 1, 60 )
end
function SPAWN:_SpawnCleanUpScheduler()
self:T()
local SpawnGroup = self:GetFirstAliveGroup()
while SpawnGroup do
if SpawnGroup:AllOnGround() and SpawnGroup:GetMaxVelocity() < 1 then
if not self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] then
self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] = timer.getTime()
else
if self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] + self.SpawnCleanUpInterval < timer.getTime() then
SpawnGroup:Destroy()
end
end
else
self.SpawnCleanUpTimeStamps[SpawnGroup:GetName()] = nil
end
SpawnGroup = self:GetNextAliveGroup()
end
end
--- Will SPAWN a Group whenever you want to do this.
-- Note that the configuration with the above functions will apply when calling this method: Maxima, Randomization of routes, Scheduler, ...
-- Uses @{DATABASE} global object defined in MOOSE.
-- @treturn SPAWN
function SPAWN:Spawn()
trace.f( self.ClassName )
local SpawnTemplate = self:_Prepare( true )
if self.SpawnStartPoint ~= 0 or self.SpawnEndPoint ~= 0 then
function SPAWN:Spawn( SpawnGroupName )
self:T( { self.SpawnPrefix, SpawnGroupName } )
local SpawnTemplate = self:_Prepare( SpawnGroupName )
if self.SpawnRandomize then
SpawnTemplate = self:_RandomizeRoute( SpawnTemplate )
end
_Database:Spawn( SpawnTemplate )
if self.SpawnRepeat then
_Database:SetStatusGroup( SpawnTemplate.name, "ReSpawn" )
end
return self
end
--- Will SPAWN a Group with a specified index number whenever you want to do this.
-- Note that the configuration with the above functions will apply when calling this method: Maxima, Randomization of routes, Scheduler, ...
-- Uses @{DATABASE} global object defined in MOOSE.
-- @treturn SPAWN
function SPAWN:SpawnWithIndex( SpawnIndex )
self:T( { self.SpawnPrefix, SpawnIndex } )
local SpawnTemplate = self:_Prepare( self:SpawnGroupName( SpawnIndex ) )
if self.SpawnRandomize then
SpawnTemplate = self:_RandomizeRoute( SpawnTemplate )
end
_Database:Spawn( SpawnTemplate )
@ -257,12 +310,15 @@ end
-- @treturn SPAWN
-- Uses _Database global object defined in MOOSE.
function SPAWN:ReSpawn( SpawnGroupName )
trace.f( self.ClassName, { SpawnGroupName } )
self:T( { SpawnGroupName } )
local SpawnGroup = Group.getByName( SpawnGroupName )
SpawnGroup:destroy()
local SpawnTemplate = self:_Prepare( false )
-- Give the Group the original name of the Group.
SpawnTemplate.name = SpawnGroupName
if SpawnGroup then
SpawnGroup:destroy()
end
local SpawnTemplate = self:_Prepare( SpawnGroupName )
-- Give the units of the Group the name following the SPAWN naming convention, so that they don't replace other units within the ME.
local SpawnUnits = table.getn( SpawnTemplate.units )
for u = 1, SpawnUnits do
@ -276,13 +332,13 @@ end
--- Will SPAWN a Group whenever you want to do this, but for AIR Groups only to be applied, and will SPAWN the Group in Uncontrolled mode... This will be similar to the Uncontrolled flag setting in the ME.
-- @treturn SPAWN
function SPAWN:SpawnUncontrolled()
trace.f( self.ClassName )
self:T()
self.UnControlled = true
local SpawnCountStart = self.SpawnCount + 1
for SpawnCount = SpawnCountStart, self.SpawnMaxGroups do
local SpawnTemplate = self:_Prepare( true )
local SpawnTemplate = self:_Prepare( )
SpawnTemplate.uncontrolled = true
_Database:Spawn( SpawnTemplate )
end
@ -293,94 +349,212 @@ end
--- Will SPAWN a Group from a Carrier. This function is mostly advisable to be used if you want to simulate SPAWNing from air units, like helicopters, which are dropping infantry into a defined Landing Zone.
-- @tparam Group CarrierGroup is the Group of the AIR unit or GROUND unit dropping or unloading other units.
-- @tparam Group HostUnit is the AIR unit or GROUND unit dropping or unloading the Spawn group.
-- @tparam string TargetZonePrefix is the Prefix of the Zone defined in the ME where the Group should be moving to after drop.
-- @tparam string NewGroupName (forgot this).
-- @tparam bool LateActivate (optional) does the SPAWNing with Lateactivation on.
function SPAWN:FromCarrier( CarrierGroup, TargetZonePrefix, NewGroupName, LateActivate )
trace.f( self.ClassName, { CarrierGroup, TargetZonePrefix, NewGroupName, LateActivate } )
function SPAWN:FromHost( HostUnit, OuterRadius, InnerRadius, NewGroupName, LateActivate )
self:T( { HostUnit, OuterRadius, InnerRadius, NewGroupName, LateActivate } )
local SpawnTemplate
if CarrierGroup and CarrierGroup:isExist() and CarrierGroup:getUnit(1) then -- and CarrierGroup:getUnit(1):inAir() == false then
if HostUnit and HostUnit:isExist() then -- and HostUnit:getUnit(1):inAir() == false then
local GroupUnits = CarrierGroup:getUnits()
local GroupUnitCount = table.getn(GroupUnits)
trace.i( self.ClassName, "CarrierGroup:getSize() = " .. CarrierGroup:getSize() )
trace.i( self.ClassName, 'GroupUnitCount = ' .. GroupUnitCount )
for UnitId, UnitData in pairs(GroupUnits) do
SpawnTemplate = self:_Prepare( NewGroupName )
UnitDeploy = UnitData
SpawnTemplate = self:_Prepare( true )
if ( self.SpawnMaxGroups == 0 ) or ( self.SpawnCount <= self.SpawnMaxGroups ) then
if ( self.SpawnMaxGroupsAlive == 0 ) or ( self.AliveUnits < self.SpawnMaxGroupsAlive * #self.SpawnTemplate.units ) or self.UnControlled then
if ( self.SpawnMaxGroups == 0 ) or ( self.SpawnCount <= self.SpawnMaxGroups ) then
if ( self.SpawnMaxGroupsAlive == 0 ) or ( self.AliveUnits < self.SpawnMaxGroupsAlive * #self.SpawnTemplate.units ) or self.UnControlled then
if NewGroupName ~= nil then
SpawnTemplate.name = NewGroupName
if LateActivate ~= nil then
if LateActivate == true then
SpawnTemplate.lateActivation = true
SpawnTemplate.visible = true
end
if LateActivate ~= nil then
if LateActivate == true then
SpawnTemplate.lateActivation = true
SpawnTemplate.visible = true
end
end
SpawnTemplate = self:_RandomizeRoute( SpawnTemplate )
local TargetZone = trigger.misc.getZone( TargetZonePrefix )
local TargetZonePos = {}
TargetZonePos.x = TargetZone.point.x + math.random(TargetZone.radius * -1, TargetZone.radius)
TargetZonePos.z = TargetZone.point.z + math.random(TargetZone.radius * -1, TargetZone.radius)
local RouteCount = table.getn( SpawnTemplate.route.points )
trace.i( self.ClassName, "RouteCount = " .. RouteCount )
local UnitDeployPosition = UnitDeploy:getPoint()
SpawnTemplate.route.points[1].x = UnitDeployPosition.x - 50
SpawnTemplate.route.points[1].y = UnitDeployPosition.z
SpawnTemplate.route.points[1].alt = nil
SpawnTemplate.route.points[1].alt_type = nil
if SpawnStartPoint ~= 0 and SpawnEndPoint ~= 0 then
SpawnTemplate.route.points[RouteCount].x = TargetZonePos.x
SpawnTemplate.route.points[RouteCount].y = TargetZonePos.z
else
SpawnTemplate.route.points[RouteCount].x = TargetZone.point.x
SpawnTemplate.route.points[RouteCount].y = TargetZone.point.z
end
trace.i( self.ClassName, 'SpawnTemplate.route.points['..RouteCount..'].x = ' .. SpawnTemplate.route.points[RouteCount].x .. ', SpawnTemplate.route.points['..RouteCount..'].y = ' .. SpawnTemplate.route.points[RouteCount].y )
for v = 1, table.getn( SpawnTemplate.units ) do
local SpawnPos = routines.getRandPointInCircle( UnitDeployPosition, 40, 10 )
SpawnTemplate.units[v].x = SpawnPos.x
SpawnTemplate.units[v].y = SpawnPos.y
trace.i( self.ClassName, 'SpawnTemplate.units['..v..'].x = ' .. SpawnTemplate.units[v].x .. ', SpawnTemplate.units['..v..'].y = ' .. SpawnTemplate.units[v].y )
end
_Database:Spawn( SpawnTemplate )
end
SpawnTemplate = self:_RandomizeRoute( SpawnTemplate )
local RouteCount = table.getn( SpawnTemplate.route.points )
self:T( "RouteCount = " .. RouteCount )
local UnitDeployPosition = HostUnit:getPoint()
for PointID, Point in pairs( SpawnTemplate.route.points ) do
Point.x = UnitDeployPosition.x
Point.y = UnitDeployPosition.z
Point.alt = nil
Point.alt_type = nil
end
for v = 1, table.getn( SpawnTemplate.units ) do
local SpawnPos = routines.getRandPointInCircle( UnitDeployPosition, OuterRadius, InnerRadius )
SpawnTemplate.units[v].x = SpawnPos.x
SpawnTemplate.units[v].y = SpawnPos.y
self:T( 'SpawnTemplate.units['..v..'].x = ' .. SpawnTemplate.units[v].x .. ', SpawnTemplate.units['..v..'].y = ' .. SpawnTemplate.units[v].y )
end
_Database:Spawn( SpawnTemplate )
end
end
end
trace.r( self.ClassName, "" )
return SpawnTemplate
end
--- Will SPAWN a Group from a Carrier. This function is mostly advisable to be used if you want to simulate SPAWNing from air units, like helicopters, which are dropping infantry into a defined Landing Zone.
-- @tparam Group CarrierUnit is the AIR unit or GROUND unit dropping or unloading the Spawn group.
-- @tparam string TargetZonePrefix is the Prefix of the Zone defined in the ME where the Group should be moving to after drop.
-- @tparam string NewGroupName (forgot this).
-- @tparam bool LateActivate (optional) does the SPAWNing with Lateactivation on.
function SPAWN:FromCarrier( CarrierUnit, TargetZonePrefix, NewGroupName, LateActivate )
self:T( { CarrierUnit, TargetZonePrefix, NewGroupName, LateActivate } )
local SpawnTemplate
if CarrierUnit and CarrierUnit:isExist() then -- and CarrierUnit:getUnit(1):inAir() == false then
SpawnTemplate = self:_Prepare( NewGroupName )
if ( self.SpawnMaxGroups == 0 ) or ( self.SpawnCount <= self.SpawnMaxGroups ) then
if ( self.SpawnMaxGroupsAlive == 0 ) or ( self.AliveUnits < self.SpawnMaxGroupsAlive * #self.SpawnTemplate.units ) or self.UnControlled then
if LateActivate ~= nil then
if LateActivate == true then
SpawnTemplate.lateActivation = true
SpawnTemplate.visible = true
end
end
SpawnTemplate = self:_RandomizeRoute( SpawnTemplate )
local TargetZone = trigger.misc.getZone( TargetZonePrefix )
local TargetZonePos = {}
TargetZonePos.x = TargetZone.point.x + math.random(TargetZone.radius / 2 * -1, TargetZone.radius / 2 )
TargetZonePos.z = TargetZone.point.z + math.random(TargetZone.radius / 2 * -1, TargetZone.radius / 2 )
local RouteCount = table.getn( SpawnTemplate.route.points )
self:T( "RouteCount = " .. RouteCount )
local UnitDeployPosition = CarrierUnit:getPosition().p
SpawnTemplate.route.points[1].x = UnitDeployPosition.x - 50
SpawnTemplate.route.points[1].y = UnitDeployPosition.z
SpawnTemplate.route.points[1].alt = nil
SpawnTemplate.route.points[1].alt_type = nil
if self.SpawnRandomize then
SpawnTemplate.route.points[RouteCount].x = TargetZonePos.x
SpawnTemplate.route.points[RouteCount].y = TargetZonePos.z
else
SpawnTemplate.route.points[RouteCount].x = TargetZone.point.x
SpawnTemplate.route.points[RouteCount].y = TargetZone.point.z
end
self:T( 'SpawnTemplate.route.points['..RouteCount..'].x = ' .. SpawnTemplate.route.points[RouteCount].x .. ', SpawnTemplate.route.points['..RouteCount..'].y = ' .. SpawnTemplate.route.points[RouteCount].y )
for v = 1, table.getn( SpawnTemplate.units ) do
local SpawnPos = routines.getRandPointInCircle( UnitDeployPosition, 40, 10 )
SpawnTemplate.units[v].x = SpawnPos.x
SpawnTemplate.units[v].y = SpawnPos.y
self:T( 'SpawnTemplate.units['..v..'].x = ' .. SpawnTemplate.units[v].x .. ', SpawnTemplate.units['..v..'].y = ' .. SpawnTemplate.units[v].y )
end
_Database:Spawn( SpawnTemplate )
end
end
end
return SpawnTemplate
end
--- Will return the SpawnGroupName either with with a specific count number or without any count.
-- @tparam number SpawnIndex is the number of the Group that is to be SPAWNed.
-- @treturn string SpawnGroupName
function SPAWN:SpawnGroupName( SpawnIndex )
self:T( { self.SpawnPrefix, SpawnIndex } )
if SpawnIndex then
self:T( string.format( '%s#%03d', self.SpawnPrefix, SpawnIndex ) )
return string.format( '%s#%03d', self.SpawnPrefix, SpawnIndex )
else
self:T( self.SpawnPrefix )
return self.SpawnPrefix
end
end
function SPAWN:GetIndexFromGroup( Group )
self:T( { self.SpawnPrefix, Group } )
local IndexString = string.match( Group:GetName(), "#.*$" )
local Index = tonumber( IndexString:sub(2) )
self:T( IndexString, Index )
return Index
end
function SPAWN:GetLastIndex()
return self.SpawnCount
end
function SPAWN:GetFirstAliveGroup()
self:T()
self.SpawnIndex = 1
for SpawnIndex = 1, self.SpawnCount do
SpawnGroupName = self:SpawnGroupName( SpawnIndex )
SpawnGroup = Group.getByName( SpawnGroupName )
if SpawnGroup and SpawnGroup:isExist() then
self.SpawnIndex = SpawnIndex
return GROUP:New( SpawnGroup )
end
end
self.SpawnIndex = nil
return nil
end
function SPAWN:GetNextAliveGroup()
self:T()
self.SpawnIndex = self.SpawnIndex + 1
for SpawnIndex = self.SpawnIndex, self.SpawnCount do
SpawnGroupName = self:SpawnGroupName( SpawnIndex )
SpawnGroup = Group.getByName( SpawnGroupName )
if SpawnGroup and SpawnGroup:isExist() then
self.SpawnIndex = SpawnIndex
return GROUP:New( SpawnGroup )
end
end
self.SpawnIndex = nil
return nil
end
function SPAWN:GetLastAliveGroup()
self:T()
local LastGroupName = self:SpawnGroupName( self:GetLastIndex() )
return GROUP:New( Group.getByName( LastGroupName ) )
end
--- Will SPAWN a Group within a given ZoneName.
-- @tparam string ZonePrefix is the name of the zone where the Group is to be SPAWNed.
-- @treturn SpawnTemplate
function SPAWN:InZone( ZonePrefix )
trace.f("Spawn", ZonePrefix )
function SPAWN:InZone( ZonePrefix, SpawnGroupName )
self:T( ZonePrefix )
local SpawnTemplate = self:_Prepare( true )
local SpawnTemplate
if SpawnGroupName then
SpawnTemplate = self:_Prepare( SpawnGroupName )
else
SpawnTemplate = self:_Prepare()
end
local Zone = trigger.misc.getZone( ZonePrefix )
local ZonePos = {}
@ -443,7 +617,7 @@ end
--- Gets the Group Template from the ME environment definition.
-- This method used the @{DATABASE} object, which contains ALL initial and new SPAWNed object in MOOSE.
function SPAWN:_GetTemplate( SpawnPrefix )
trace.f( self.ClassName, SpawnPrefix )
self:T( SpawnPrefix )
local SpawnTemplate = nil
@ -457,13 +631,13 @@ trace.f( self.ClassName, SpawnPrefix )
SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnPrefix )
SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnPrefix )
trace.r( self.ClassName, "", { SpawnTemplate } )
self:T( { SpawnTemplate } )
return SpawnTemplate
end
--- Prepares the new Group Template before Spawning.
function SPAWN:_Prepare( SpawnIncrement )
trace.f( self.ClassName )
function SPAWN:_Prepare( SpawnGroupName )
self:T()
local SpawnCount
local SpawnUnits
@ -476,11 +650,14 @@ trace.f( self.ClassName )
end
-- Increase the spawn counter for the group
if SpawnIncrement == true then
if SpawnGroupName then
SpawnTemplate.name = SpawnGroupName
else
self.SpawnCount = self.SpawnCount + 1
SpawnTemplate.name = self:SpawnGroupName( self.SpawnCount )
end
SpawnTemplate.name = string.format( self.SpawnPrefix .. '#%03d', self.SpawnCount )
SpawnTemplate.groupId = nil
SpawnTemplate.lateActivation = false
if SpawnTemplate.SpawnCategoryID == Group.Category.GROUND then
@ -501,32 +678,32 @@ trace.f( self.ClassName )
SpawnUnits = table.getn( SpawnTemplate.units )
for u = 1, SpawnUnits do
SpawnTemplate.units[u].name = string.format( self.SpawnPrefix .. '#%03d-%02d', self.SpawnCount, u )
SpawnTemplate.units[u].name = string.format( SpawnTemplate.name .. '-%02d', u )
SpawnTemplate.units[u].unitId = nil
SpawnTemplate.units[u].x = SpawnTemplate.route.points[1].x
SpawnTemplate.units[u].y = SpawnTemplate.route.points[1].y
SpawnTemplate.units[u].x = SpawnTemplate.route.points[1].x + math.random( -50, 50 )
SpawnTemplate.units[u].y = SpawnTemplate.route.points[1].y + math.random( -50, 50 )
end
trace.r( self.ClassName, "", SpawnTemplate.name )
self:T( SpawnTemplate.name )
return SpawnTemplate
end
--- Will randomize the route of the Group Template.
function SPAWN:_RandomizeRoute( SpawnTemplate )
trace.f( self.ClassName, SpawnTemplate.name )
self:T( SpawnTemplate.name )
if self.SpawnStartPoint and self.SpawnEndPoint then
if self.SpawnRandomize then
local RouteCount = table.getn( SpawnTemplate.route.points )
for t = self.SpawnStartPoint, RouteCount - self.SpawnEndPoint do
for t = self.SpawnStartPoint+1, RouteCount - self.SpawnEndPoint do
SpawnTemplate.route.points[t].x = SpawnTemplate.route.points[t].x + math.random( self.SpawnRadius * -1, self.SpawnRadius )
SpawnTemplate.route.points[t].y = SpawnTemplate.route.points[t].y + math.random( self.SpawnRadius * -1, self.SpawnRadius )
SpawnTemplate.route.points[t].alt = nil
--SpawnGroup.route.points[t].alt_type = nil
trace.i( self.ClassName, 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y )
self:T( 'SpawnTemplate.route.points[' .. t .. '].x = ' .. SpawnTemplate.route.points[t].x .. ', SpawnTemplate.route.points[' .. t .. '].y = ' .. SpawnTemplate.route.points[t].y )
end
end
trace.r( self.ClassName, "", SpawnTemplate.name )
self:T( SpawnTemplate.name )
return SpawnTemplate
end
@ -536,16 +713,16 @@ end
--- Obscolete
-- @todo Need to delete this... _Database does this now ...
function SPAWN:OnBirth( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
if timer.getTime0() < timer.getAbsTime() then -- dont need to add units spawned in at the start of the mission if mist is loaded in init line
if event.initiator and event.initiator:getName() then
trace.l(self.ClassName, "OnBirth", "Birth object : " .. event.initiator:getName() )
self:T( "Birth object : " .. event.initiator:getName() )
local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then
--MessageToAll( "Mission command: unit " .. SpawnPrefix .. " spawned." , 5, EventPrefix .. '/Event')
self.AliveUnits = self.AliveUnits + 1
trace.l(self.ClassName, "OnBirth", self.AliveUnits )
self:T( self.AliveUnits )
end
end
end
@ -555,17 +732,17 @@ end
--- Obscolete
-- @todo Need to delete this... _Database does this now ...
function SPAWN:OnDeadOrCrash( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
if event.initiator and event.initiator:getName() then
trace.l( self.ClassName, "OnDeadOrCrash", "Dead object : " .. event.initiator:getName() )
self:T( "Dead object : " .. event.initiator:getName() )
local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then
-- local DestroyedUnit = Unit.getByName( EventPrefix )
-- if DestroyedUnit and DestroyedUnit.getLife() <= 1.0 then
--MessageToAll( "Mission command: unit " .. SpawnPrefix .. " crashed." , 5, EventPrefix .. '/Event')
self.AliveUnits = self.AliveUnits - 1
trace.l( self.ClassName, "OnDeadOrCrash", self.AliveUnits )
self:T( self.AliveUnits )
-- end
end
end
@ -575,17 +752,17 @@ end
-- This is needed to ensure that Re-SPAWNing is only done for landed AIR Groups.
-- @todo Need to test for AIR Groups only...
function SPAWN:OnLand( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
if event.initiator and event.initiator:getName() then
trace.l( self.ClassName, "OnLand", "Landed object : " .. event.initiator:getName() )
self:T( "Landed object : " .. event.initiator:getName() )
local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then
self.Landed = true
trace.l( self.ClassName, "OnLand", "self.Landed = true" )
self:T( "self.Landed = true" )
if self.Landed and self.RepeatOnLanding then
local SpawnGroupName = Unit.getGroup(event.initiator):getName()
trace.l( self.ClassName, "OnLand", "ReSpawn " .. SpawnGroupName )
self:T( "ReSpawn " .. SpawnGroupName )
self:ReSpawn( SpawnGroupName )
end
end
@ -596,13 +773,13 @@ end
-- This is needed to ensure that Re-SPAWNing only is done for landed AIR Groups.
-- @todo Need to test for AIR Groups only...
function SPAWN:OnTakeOff( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
if event.initiator and event.initiator:getName() then
trace.l( self.ClassName, "OnTakeOff", "TakeOff object : " .. event.initiator:getName() )
self:T( "TakeOff object : " .. event.initiator:getName() )
local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then
trace.l( self.ClassName, "OnTakeOff", "self.Landed = false" )
self:T( "self.Landed = false" )
self.Landed = false
end
end
@ -615,15 +792,15 @@ end
-- @see OnLand
-- @todo Need to test for AIR Groups only...
function SPAWN:OnEngineShutDown( event )
trace.f( self.ClassName, { event } )
self:T( { event } )
if event.initiator and event.initiator:getName() then
trace.l( self.ClassName, "OnEngineShutDown", "EngineShutDown object : " .. event.initiator:getName() )
self:T( "EngineShutDown object : " .. event.initiator:getName() )
local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then
if self.Landed and self.RepeatOnEngineShutDown then
local SpawnGroupName = Unit.getGroup(event.initiator):getName()
trace.l( self.ClassName, "OnEngineShutDown", "ReSpawn " .. SpawnGroupName )
self:T( "ReSpawn " .. SpawnGroupName )
self:ReSpawn( SpawnGroupName )
end
end
@ -636,7 +813,7 @@ end
--- This function is called automatically by the Spawning scheduler.
-- It is the internal worker method SPAWNing new Groups on the defined time intervals.
function SPAWN:_Scheduler()
trace.l( self.ClassName, '_Scheduler', self.SpawnPrefix )
self:T( self.SpawnPrefix )
if self.SpawnInit or self.SpawnCurrentTimer == self.SpawnSetTimer then
-- Validate if there are still groups left in the batch...

View File

@ -27,13 +27,12 @@ STAGE = {
function STAGE:New()
trace.f(self.ClassName)
local self = BASE:Inherit( self, BASE:New() )
self:T()
return self
end
function STAGE:Execute( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = true
@ -41,13 +40,10 @@ trace.f(self.ClassName)
end
function STAGE:Executing( Mission, Client, Task )
trace.f(self.ClassName)
end
function STAGE:Validate( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = true
return Valid
@ -56,31 +52,30 @@ end
STAGEBRIEF = {
ClassName = "BRIEF",
MSG = { ID = "Brief", TIME = 30 },
MSG = { ID = "Brief", TIME = 1 },
Name = "Brief",
StageBriefingTime = 0,
StageBriefingDuration = 30
StageBriefingDuration = 1
}
function STAGEBRIEF:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'CLIENT'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGEBRIEF:Execute( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
self:T()
Mission:ShowBriefing( Client )
self.StageBriefingTime = timer.getTime()
return Valid
end
function STAGEBRIEF:Validate( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = STAGE:Validate( Mission, Client, Task )
self:T()
if timer.getTime() - self.StageBriefingTime <= self.StageBriefingDuration then
return 0
@ -94,34 +89,33 @@ end
STAGESTART = {
ClassName = "START",
MSG = { ID = "Start", TIME = 30 },
MSG = { ID = "Start", TIME = 1 },
Name = "Start",
StageStartTime = 0,
StageStartDuration = 30
StageStartDuration = 1
}
function STAGESTART:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'CLIENT'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGESTART:Execute( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
if Task.TaskBriefing then
Client:Message( Task.TaskBriefing, self.StageStartDuration, Mission.Name .. "/Stage", "Mission Command: Tasking" )
Client:Message( Task.TaskBriefing, 30, Mission.Name .. "/Stage", "Mission Command: Tasking" )
else
Client:Message( 'Task ' .. Task.TaskNumber .. '.', self.StageStartDuration, Mission.Name .. "/Stage", "Mission Command: Tasking" )
Client:Message( 'Task ' .. Task.TaskNumber .. '.', 30, Mission.Name .. "/Stage", "Mission Command: Tasking" )
end
self.StageStartTime = timer.getTime()
return Valid
end
function STAGESTART:Validate( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
local Valid = STAGE:Validate( Mission, Client, Task )
if timer.getTime() - self.StageStartTime <= self.StageStartDuration then
@ -135,17 +129,90 @@ trace.f(self.ClassName)
end
STAGE_CARGO_LOAD = {
ClassName = "STAGE_CARGO_LOAD"
}
function STAGE_CARGO_LOAD:New()
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGE_CARGO_LOAD:Execute( Mission, Client, Task )
self:T()
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
for LoadCargoID, LoadCargo in pairs( Task.Cargos.LoadCargos ) do
LoadCargo:Load( Client )
end
if Mission.MissionReportFlash and Client:IsTransport() then
Client:ShowCargo()
end
return Valid
end
function STAGE_CARGO_LOAD:Validate( Mission, Client, Task )
self:T()
local Valid = STAGE:Validate( Mission, Client, Task )
return 1
end
STAGE_CARGO_INIT = {
ClassName = "STAGE_CARGO_INIT"
}
function STAGE_CARGO_INIT:New()
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGE_CARGO_INIT:Execute( Mission, Client, Task )
self:T()
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
for InitLandingZoneID, InitLandingZone in pairs( Task.LandingZones.LandingZones ) do
self:T( InitLandingZone )
InitLandingZone:Spawn()
end
self:T( Task.Cargos.InitCargos )
for InitCargoID, InitCargoData in pairs( Task.Cargos.InitCargos ) do
self:T( { InitCargoData } )
InitCargoData:Spawn()
end
return Valid
end
function STAGE_CARGO_INIT:Validate( Mission, Client, Task )
self:T()
local Valid = STAGE:Validate( Mission, Client, Task )
return 1
end
STAGEROUTE = {
ClassName = "STAGEROUTE",
MSG = { ID = "Route", TIME = 1 },
MSG = { ID = "Route", TIME = 5 },
Frequency = STAGE.FREQUENCY.REPEAT,
Name = "Route"
}
function STAGEROUTE:New()
trace.f(self.ClassName)
-- Arrange meta tables
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
self.MessageSwitch = true
return self
@ -153,19 +220,17 @@ end
function STAGEROUTE:Execute( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
if type( Task.LandingZones) == "table" then
local RouteMessage = "Fly to "
for LandingZoneID, LandingZoneName in pairs( Task.LandingZones ) do
RouteMessage = RouteMessage .. LandingZoneName .. ' at ' .. routines.getBRStringZone( { zone = LandingZoneName, ref = Client:ClientGroup():getUnit(1):getPoint(), true, true } ) .. ' km. '
end
Client:Message( RouteMessage, self.MSG.TIME, Mission.Name .. "/StageRoute", "Co-Pilot: Route", 10 )
else
Client:Message( "Fly to " .. Task.LandingZones .. ' at ' .. routines.getBRStringZone( { zone = Task.LandingZones, ref = Client:ClientGroup():getUnit(1):getPoint(), true, true } ) .. ' km. ', self.MSG.TIME, Mission.Name .. "/StageRoute", "Co-Pilot: Route", 1 )
local RouteMessage = "Fly to "
self:T( Task.LandingZones )
for LandingZoneID, LandingZoneName in pairs( Task.LandingZones.LandingZoneNames ) do
RouteMessage = RouteMessage .. LandingZoneName .. ' at ' .. routines.getBRStringZone( { zone = LandingZoneName, ref = Client:GetClientGroupUnit():getPoint(), true, true } ) .. ' km. '
end
if Client:IsTransport() then
Client:Message( RouteMessage, self.MSG.TIME, Mission.Name .. "/StageRoute", "Co-Pilot: Route", 20 )
if Mission.MissionReportFlash and Client:IsTransport() then
Client:ShowCargo()
end
@ -173,59 +238,32 @@ trace.f(self.ClassName)
end
function STAGEROUTE:Validate( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = STAGE:Validate( Mission, Client, Task )
self:T()
local Valid = STAGE:Validate( Mission, Client, Task )
-- check if the Client is in the landing zone
self:T( Task.LandingZones.LandingZoneNames )
Task.CurrentLandingZoneName = routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.LandingZones.LandingZoneNames )
if Task.CurrentLandingZoneName then
-- check if this carrier is in the landing zone
Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones )
if ( Task.CurrentLandingZoneID ) then
if not Task.Signalled then
if Task.LandingZoneSignalType then
env.info( 'TransportSchedule: Task.LandingZoneSignalType = ' .. Task.LandingZoneSignalType.TEXT )
if Task.LandingZoneSignalUnitNames then
local LandingZoneSignalUnit = Task.LandingZoneSignalUnitNames[Task.CurrentLandingZoneID]
trace.i( self.ClassName, 'LandingZoneSignalUnit = ' .. LandingZoneSignalUnit )
local SignalUnit = Unit.getByName(LandingZoneSignalUnit)
if SignalUnit == nil then
SignalUnit = StaticObject.getByName( LandingZoneSignalUnit )
end
if SignalUnit ~= nil then
trace.i( self.ClassName, 'Signalling Unit' )
local SignalVehiclePos = SignalUnit:getPosition().p
SignalVehiclePos.y = SignalVehiclePos.y + Task.LandingZoneSignalHeight
if Task.LandingZoneSignalType.ID == Task.SIGNAL.TYPE.SMOKE.ID then
trigger.action.smoke( SignalVehiclePos, Task.LandingZoneSignalColor.COLOR )
elseif Task.LandingZoneSignalType.ID == Task.SIGNAL.TYPE.FLARE.ID then
trigger.action.signalFlare( SignalVehiclePos, Task.LandingZoneSignalColor.COLOR, 0 )
end
end
else
env.info( 'TransportSchedule: Signaling landing zone ' )
local LandingZone = trigger.misc.getZone( Task.LandingZones [ Task.CurrentLandingZoneID ] )
local CurrentPosition = { x = LandingZone.point.x, y = LandingZone.point.z }
LandingZone.point.y = land.getHeight( CurrentPosition ) + 10
if Task.LandingZoneSignalType.ID == Task.SIGNAL.TYPE.SMOKE.ID then
env.info( 'TransportSchedule: Smoking zone x = ' .. LandingZone.point.x .. ' y = ' .. LandingZone.point.y .. ' z = ' .. LandingZone.point.z )
trigger.action.smoke( LandingZone.point, Task.LandingZoneSignalColor.COLOR )
elseif Task.LandingZoneSignalType.ID == Task.SIGNAL.TYPE.SMOKE.FLARE.ID then
env.info( 'TransportSchedule: Flaring zone x = ' .. LandingZone.point.x .. ' y = ' .. LandingZone.point.y .. ' z = ' .. LandingZone.point.z )
trigger.action.signalFlare( LandingZone.point, Task.LandingZoneSignalColor.COLOR, 0 )
end
Task.CurrentLandingZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName].CargoZone
Task.CurrentCargoZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName]
if Task.CurrentCargoZone then
if not Task.Signalled then
Task.Signalled = Task.CurrentCargoZone:Signal()
end
end
self.Signalled = true
return 1
end
return 1
end
return 0
return 0
end
STAGELANDING = {
ClassName = "STAGELANDING",
MSG = { ID = "Landing", TIME = 10 },
@ -234,37 +272,96 @@ STAGELANDING = {
}
function STAGELANDING:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'CLIENT'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGELANDING:Execute( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
Client:Message( 'We have arrived at ' .. Task.LandingZones[Task.CurrentLandingZoneID] .. '. Land the helicopter to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType.TEXT .. '.',
self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Landing" )
Client:Message( "We have arrived at the landing zone.", self.MSG.TIME, Mission.Name .. "/StageArrived", "Co-Pilot: Arrived", 10 )
Task.HostUnit = Task.CurrentCargoZone:GetHostUnit()
if Task.HostUnit then
Task.HostUnitName = Task.HostUnit:getName()
Task.HostUnitTypeName = Task.HostUnit:getTypeName()
local HostMessage = ""
Task.CargoNames = ""
local IsFirst = true
for CargoID, Cargo in pairs( CARGOS ) do
if Cargo.CargoType == Task.CargoType then
if Cargo:IsLandingRequired() then
self:T( "Task for cargo " .. Cargo.CargoType .. " requires landing.")
Task.IsLandingRequired = true
end
if Cargo:IsSlingLoad() then
self:T( "Task for cargo " .. Cargo.CargoType .. " is a slingload.")
Task.IsSlingLoad = true
end
if IsFirst then
IsFirst = false
Task.CargoNames = Task.CargoNames .. Cargo.CargoName .. "( " .. Cargo.CargoWeight .. " )"
else
Task.CargoNames = Task.CargoNames .. "; " .. Cargo.CargoName .. "( " .. Cargo.CargoWeight .. " )"
end
end
end
if Task.IsLandingRequired then
HostMessage = "Land the helicopter to " .. Task.TEXT[1] .. " " .. Task.CargoNames .. "."
else
HostMessage = "Use the Radio menu and F6 to find the cargo, then fly or land near the cargo and " .. Task.TEXT[1] .. " " .. Task.CargoNames .. "."
end
Client:Message( HostMessage, self.MSG.TIME, Mission.Name .. "/STAGELANDING.EXEC." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":", 10 )
end
end
function STAGELANDING:Validate( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then
else
Task.Signalled = false
Task:RemoveCargoMenus( Client )
return -1
end
Task.CurrentLandingZoneName = routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.LandingZones.LandingZoneNames )
if Task.CurrentLandingZoneName then
-- Client is in de landing zone.
self:T( Task.CurrentLandingZoneName )
Task.CurrentLandingZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName].CargoZone
Task.CurrentCargoZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName]
if Task.CurrentCargoZone then
if not Task.Signalled then
Task.Signalled = Task.CurrentCargoZone:Signal()
end
end
else
if Task.CurrentLandingZone then
Task.CurrentLandingZone = nil
end
if Task.CurrentCargoZone then
Task.CurrentCargoZone = nil
end
Task.Signalled = false
Task:RemoveCargoMenus( Client )
return -1
end
if not Client:ClientGroup():getUnits()[1]:inAir() then
else
return 0
end
if Task.IsLandingRequired and Client:GetClientGroupUnit():inAir() then
return 0
end
return 1
return 1
end
STAGELANDED = {
@ -275,46 +372,52 @@ STAGELANDED = {
}
function STAGELANDED:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'CLIENT'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGELANDED:Execute( Mission, Client, Task )
trace.f(self.ClassName)
Client:Message( 'We have landed within the landing zone. Use the radio menu (F10) to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType.TEXT .. '.', self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Landed" )
if not self.MenusAdded then
Task:RemoveCargoMenus( Client )
Task:AddCargoMenus( Client, Mission._Cargos, 250 )
self:T()
if Task.IsLandingRequired then
Client:Message( 'We have landed within the landing zone. Use the radio menu (F10) to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType .. '.',
self.MSG.TIME, Mission.Name .. "/STAGELANDED.EXEC." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
if not self.MenusAdded then
Task.Cargo = nil
Task:RemoveCargoMenus( Client )
Task:AddCargoMenus( Client, CARGOS, 250 )
end
end
end
function STAGELANDED:Validate( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then
else
Task.Signalled = false
Task:RemoveCargoMenus( Client )
return -2
end
if not routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then
self:T( "Client is not anymore in the landing zone, go back to stage Route, and remove cargo menus." )
Task.Signalled = false
Task:RemoveCargoMenus( Client )
return -2
end
if not Client:ClientGroup():getUnits()[1]:inAir() then
else
Task.Signalled = false
return -1
end
if Task.IsLandingRequired and Client:GetClientGroupUnit():inAir() then
self:T( "Client went back in the air. Go back to stage Landing." )
Task.Signalled = false
return -1
end
if Task.ExecuteStage == _TransportExecuteStage.EXECUTING then
else
return 0
end
-- Wait until cargo is selected from the menu.
if Task.IsLandingRequired then
if not Task.Cargo then
return 0
end
end
return 1
return 1
end
STAGEUNLOAD = {
@ -324,72 +427,63 @@ STAGEUNLOAD = {
}
function STAGEUNLOAD:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'CLIENT'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGEUNLOAD:Execute( Mission, Client, Task )
trace.f(self.ClassName)
Client:Message( 'The ' .. Task.CargoType.TEXT .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.',
self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Unload" )
Task:RemoveCargoMenus( Client )
self:T()
Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.',
self.MSG.TIME, Mission.Name .. "/StageUnLoad", "Co-Pilot: Unload" )
Task:RemoveCargoMenus( Client )
end
function STAGEUNLOAD:Executing( Mission, Client, Task )
trace.f(self.ClassName)
env.info( 'STAGEUNLOAD:Executing() Task.CargoName = ' .. Task.CargoName )
local Cargo = Client:RemoveCargo( Task.CargoName )
if Cargo then
env.info( 'STAGEUNLOAD:Executing() Cargo.CargoName = ' .. Cargo.CargoName )
env.info( 'STAGEUNLOAD:Executing() Cargo.CargoGroupName = ' .. Cargo.CargoGroupName )
env.info( 'STAGEUNLOAD:Executing() Mission._Cargos[Cargo.CargoName].CargoGroupTemplate = ' .. Mission._Cargos[Cargo.CargoName].CargoGroupTemplate )
if Cargo.CargoType.TRANSPORT == CARGO_TRANSPORT.UNIT then
if Cargo.CargoName then
if Task.TargetZoneName then
SPAWN:New( Mission._Cargos[Cargo.CargoName].CargoGroupTemplate ):FromCarrier ( Client:ClientGroup(),
Task.TargetZoneName,
Mission._Cargos[Cargo.CargoName].CargoGroupName )
else
SPAWN:New( Mission._Cargos[Cargo.CargoName].CargoGroupTemplate ):FromCarrier ( Client:ClientGroup(),
Task.LandingZones[Task.CurrentLandingZoneID],
Mission._Cargos[Cargo.CargoName].CargoGroupName )
end
end
end
self:T()
env.info( 'STAGEUNLOAD:Executing() Task.Cargo.CargoName = ' .. Task.Cargo.CargoName )
local TargetZoneName
if Task.TargetZoneName then
TargetZoneName = Task.TargetZoneName
else
TargetZoneName = Task.CurrentLandingZoneName
end
if Task.Cargo:UnLoad( Client, TargetZoneName ) then
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
Client:ShowCargo()
if Mission.MissionReportFlash then
Client:ShowCargo()
end
end
end
function STAGEUNLOAD:Validate( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
env.info( 'STAGEUNLOAD:Validate()' )
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then
if routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then
else
Task.ExecuteStage = _TransportExecuteStage.FAILED
Task:RemoveCargoMenus( Client )
Client:Message( 'The ' .. Task.CargoType.TEXT .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
Client:Message( 'The ' .. Task.CargoType .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
_TransportStageMsgTime.DONE, Mission.Name .. "/StageFailure", "Co-Pilot: Unload" )
return 1
end
if not Client:ClientGroup():getUnits()[1]:inAir() then
if not Client:GetClientGroupUnit():inAir() then
else
Task.ExecuteStage = _TransportExecuteStage.FAILED
Task:RemoveCargoMenus( Client )
Client:Message( 'The ' .. Task.CargoType.TEXT .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
Client:Message( 'The ' .. Task.CargoType .. " haven't been successfully " .. Task.TEXT[3] .. ' within the landing zone. Task and mission has failed.',
_TransportStageMsgTime.DONE, Mission.Name .. "/StageFailure", "Co-Pilot: Unload" )
return 1
end
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then
Client:Message( 'The ' .. Task.CargoType.TEXT .. ' have been sucessfully ' .. Task.TEXT[3] .. ' within the landing zone.', _TransportStageMsgTime.DONE, Mission.Name .. "/Stage", "Co-Pilot: Unload" )
Mission._Cargos[Task.CargoName].Status = CARGOSTATUS.UNLOADED
Client:Message( 'The ' .. Task.CargoType .. ' have been sucessfully ' .. Task.TEXT[3] .. ' within the landing zone.', _TransportStageMsgTime.DONE, Mission.Name .. "/Stage", "Co-Pilot: Unload" )
Task:RemoveCargoMenus( Client )
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.CargoName, 1 ) -- We set the cargo as one more goal completed in the mission.
return 1
@ -405,173 +499,131 @@ STAGELOAD = {
}
function STAGELOAD:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'CLIENT'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGELOAD:Execute( Mission, Client, Task )
trace.f(self.ClassName)
Client:Message( 'The ' .. Task.CargoType.TEXT .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.',
_TransportStageMsgTime.EXECUTING, Mission.Name .. "/Stage", "Co-Pilot: Load" )
self:T()
if not Task.IsSlingLoad then
Client:Message( 'The ' .. Task.CargoType .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.',
_TransportStageMsgTime.EXECUTING, Mission.Name .. "/STAGELOAD.EXEC." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
-- Route the cargo to the Carrier
if Mission._Cargos[Task.CargoName].CargoType.TRANSPORT == CARGO_TRANSPORT.UNIT then
Task:OnBoardCargo( Client:ClientGroup(), Mission._Cargos )
-- Route the cargo to the Carrier
Task.Cargo:OnBoard( Client, Task.CurrentCargoZone, Task.OnBoardSide )
Task.ExecuteStage = _TransportExecuteStage.EXECUTING
else
-- Add the group to the internal cargo;
Client:AddCargo( Task.CargoName, Mission._Cargos[Task.CargoName].CargoGroupName, Mission._Cargos[Task.CargoName].CargoType, Mission._Cargos[Task.CargoName].CargoWeight, Mission._Cargos[Task.CargoName].CargoGroupTemplate )
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
Task.ExecuteStage = _TransportExecuteStage.EXECUTING
end
end
function STAGELOAD:Executing( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
-- Remove the loaded object from the battle zone.
if routines.IsPartOfGroupInRadius( Group.getByName(Mission._Cargos[Task.CargoName].CargoGroupName), Client:ClientGroup(), 75 ) then
routines.DestroyGroupInRadiusFromGroup( Group.getByName(Mission._Cargos[Task.CargoName].CargoGroupName), Client:ClientGroup(), 75 )
env.info('trying to remove cargo')
-- If the Cargo is ready to be loaded, load it into the Client.
-- Add the group to the internal cargo;
Client:AddCargo( Task.CargoName, Mission._Cargos[Task.CargoName].CargoGroupName, Mission._Cargos[Task.CargoName].CargoType, Mission._Cargos[Task.CargoName].CargoWeight, Mission._Cargos[Task.CargoName].CargoGroupTemplate )
-- Message to the pilot that cargo has been loaded.
Client:Message( "The cargo " .. Task.CargoName .. " has been loaded in our helicopter.", 20, Mission.Name .. "/Stage", "Co-Pilot: Load" )
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
Client:ShowCargo()
end
end
if not Task.IsSlingLoad then
trace.i(self.ClassName, Task.Cargo.CargoName)
if Task.Cargo:OnBoarded( Client, Task.CurrentCargoZone ) then
function STAGELOAD:Validate( Mission, Client, Task )
trace.f(self.ClassName)
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then
-- Load the Cargo onto the Client
Task.Cargo:Load( Client )
-- Message to the pilot that cargo has been loaded.
Client:Message( "The cargo " .. Task.Cargo.CargoName .. " has been loaded in our helicopter.",
20, Mission.Name .. "/STAGELANDING.LOADING1." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
Client:ShowCargo()
end
else
Task:RemoveCargoMenus( Client )
Task.ExecuteStage = _TransportExecuteStage.FAILED
Task.CargoName = nil
Client:Message( "The " .. Task.CargoType.TEXT .. " loading has been aborted. You flew outside the pick-up zone while loading. ",
_TransportStageMsgTime.DONE, Mission.Name .. "/StageSuccess", "Co-Pilot: Load" )
return 1
end
if not Client:ClientGroup():getUnits()[1]:inAir() then
else
-- The carrier is back in the air, undo the loading process.
Task:RemoveCargoMenus( Client )
Task.ExecuteStage = _TransportExecuteStage.NONE
Task.CargoName = nil
Client:Message( "The " .. Task.CargoType.TEXT .. " loading has been aborted. Land the helicopter and load the cargo. Don't fly outside the pick-up zone. ",
_TransportStageMsgTime.DONE, Mission.Name .. "/StageSuccess", "Co-Pilot: Load" )
return -1
end
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then
Mission._Cargos[Task.CargoName].Status = CARGOSTATUS.LOADED
Task:RemoveCargoMenus( Client )
Client:Message( 'Co-Pilot: The ' .. Task.CargoType.TEXT .. ' have been sucessfully ' .. Task.TEXT[3] .. ' within the landing zone.',
_TransportStageMsgTime.DONE, Mission.Name .. "/Stage", "Co-Pilot: Load" )
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.CargoName, 1 )
return 1
end
return 0
end
STAGE_SLINGLOAD_HOOK = {
ClassName = "STAGE_SLINGLOAD_HOOK",
MSG = { ID = "SlingLoadHook", TIME = 10 },
Name = "SlingLoadHook"
}
function STAGE_SLINGLOAD_HOOK:New()
trace.f(self.ClassName)
-- Arrange meta tables
local self = BASE:Inherit( self, STAGE:New() )
self.StageType = 'CLIENT'
return self
end
function STAGE_SLINGLOAD_HOOK:Execute( Mission, Client, Task )
trace.f(self.ClassName)
Client:Message( 'Hook the Cargo onto the helicopter, and fly out the pick-up zone. Due to a bug in DCS world it cannot be chacked (for the moment) ' ..
'if the cargo is in our out of the zone and attached to your helicopter...', self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Hook" )
end
function STAGE_SLINGLOAD_HOOK:Validate( Mission, Client, Task )
trace.f(self.ClassName)
for CargoID, CargoName in pairs( Task.CargoPrefixes ) do
env.info( CargoName )
if StaticObject.getByName( CargoName ):inAir() then
Task.CargoName = CargoName
Task.CargoID = CargoID
Client:Message( 'Co-Pilot: The Cargo has been successfully hooked onto the helicopter within the landing zone.', self.MSG.TIME, Mission.Name .. "/StageSuccess" )
break
end
end
if Task.CargoName then
if routines.IsStaticInZones( StaticObject.getByName( Task.CargoName ), Task.LandingZones[Task.CurrentLandingZoneID] ) then
else
Mission._Cargos[Task.CargoName].Status = CARGOSTATUS.LOADED
return 1
end
end
return 1
end
STAGE_SLINGLOAD_UNHOOK = {
ClassName = "STAGE_SLINGLOAD_UNHOOK",
MSG = { ID = "SlingLoadUnHook", TIME = 10 },
Name = "SlingLoadUnHook"
}
function STAGE_SLINGLOAD_UNHOOK:New()
trace.f(self.ClassName)
-- Arrange meta tables
local self = BASE:Inherit( self, STAGE:New() )
self.StageType = 'CLIENT'
return self
end
function STAGE_SLINGLOAD_UNHOOK:Execute( Mission, Client, Task )
trace.f(self.ClassName)
Client:Message( 'Deploy the Cargo in the Landing Zone and unhook the cargo, and fly out of the drop zone.', self.MSG.TIME, Mission.Name .. "/StageUnhook", "Co-Pilot: Unhook" )
end
function STAGE_SLINGLOAD_UNHOOK:Validate( Mission, Client, Task )
trace.f(self.ClassName)
for CargoID, CargoName in pairs( Task.CargoPrefixes ) do
if StaticObject.getByName( CargoName ):inAir() then
Task.CargoName = CargoName
Task.CargoID = CargoID
Client:Message( 'Co-Pilot: Drop the cargo within the landing zone and unhook.', self.MSG.TIME, Mission.Name .. "/Stage" )
break
end
end
if Task.CargoName then
if not StaticObject.getByName( Task.CargoName ):inAir() then
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then
else
Client:Message( 'Co-Pilot: The Cargo is Dropped in the Landing Zone, and You have flown outside of the landing zone.', self.MSG.TIME, Mission.Name .. "/Stage" )
return 1
Client:Message( "Hook the " .. Task.CargoNames .. " onto the helicopter " .. Task.TEXT[3] .. " within the landing zone.",
_TransportStageMsgTime.EXECUTING, Mission.Name .. "/STAGELOAD.LOADING.1." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":", 10 )
for CargoID, Cargo in pairs( CARGOS ) do
self:T( "Cargo.CargoName = " .. Cargo.CargoName )
if Cargo:IsSlingLoad() then
local CargoStatic = StaticObject.getByName( Cargo.CargoStaticName )
if CargoStatic then
trace.i(self.ClassName, "Cargo is found in the DCS simulator.")
local CargoStaticPosition = CargoStatic:getPosition().p
trace.i(self.ClassName, "Cargo Position x = " .. CargoStaticPosition.x .. ", y = " .. CargoStaticPosition.y .. ", z = " .. CargoStaticPosition.z )
local CargoStaticHeight = routines.GetUnitHeight( CargoStatic )
if CargoStaticHeight > 5 then
trace.i(self.ClassName, "Cargo is airborne.")
Cargo:StatusLoaded()
Task.Cargo = Cargo
Client:Message( 'The Cargo has been successfully hooked onto the helicopter and is now being sling loaded. Fly outside the landing zone.',
self.MSG.TIME, Mission.Name .. "/STAGELANDING.LOADING.2." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
break
end
else
self:T( "Cargo not found in the DCS simulator." )
end
end
end
end
return 1
end
function STAGELOAD:Validate( Mission, Client, Task )
self:T()
self:T( "Task.CurrentLandingZoneName = " .. Task.CurrentLandingZoneName )
if not Task.IsSlingLoad then
if not routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then
Task:RemoveCargoMenus( Client )
Task.ExecuteStage = _TransportExecuteStage.FAILED
Task.CargoName = nil
Client:Message( "The " .. Task.CargoType .. " loading has been aborted. You flew outside the pick-up zone while loading. ",
self.MSG.TIME, Mission.Name .. "/STAGELANDING.VALIDATE.1." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
return -1
end
if not Client:GetClientGroupUnit():inAir() then
else
-- The carrier is back in the air, undo the loading process.
Task:RemoveCargoMenus( Client )
Task.ExecuteStage = _TransportExecuteStage.NONE
Task.CargoName = nil
Client:Message( "The " .. Task.CargoType .. " loading has been aborted. Re-start the " .. Task.TEXT[3] .. " process. Don't fly outside the pick-up zone.",
self.MSG.TIME, Mission.Name .. "/STAGELANDING.VALIDATE.2." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
return -1
end
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then
Task:RemoveCargoMenus( Client )
Client:Message( "Good Job. The " .. Task.CargoType .. " has been sucessfully " .. Task.TEXT[3] .. " within the landing zone.",
self.MSG.TIME, Mission.Name .. "/STAGELANDING.VALIDATE.3." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.CargoName, 1 )
return 1
end
else
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then
CargoStatic = StaticObject.getByName( Task.Cargo.CargoStaticName )
if CargoStatic and not routines.IsStaticInZones( CargoStatic, Task.CurrentLandingZoneName ) then
Client:Message( "Good Job. The " .. Task.CargoType .. " has been sucessfully " .. Task.TEXT[3] .. " and flown outside of the landing zone.",
self.MSG.TIME, Mission.Name .. "/STAGELANDING.VALIDATE.4." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.Cargo.CargoName, 1 )
return 1
end
end
end
return 0
end
STAGEDONE = {
ClassName = "STAGEDONE",
MSG = { ID = "Done", TIME = 10 },
@ -579,20 +631,19 @@ STAGEDONE = {
}
function STAGEDONE:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'AI'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'AI'
return self
end
function STAGEDONE:Execute( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
end
function STAGEDONE:Validate( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
Task:Done()
@ -606,24 +657,23 @@ STAGEARRIVE = {
}
function STAGEARRIVE:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'CLIENT'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT'
return self
end
function STAGEARRIVE:Execute( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
Client:Message( 'We have arrived at ' .. Task.LandingZones[Task.CurrentLandingZoneID] .. ".", self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Arrived" )
Client:Message( 'We have arrived at ' .. Task.CurrentLandingZoneName .. ".", self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Arrived" )
end
function STAGEARRIVE:Validate( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones )
Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.LandingZones )
if ( Task.CurrentLandingZoneID ) then
else
return -1
@ -641,11 +691,10 @@ STAGEGROUPSDESTROYED = {
}
function STAGEGROUPSDESTROYED:New()
trace.f(self.ClassName)
-- Arrange meta tables
local Child = BASE:Inherit( self, STAGE:New() )
Child.StageType = 'AI'
return Child
local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'AI'
return self
end
--function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task )
@ -655,7 +704,7 @@ end
--end
function STAGEGROUPSDESTROYED:Validate( Mission, Client, Task )
trace.f(self.ClassName)
self:T()
if Task.MissionTask:IsGoalReached() then
return 1
@ -665,8 +714,8 @@ trace.f(self.ClassName)
end
function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task )
trace.f(self.ClassName)
trace.i( self.ClassName, { Task.ClassName, Task.Destroyed } )
self:T()
self:T( { Task.ClassName, Task.Destroyed } )
--env.info( 'Event Table Task = ' .. tostring(Task) )
end

View File

@ -9,29 +9,37 @@ Include.File( "Stage" )
TASK = {
-- Defines the different signal types with a Task.
SIGNAL = {
COLOR = {
RED = { ID = 1, COLOR = trigger.smokeColor.Red, TEXT = "A red" },
GREEN = { ID = 2, COLOR = trigger.smokeColor.Green, TEXT = "A green" },
BLUE = { ID = 3, COLOR = trigger.smokeColor.Blue, TEXT = "A blue" },
WHITE = { ID = 4, COLOR = trigger.smokeColor.White, TEXT = "A white" },
ORANGE = { ID = 5, COLOR = trigger.smokeColor.Orange, TEXT = "An orange" }
},
TYPE = {
SMOKE = { ID = 1, TEXT = "smoke" },
FLARE = { ID = 2, TEXT = "flare" }
}
},
ClassName = "TASK",
Mission = {}, -- Owning mission of the Task
Name = '',
Stages = {},
Stage = {},
ActiveStage = 0,
TaskDone = false,
TaskFailed = false,
GoalTasks = {}
-- Defines the different signal types with a Task.
SIGNAL = {
COLOR = {
RED = { ID = 1, COLOR = trigger.smokeColor.Red, TEXT = "A red" },
GREEN = { ID = 2, COLOR = trigger.smokeColor.Green, TEXT = "A green" },
BLUE = { ID = 3, COLOR = trigger.smokeColor.Blue, TEXT = "A blue" },
WHITE = { ID = 4, COLOR = trigger.smokeColor.White, TEXT = "A white" },
ORANGE = { ID = 5, COLOR = trigger.smokeColor.Orange, TEXT = "An orange" }
},
TYPE = {
SMOKE = { ID = 1, TEXT = "smoke" },
FLARE = { ID = 2, TEXT = "flare" }
}
},
ClassName = "TASK",
Mission = {}, -- Owning mission of the Task
Name = '',
Stages = {},
Stage = {},
Cargos = {
InitCargos = {},
LoadCargos = {}
},
LandingZones = {
LandingZoneNames = {},
LandingZones = {}
},
ActiveStage = 0,
TaskDone = false,
TaskFailed = false,
GoalTasks = {}
}
--- Instantiates a new TASK Base. Should never be used. Interface Class.
@ -120,7 +128,9 @@ trace.f(self.ClassName)
end
end
Client:Message( GoalsText, 10, "/TASKPROGRESS" .. self.ClassName, "Mission Command: Task Status", 30 )
if Mission.MissionReportFlash or Mission.MissionReportShow then
Client:Message( GoalsText, 10, "/TASKPROGRESS" .. self.ClassName, "Mission Command: Task Status", 30 )
end
end
--- Sets a TASK to status Done.
@ -132,7 +142,7 @@ end
--- Returns if a TASK is done.
-- @treturn bool
function TASK:IsDone()
trace.f(self.ClassName)
trace.i( self.ClassName, self.TaskDone )
return self.TaskDone
end
@ -145,7 +155,7 @@ end
--- Returns if a TASk has failed.
-- @return bool
function TASK:IsFailed()
trace.f(self.ClassName)
trace.i( self.ClassName, self.TaskFailed )
return self.TaskFailed
end
@ -268,7 +278,6 @@ end
--- Returns if all the Goals of the TASK were achieved.
-- @treturn bool
function TASK:IsGoalReached( )
trace.f(self.ClassName)
local GoalReached = true
@ -287,6 +296,7 @@ trace.f(self.ClassName)
end
end
trace.i( self.ClassName, GoalReached )
return GoalReached
end
@ -319,10 +329,9 @@ end
function TASK.MenuAction( Parameter )
trace.menu("TASK","MenuAction")
trace.l( "TASK", "MenuAction", { Parameter } )
trace.l( "TASK", "MenuAction" )
Parameter.ReferenceTask.ExecuteStage = _TransportExecuteStage.EXECUTING
Parameter.ReferenceTask.CargoName = Parameter.CargoName
Parameter.ReferenceTask.Cargo = Parameter.CargoTask
end
function TASK:StageExecute()

View File

@ -62,6 +62,7 @@ trace.names.FollowPlayers = false
trace.names.AddPlayerFromUnit = false
trace.names.FromCarrier = false
trace.names.OnDeadOrCrash = false
trace.classes.CLEANUP = false
trace.cache = {}
@ -249,8 +250,9 @@ end
trace.i = function(object, variable)
local info = debug.getinfo( 2, "nl" )
if info.name ~= trace.nametrace then
trace.nametrace = info.name
trace.nametrace = info.name
if trace.nametrace == nil then
trace.nametrace = "function"
end
if trace.names.all or trace.tracefunction( trace.nametrace ) or trace.classes[ object ] then
local objecttrace = ""

58
Moose/Unit.lua Normal file
View File

@ -0,0 +1,58 @@
--- UNIT Classes
-- @classmod UNIT
Include.File( "Routines" )
Include.File( "Base" )
Include.File( "Message" )
UNITS = {}
UNIT = {
ClassName="UNIT",
}
function UNIT:New( _Unit )
local self = BASE:Inherit( self, BASE:New() )
self:T( _Unit:getName() )
self._Unit = _Unit
self.UnitName = _Unit:getName()
self.UnitID = _Unit:getID()
return self
end
function UNIT:GetCallSign()
self:T( self.UnitName )
return self._Unit:getCallsign()
end
function UNIT:GetPositionVec3()
self:T( self.UnitName )
local UnitPos = self._Unit:getPosition().p
self:T( UnitPos )
return UnitPos
end
function UNIT:OtherUnitInRadius( AwaitUnit, Radius )
self:T( { self.UnitName, AwaitUnit.UnitName, Radius } )
local UnitPos = self:GetPositionVec3()
local AwaitUnitPos = AwaitUnit:GetPositionVec3()
if (((UnitPos.x - AwaitUnitPos.x)^2 + (UnitPos.z - AwaitUnitPos.z)^2)^0.5 <= Radius) then
self:T( "true" )
return true
else
self:T( "false" )
return false
end
self:T( "false" )
return false
end

57
Moose/Zone.lua Normal file
View File

@ -0,0 +1,57 @@
--- ZONE Classes
-- @classmod ZONE
Include.File( "Routines" )
Include.File( "Base" )
Include.File( "Message" )
ZONES = {}
ZONE = {
ClassName="ZONE",
}
function ZONE:New( ZoneName )
trace.f( self.ClassName, ZoneName )
local self = BASE:Inherit( self, BASE:New() )
local Zone = trigger.misc.getZone( ZoneName )
if not Zone then
error( "Zone " .. ZoneName .. " does not exist." )
return nil
end
self.Zone = Zone
self.ZoneName = ZoneName
return self
end
function ZONE:GetRandomPoint()
trace.f( self.ClassName, self.ZoneName )
local Point = {}
local Zone = trigger.misc.getZone( self.ZoneName )
Point.x = Zone.point.x + math.random( Zone.radius * -1, Zone.radius )
Point.y = Zone.point.z + math.random( Zone.radius * -1, Zone.radius )
trace.i( self.ClassName, { Zone } )
trace.i( self.ClassName, { Point } )
return Point
end
function ZONE:GetRadius()
trace.f( self.ClassName, self.ZoneName )
local Zone = trigger.misc.getZone( self.ZoneName )
trace.i( self.ClassName, { Zone } )
return Zone.radius
end

View File

@ -0,0 +1,126 @@
Include.File( "Mission" )
Include.File( "Client" )
Include.File( "DeployTask" )
Include.File( "PickupTask" )
Include.File( "DestroyGroupsTask" )
Include.File( "DestroyRadarsTask" )
Include.File( "DestroyUnitTypesTask" )
Include.File( "GoHomeTask" )
Include.File( "Spawn" )
Include.File( "Movement" )
Include.File( "Sead" )
Include.File( "CleanUp" )
do
local Mission = MISSION:New( 'Pickup', 'Operational', 'Pickup Troops', 'NATO' )
Mission:AddClient( CLIENT:New( 'DE Pickup Test 1' ):Transport() )
Mission:AddClient( CLIENT:New( 'DE Pickup Test 2' ):Transport() )
local CargoTable = {}
local EngineerNames = { "Alpha", "Beta", "Gamma", "Delta", "Theta" }
Cargo_Pickup_Zone_1 = CARGO_ZONE:New( 'Pickup Zone 1', 'DE Communication Center 1' ):BlueSmoke()
Cargo_Pickup_Zone_2 = CARGO_ZONE:New( 'Pickup Zone 2', 'DE Communication Center 2' ):RedSmoke()
for CargoItem = 1, 2 do
CargoTable[CargoItem] = CARGO_GROUP:New( 'Engineers', 'Team ' .. EngineerNames[CargoItem], math.random( 70, 100 ) * 3, 'DE Infantry', Cargo_Pickup_Zone_1 )
end
for CargoItem = 3, 5 do
CargoTable[CargoItem] = CARGO_GROUP:New( 'Engineers', 'Team ' .. EngineerNames[CargoItem], math.random( 70, 100 ) * 3, 'DE Infantry', Cargo_Pickup_Zone_2 )
end
--Cargo_Package = CARGO_INVISIBLE:New( 'Letter', 0.1, 'DE Secret Agent', 'Pickup Zone Package' )
--Cargo_Goods = CARGO_STATIC:New( 'Goods', 20, 'Goods', 'Pickup Zone Goods', 'DE Collection Point' )
--Cargo_SlingLoad = CARGO_SLING:New( 'Basket', 40, 'Basket', 'Pickup Zone Sling Load', 'DE Cargo Guard' )
-- Assign the Pickup Task
local PickupTask = PICKUPTASK:New( 'Engineers', CLIENT.ONBOARDSIDE.LEFT )
PickupTask:FromZone( Cargo_Pickup_Zone_1 )
PickupTask:FromZone( Cargo_Pickup_Zone_2 )
PickupTask:InitCargo( CargoTable )
PickupTask:SetGoalTotal( 3 )
Mission:AddTask( PickupTask, 1 )
Cargo_Deploy_Zone_1 = CARGO_ZONE:New( 'Deploy Zone 1', 'DE Communication Center 3' ):RedFlare()
Cargo_Deploy_Zone_2 = CARGO_ZONE:New( 'Deploy Zone 2', 'DE Communication Center 4' ):WhiteFlare()
-- Assign the Pickup Task
local DeployTask = DEPLOYTASK:New( 'Engineers' )
DeployTask:ToZone( Cargo_Deploy_Zone_1 )
DeployTask:ToZone( Cargo_Deploy_Zone_2 )
DeployTask:SetGoalTotal( 3 )
Mission:AddTask( DeployTask, 2 )
MISSIONSCHEDULER.AddMission( Mission )
end
do
local Mission = MISSION:New( 'Deliver secret letter', 'Operational', 'Pickup letter to the commander.', 'NATO' )
Mission:AddClient( CLIENT:New( 'BE Package Test 1' ):Transport() )
Mission:AddClient( CLIENT:New( 'BE Package Test 2' ):Transport() )
Mission:AddClient( CLIENT:New( 'DE Pickup Test 1' ):Transport() )
Mission:AddClient( CLIENT:New( 'DE Pickup Test 2' ):Transport() )
Package_Pickup_Zone = CARGO_ZONE:New( 'Package Pickup Zone', 'DE Guard' ):GreenSmoke()
Cargo_Package = CARGO_PACKAGE:New( 'Letter', 'Letter to Command', 0.1, 'DE Guard' )
--Cargo_Goods = CARGO_STATIC:New( 'Goods', 20, 'Goods', 'Pickup Zone Goods', 'DE Collection Point' )
--Cargo_SlingLoad = CARGO_SLING:New( 'Basket', 40, 'Basket', 'Pickup Zone Sling Load', 'DE Cargo Guard' )
-- Assign the Pickup Task
local PickupTask = PICKUPTASK:New( 'Letter', CLIENT.ONBOARDSIDE.FRONT )
PickupTask:FromZone( Package_Pickup_Zone )
PickupTask:InitCargo( { Cargo_Package } )
PickupTask:SetGoalTotal( 1 )
Mission:AddTask( PickupTask, 1 )
Package_Deploy_Zone = CARGO_ZONE:New( 'Package Deploy Zone', 'DE Secret Car' ):GreenFlare()
-- Assign the Pickup Task
local DeployTask = DEPLOYTASK:New( 'Letter' )
DeployTask:ToZone( Package_Deploy_Zone )
DeployTask:SetGoalTotal( 1 )
Mission:AddTask( DeployTask, 2 )
MISSIONSCHEDULER.AddMission( Mission )
end
do
local Mission = MISSION:New( 'Sling load Cargo', 'Operational', 'Sling Load Cargo to Deploy Zone.', 'NATO' )
Mission:AddClient( CLIENT:New( 'Sling Load Test Client 1' ):Transport() )
Mission:AddClient( CLIENT:New( 'Sling Load Test Client 2' ):Transport() )
Sling_Load_Pickup_Zone = CARGO_ZONE:New( 'Sling Load Pickup Zone', 'Sling Load Guard' ):RedSmoke()
Cargo_Sling_Load = CARGO_SLINGLOAD:New( 'Sling', 'Food Boxes', 200, 'Sling Load Pickup Zone', 'Sling Load Guard', country.id.USA )
--Cargo_Goods = CARGO_STATIC:New( 'Goods', 20, 'Goods', 'Pickup Zone Goods', 'DE Collection Point' )
--Cargo_SlingLoad = CARGO_SLING:New( 'Basket', 40, 'Basket', 'Pickup Zone Sling Load', 'DE Cargo Guard' )
-- Assign the Pickup Task
local PickupTask = PICKUPTASK:New( 'Sling', CLIENT.ONBOARDSIDE.FRONT )
PickupTask:FromZone( Sling_Load_Pickup_Zone )
PickupTask:InitCargo( { Cargo_Sling_Load } )
PickupTask:SetGoalTotal( 1 )
Mission:AddTask( PickupTask, 1 )
MISSIONSCHEDULER.AddMission( Mission )
end
-- MISSION SCHEDULER STARTUP
MISSIONSCHEDULER.Start()
MISSIONSCHEDULER.ReportMenu()
MISSIONSCHEDULER.ReportMissionsHide()
env.info( "Test Mission loaded" )

Binary file not shown.

View File

@ -0,0 +1,15 @@
Include.File( "Spawn" )
SpawnTest = SPAWN:New( 'TEST' ):Schedule( 1, 1, 15, 0.4 ):Repeat()
SpawnTestPlane = SPAWN:New( 'TESTPLANE' ):Schedule( 1, 1, 15, 0.4 ):RepeatOnLanding()
SpawnTestShipPlane = SPAWN:New( 'SHIPPLANE' ):Schedule( 1, 1, 15, 0.4 ):RepeatOnLanding()
SpawnTestShipHeli = SPAWN:New( 'SHIPHELI' ):Schedule( 1, 1, 15, 0.4 ):RepeatOnLanding()
SpawnCH53E = SPAWN:New( 'VEHICLE' )
SpawnTestHelicopterCleanUp = SPAWN:New( "TEST_HELI_CLEANUP" ):Limit( 3, 100 ):Schedule( 10, 0 ):RandomizeRoute( 1, 1, 1000 ):CleanUp( 180 )
SpawnTestVehiclesCleanUp = SPAWN:New( "TEST_AAA_CLEANUP" ):Limit( 3, 100 ):Schedule( 10, 0 ):RandomizeRoute( 1, 1, 1000 )

Binary file not shown.